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 d’outils en tâche de fond ;
|
||||
- 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 :
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ G_BEGIN_DECLS
|
|||
*/
|
||||
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.
|
||||
*/
|
||||
|
|
@ -33,13 +38,17 @@ typedef struct InvestigationGraphView InvestigationGraphView;
|
|||
/**
|
||||
* @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 relation_record Relation sélectionnée empruntée, ou NULL.
|
||||
* @param user_data Données empruntées fournies par l'appelant.
|
||||
*/
|
||||
typedef void (*InvestigationGraphViewSelectionCallback)(
|
||||
const EntityRecord *entity_record,
|
||||
const RelationRecord *relation_record,
|
||||
gpointer user_data
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ typedef void (*WorkspaceVerifyEvidenceCallback)(
|
|||
*
|
||||
* 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 y Coordonnée verticale logique.
|
||||
* @param user_data Données empruntées fournies par l'appelant.
|
||||
*/
|
||||
typedef void (*WorkspaceGraphNodeMovedCallback)(
|
||||
const char *entity_identifier,
|
||||
const char *node_identifier,
|
||||
double x,
|
||||
double y,
|
||||
gpointer user_data
|
||||
|
|
|
|||
|
|
@ -623,6 +623,9 @@ static void investigation_graph_view_set_selected_node(
|
|||
const EntityRecord *entity_record =
|
||||
NULL;
|
||||
|
||||
const RelationRecord *relation_record =
|
||||
NULL;
|
||||
|
||||
if (graph_view == NULL ||
|
||||
graph_view->selected_node == node_layout)
|
||||
{
|
||||
|
|
@ -639,6 +642,13 @@ static void investigation_graph_view_set_selected_node(
|
|||
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)
|
||||
{
|
||||
|
|
@ -651,6 +661,7 @@ static void investigation_graph_view_set_selected_node(
|
|||
{
|
||||
graph_view->selection_callback(
|
||||
entity_record,
|
||||
relation_record,
|
||||
graph_view->selection_user_data
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "widgets/workspace.h"
|
||||
|
||||
#include "models/entity_record.h"
|
||||
#include "models/relation_record.h"
|
||||
#include "widgets/entity_details_panel.h"
|
||||
#include "widgets/investigation_graph_view.h"
|
||||
|
||||
|
|
@ -49,6 +51,10 @@ struct Workspace
|
|||
GtkWidget *graph_view_page;
|
||||
GtkWidget *graph_toolbar;
|
||||
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_popover;
|
||||
|
||||
|
|
@ -111,6 +117,110 @@ struct Workspace
|
|||
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.
|
||||
*
|
||||
|
|
@ -310,26 +420,35 @@ static void workspace_on_graph_node_moved(
|
|||
/**
|
||||
* @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 RelationRecord *relation_record,
|
||||
gpointer user_data
|
||||
)
|
||||
{
|
||||
Workspace *workspace =
|
||||
user_data;
|
||||
|
||||
if (workspace == NULL ||
|
||||
workspace->entity_details_panel == NULL)
|
||||
if (workspace == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (workspace->entity_details_panel != NULL)
|
||||
{
|
||||
entity_details_panel_set_entity(
|
||||
workspace->entity_details_panel,
|
||||
entity_record
|
||||
);
|
||||
}
|
||||
|
||||
workspace_update_osint_tools_menu(
|
||||
workspace,
|
||||
entity_record,
|
||||
relation_record
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Relaie la demande d'ajout d'une relation.
|
||||
*/
|
||||
|
|
@ -1092,7 +1211,7 @@ Workspace *workspace_new(void)
|
|||
|
||||
investigation_graph_view_set_selection_callback(
|
||||
workspace->graph_view,
|
||||
workspace_on_graph_entity_selected,
|
||||
workspace_on_graph_node_selected,
|
||||
workspace
|
||||
);
|
||||
|
||||
|
|
@ -1134,8 +1253,41 @@ Workspace *workspace_new(void)
|
|||
"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 ||
|
||||
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
|
||||
|
|
@ -1184,6 +1336,121 @@ Workspace *workspace_new(void)
|
|||
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(
|
||||
workspace->reset_graph_layout_button,
|
||||
"clicked",
|
||||
|
|
@ -1200,6 +1467,13 @@ Workspace *workspace_new(void)
|
|||
workspace->reset_graph_layout_button
|
||||
);
|
||||
|
||||
gtk_box_append(
|
||||
GTK_BOX(
|
||||
workspace->graph_toolbar
|
||||
),
|
||||
workspace->osint_tools_button
|
||||
);
|
||||
|
||||
gtk_overlay_add_overlay(
|
||||
GTK_OVERLAY(
|
||||
workspace->graph_view_page
|
||||
|
|
|
|||
Loading…
Reference in a new issue