feat(osint): add contextual tools menu
This commit is contained in:
parent
be138946be
commit
1fb3c71c3f
5 changed files with 307 additions and 12 deletions
|
|
@ -138,7 +138,8 @@ Le socle actuel comprend notamment :
|
||||||
- exécution sécurisée par `GSubprocess` ;
|
- exécution sécurisée par `GSubprocess` ;
|
||||||
- exécution d’outils en tâche de fond ;
|
- exécution d’outils en tâche de fond ;
|
||||||
- catalogue initial d’outils ;
|
- catalogue initial d’outils ;
|
||||||
- détection de présence et de version.
|
- détection de présence et de version ;
|
||||||
|
- menu OSINT contextuel préparé pour les entités et relations du graphe.
|
||||||
|
|
||||||
Les outils actuellement présents dans le catalogue initial sont :
|
Les outils actuellement présents dans le catalogue initial sont :
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,11 @@ G_BEGIN_DECLS
|
||||||
*/
|
*/
|
||||||
typedef struct EntityRecord EntityRecord;
|
typedef struct EntityRecord EntityRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Représentation opaque d'une relation métier.
|
||||||
|
*/
|
||||||
|
typedef struct RelationRecord RelationRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Représentation opaque du graphe métier d'une enquête.
|
* @brief Représentation opaque du graphe métier d'une enquête.
|
||||||
*/
|
*/
|
||||||
|
|
@ -33,13 +38,17 @@ typedef struct InvestigationGraphView InvestigationGraphView;
|
||||||
/**
|
/**
|
||||||
* @brief Callback appelé lors d'un changement de sélection.
|
* @brief Callback appelé lors d'un changement de sélection.
|
||||||
*
|
*
|
||||||
* entity_record est emprunté au graphe. NULL représente une désélection.
|
* Les enregistrements sont empruntés au graphe et restent valides uniquement
|
||||||
|
* pendant l'appel. Un seul des deux pointeurs est non NULL. Deux pointeurs
|
||||||
|
* NULL représentent une désélection.
|
||||||
*
|
*
|
||||||
* @param entity_record Entité sélectionnée empruntée, ou NULL.
|
* @param entity_record Entité sélectionnée empruntée, ou NULL.
|
||||||
|
* @param relation_record Relation sélectionnée empruntée, ou NULL.
|
||||||
* @param user_data Données empruntées fournies par l'appelant.
|
* @param user_data Données empruntées fournies par l'appelant.
|
||||||
*/
|
*/
|
||||||
typedef void (*InvestigationGraphViewSelectionCallback)(
|
typedef void (*InvestigationGraphViewSelectionCallback)(
|
||||||
const EntityRecord *entity_record,
|
const EntityRecord *entity_record,
|
||||||
|
const RelationRecord *relation_record,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,13 +42,13 @@ typedef void (*WorkspaceVerifyEvidenceCallback)(
|
||||||
*
|
*
|
||||||
* Les coordonnées sont exprimées dans l'espace logique du graphe.
|
* Les coordonnées sont exprimées dans l'espace logique du graphe.
|
||||||
*
|
*
|
||||||
* @param entity_identifier UUID de l'entité déplacée.
|
* @param node_identifier UUID du nœud déplacé.
|
||||||
* @param x Coordonnée horizontale logique.
|
* @param x Coordonnée horizontale logique.
|
||||||
* @param y Coordonnée verticale logique.
|
* @param y Coordonnée verticale logique.
|
||||||
* @param user_data Données empruntées fournies par l'appelant.
|
* @param user_data Données empruntées fournies par l'appelant.
|
||||||
*/
|
*/
|
||||||
typedef void (*WorkspaceGraphNodeMovedCallback)(
|
typedef void (*WorkspaceGraphNodeMovedCallback)(
|
||||||
const char *entity_identifier,
|
const char *node_identifier,
|
||||||
double x,
|
double x,
|
||||||
double y,
|
double y,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
|
|
|
||||||
|
|
@ -623,6 +623,9 @@ static void investigation_graph_view_set_selected_node(
|
||||||
const EntityRecord *entity_record =
|
const EntityRecord *entity_record =
|
||||||
NULL;
|
NULL;
|
||||||
|
|
||||||
|
const RelationRecord *relation_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
if (graph_view == NULL ||
|
if (graph_view == NULL ||
|
||||||
graph_view->selected_node == node_layout)
|
graph_view->selected_node == node_layout)
|
||||||
{
|
{
|
||||||
|
|
@ -639,6 +642,13 @@ static void investigation_graph_view_set_selected_node(
|
||||||
entity_record =
|
entity_record =
|
||||||
node_layout->entity_record;
|
node_layout->entity_record;
|
||||||
}
|
}
|
||||||
|
else if (node_layout != NULL &&
|
||||||
|
node_layout->kind ==
|
||||||
|
INVESTIGATION_GRAPH_NODE_KIND_RELATION)
|
||||||
|
{
|
||||||
|
relation_record =
|
||||||
|
node_layout->relation_record;
|
||||||
|
}
|
||||||
|
|
||||||
if (graph_view->drawing_area != NULL)
|
if (graph_view->drawing_area != NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -651,6 +661,7 @@ static void investigation_graph_view_set_selected_node(
|
||||||
{
|
{
|
||||||
graph_view->selection_callback(
|
graph_view->selection_callback(
|
||||||
entity_record,
|
entity_record,
|
||||||
|
relation_record,
|
||||||
graph_view->selection_user_data
|
graph_view->selection_user_data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
#include "widgets/workspace.h"
|
#include "widgets/workspace.h"
|
||||||
|
|
||||||
|
#include "models/entity_record.h"
|
||||||
|
#include "models/relation_record.h"
|
||||||
#include "widgets/entity_details_panel.h"
|
#include "widgets/entity_details_panel.h"
|
||||||
#include "widgets/investigation_graph_view.h"
|
#include "widgets/investigation_graph_view.h"
|
||||||
|
|
||||||
|
|
@ -49,6 +51,10 @@ struct Workspace
|
||||||
GtkWidget *graph_view_page;
|
GtkWidget *graph_view_page;
|
||||||
GtkWidget *graph_toolbar;
|
GtkWidget *graph_toolbar;
|
||||||
GtkWidget *reset_graph_layout_button;
|
GtkWidget *reset_graph_layout_button;
|
||||||
|
GtkWidget *osint_tools_button;
|
||||||
|
GtkWidget *osint_tools_popover;
|
||||||
|
GtkWidget *osint_tools_context_label;
|
||||||
|
GtkWidget *osint_tools_status_label;
|
||||||
GtkWidget *graph_help_button;
|
GtkWidget *graph_help_button;
|
||||||
GtkWidget *graph_help_popover;
|
GtkWidget *graph_help_popover;
|
||||||
|
|
||||||
|
|
@ -111,6 +117,110 @@ struct Workspace
|
||||||
WorkspaceGraphState graph_state;
|
WorkspaceGraphState graph_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Actualise le menu OSINT selon la sélection du graphe.
|
||||||
|
*
|
||||||
|
* Aucun outil n'est encore exposé par ce ticket. Le menu prépare le point
|
||||||
|
* d'entrée contextuel et explique explicitement cet état à l'utilisateur.
|
||||||
|
*/
|
||||||
|
static void workspace_update_osint_tools_menu(
|
||||||
|
Workspace *workspace,
|
||||||
|
const EntityRecord *entity_record,
|
||||||
|
const RelationRecord *relation_record
|
||||||
|
)
|
||||||
|
{
|
||||||
|
const char *selection_kind =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
const char *selection_identifier =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *context_text =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (workspace == NULL ||
|
||||||
|
workspace->osint_tools_button == NULL ||
|
||||||
|
workspace->osint_tools_context_label == NULL ||
|
||||||
|
workspace->osint_tools_status_label == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entity_record != NULL)
|
||||||
|
{
|
||||||
|
selection_kind =
|
||||||
|
"Entité";
|
||||||
|
|
||||||
|
selection_identifier =
|
||||||
|
entity_record_get_identifier(
|
||||||
|
entity_record
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (relation_record != NULL)
|
||||||
|
{
|
||||||
|
selection_kind =
|
||||||
|
"Relation";
|
||||||
|
|
||||||
|
selection_identifier =
|
||||||
|
relation_record_get_identifier(
|
||||||
|
relation_record
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
gtk_widget_set_sensitive(
|
||||||
|
workspace->osint_tools_button,
|
||||||
|
selection_identifier != NULL &&
|
||||||
|
selection_identifier[0] != '\0'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selection_identifier == NULL ||
|
||||||
|
selection_identifier[0] == '\0')
|
||||||
|
{
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_context_label
|
||||||
|
),
|
||||||
|
"Sélectionnez un nœud du graphe."
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_status_label
|
||||||
|
),
|
||||||
|
"Les outils compatibles apparaîtront ici."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
context_text =
|
||||||
|
g_strdup_printf(
|
||||||
|
"%s sélectionnée\n%s",
|
||||||
|
selection_kind,
|
||||||
|
selection_identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_context_label
|
||||||
|
),
|
||||||
|
context_text != NULL
|
||||||
|
? context_text
|
||||||
|
: selection_kind
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_text(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_status_label
|
||||||
|
),
|
||||||
|
"Aucun outil OSINT intégré pour le moment."
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
context_text
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Ajoute une ligne de métadonnée dans la grille.
|
* @brief Ajoute une ligne de métadonnée dans la grille.
|
||||||
*
|
*
|
||||||
|
|
@ -310,23 +420,32 @@ static void workspace_on_graph_node_moved(
|
||||||
/**
|
/**
|
||||||
* @brief Transmet la sélection du graphe au volet de détails.
|
* @brief Transmet la sélection du graphe au volet de détails.
|
||||||
*/
|
*/
|
||||||
static void workspace_on_graph_entity_selected(
|
static void workspace_on_graph_node_selected(
|
||||||
const EntityRecord *entity_record,
|
const EntityRecord *entity_record,
|
||||||
|
const RelationRecord *relation_record,
|
||||||
gpointer user_data
|
gpointer user_data
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Workspace *workspace =
|
Workspace *workspace =
|
||||||
user_data;
|
user_data;
|
||||||
|
|
||||||
if (workspace == NULL ||
|
if (workspace == NULL)
|
||||||
workspace->entity_details_panel == NULL)
|
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
entity_details_panel_set_entity(
|
if (workspace->entity_details_panel != NULL)
|
||||||
workspace->entity_details_panel,
|
{
|
||||||
entity_record
|
entity_details_panel_set_entity(
|
||||||
|
workspace->entity_details_panel,
|
||||||
|
entity_record
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace_update_osint_tools_menu(
|
||||||
|
workspace,
|
||||||
|
entity_record,
|
||||||
|
relation_record
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1092,7 +1211,7 @@ Workspace *workspace_new(void)
|
||||||
|
|
||||||
investigation_graph_view_set_selection_callback(
|
investigation_graph_view_set_selection_callback(
|
||||||
workspace->graph_view,
|
workspace->graph_view,
|
||||||
workspace_on_graph_entity_selected,
|
workspace_on_graph_node_selected,
|
||||||
workspace
|
workspace
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -1134,8 +1253,41 @@ Workspace *workspace_new(void)
|
||||||
"view-refresh-symbolic"
|
"view-refresh-symbolic"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
workspace->osint_tools_button =
|
||||||
|
gtk_menu_button_new();
|
||||||
|
|
||||||
|
workspace->osint_tools_popover =
|
||||||
|
gtk_popover_new();
|
||||||
|
|
||||||
|
GtkWidget *osint_tools_content =
|
||||||
|
gtk_box_new(
|
||||||
|
GTK_ORIENTATION_VERTICAL,
|
||||||
|
8
|
||||||
|
);
|
||||||
|
|
||||||
|
GtkWidget *osint_tools_title =
|
||||||
|
gtk_label_new(
|
||||||
|
"Outils OSINT"
|
||||||
|
);
|
||||||
|
|
||||||
|
workspace->osint_tools_context_label =
|
||||||
|
gtk_label_new(
|
||||||
|
"Sélectionnez un nœud du graphe."
|
||||||
|
);
|
||||||
|
|
||||||
|
workspace->osint_tools_status_label =
|
||||||
|
gtk_label_new(
|
||||||
|
"Les outils compatibles apparaîtront ici."
|
||||||
|
);
|
||||||
|
|
||||||
if (workspace->graph_toolbar == NULL ||
|
if (workspace->graph_toolbar == NULL ||
|
||||||
workspace->reset_graph_layout_button == NULL)
|
workspace->reset_graph_layout_button == NULL ||
|
||||||
|
workspace->osint_tools_button == NULL ||
|
||||||
|
workspace->osint_tools_popover == NULL ||
|
||||||
|
osint_tools_content == NULL ||
|
||||||
|
osint_tools_title == NULL ||
|
||||||
|
workspace->osint_tools_context_label == NULL ||
|
||||||
|
workspace->osint_tools_status_label == NULL)
|
||||||
{
|
{
|
||||||
workspace_free(
|
workspace_free(
|
||||||
workspace
|
workspace
|
||||||
|
|
@ -1184,6 +1336,121 @@ Workspace *workspace_new(void)
|
||||||
FALSE
|
FALSE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gtk_menu_button_set_label(
|
||||||
|
GTK_MENU_BUTTON(
|
||||||
|
workspace->osint_tools_button
|
||||||
|
),
|
||||||
|
"Outils OSINT"
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_add_css_class(
|
||||||
|
workspace->osint_tools_button,
|
||||||
|
"flat"
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_tooltip_text(
|
||||||
|
workspace->osint_tools_button,
|
||||||
|
"Afficher les outils compatibles avec la sélection"
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_sensitive(
|
||||||
|
workspace->osint_tools_button,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_margin_start(
|
||||||
|
osint_tools_content,
|
||||||
|
16
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_margin_end(
|
||||||
|
osint_tools_content,
|
||||||
|
16
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_margin_top(
|
||||||
|
osint_tools_content,
|
||||||
|
14
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_set_margin_bottom(
|
||||||
|
osint_tools_content,
|
||||||
|
14
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_xalign(
|
||||||
|
GTK_LABEL(
|
||||||
|
osint_tools_title
|
||||||
|
),
|
||||||
|
0.0F
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_add_css_class(
|
||||||
|
osint_tools_title,
|
||||||
|
"heading"
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_xalign(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_context_label
|
||||||
|
),
|
||||||
|
0.0F
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_selectable(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_context_label
|
||||||
|
),
|
||||||
|
TRUE
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_label_set_xalign(
|
||||||
|
GTK_LABEL(
|
||||||
|
workspace->osint_tools_status_label
|
||||||
|
),
|
||||||
|
0.0F
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_widget_add_css_class(
|
||||||
|
workspace->osint_tools_status_label,
|
||||||
|
"dim-label"
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(
|
||||||
|
osint_tools_content
|
||||||
|
),
|
||||||
|
osint_tools_title
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(
|
||||||
|
osint_tools_content
|
||||||
|
),
|
||||||
|
workspace->osint_tools_context_label
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(
|
||||||
|
osint_tools_content
|
||||||
|
),
|
||||||
|
workspace->osint_tools_status_label
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_popover_set_child(
|
||||||
|
GTK_POPOVER(
|
||||||
|
workspace->osint_tools_popover
|
||||||
|
),
|
||||||
|
osint_tools_content
|
||||||
|
);
|
||||||
|
|
||||||
|
gtk_menu_button_set_popover(
|
||||||
|
GTK_MENU_BUTTON(
|
||||||
|
workspace->osint_tools_button
|
||||||
|
),
|
||||||
|
workspace->osint_tools_popover
|
||||||
|
);
|
||||||
|
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
workspace->reset_graph_layout_button,
|
workspace->reset_graph_layout_button,
|
||||||
"clicked",
|
"clicked",
|
||||||
|
|
@ -1200,6 +1467,13 @@ Workspace *workspace_new(void)
|
||||||
workspace->reset_graph_layout_button
|
workspace->reset_graph_layout_button
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gtk_box_append(
|
||||||
|
GTK_BOX(
|
||||||
|
workspace->graph_toolbar
|
||||||
|
),
|
||||||
|
workspace->osint_tools_button
|
||||||
|
);
|
||||||
|
|
||||||
gtk_overlay_add_overlay(
|
gtk_overlay_add_overlay(
|
||||||
GTK_OVERLAY(
|
GTK_OVERLAY(
|
||||||
workspace->graph_view_page
|
workspace->graph_view_page
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue