feat(osint): integrate public username and email research tools
This commit is contained in:
parent
832e3eca32
commit
4e97d0979a
8 changed files with 402 additions and 3 deletions
|
|
@ -69,6 +69,9 @@ typedef void (*EntityDetailsPanelPersonNameCallback)(
|
||||||
/** @brief Callback appelé pour gérer les preuves d'une personne. */
|
/** @brief Callback appelé pour gérer les preuves d'une personne. */
|
||||||
typedef void (*EntityDetailsPanelPersonEvidenceCallback)(
|
typedef void (*EntityDetailsPanelPersonEvidenceCallback)(
|
||||||
const char *entity_identifier, gpointer user_data);
|
const char *entity_identifier, gpointer user_data);
|
||||||
|
/** @brief Callback appelé pour ouvrir les recherches OSINT compatibles. */
|
||||||
|
typedef void (*EntityDetailsPanelOsintCallback)(
|
||||||
|
const char *entity_identifier, gpointer user_data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Crée un volet de détails fermé.
|
* @brief Crée un volet de détails fermé.
|
||||||
|
|
@ -175,6 +178,9 @@ void entity_details_panel_set_person_name_callback(
|
||||||
void entity_details_panel_set_person_evidence_callback(
|
void entity_details_panel_set_person_evidence_callback(
|
||||||
EntityDetailsPanel *details_panel,
|
EntityDetailsPanel *details_panel,
|
||||||
EntityDetailsPanelPersonEvidenceCallback callback, gpointer user_data);
|
EntityDetailsPanelPersonEvidenceCallback callback, gpointer user_data);
|
||||||
|
/** @brief Définit le callback du bouton de recherche OSINT. */
|
||||||
|
void entity_details_panel_set_osint_callback(EntityDetailsPanel *details_panel,
|
||||||
|
EntityDetailsPanelOsintCallback callback, gpointer user_data);
|
||||||
/**
|
/**
|
||||||
* @brief Affiche les preuves associées à la personne courante.
|
* @brief Affiche les preuves associées à la personne courante.
|
||||||
* @param details_panel Volet à mettre à jour.
|
* @param details_panel Volet à mettre à jour.
|
||||||
|
|
|
||||||
|
|
@ -218,6 +218,7 @@ typedef struct
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Application *application;
|
Application *application;
|
||||||
|
char *action_identifier;
|
||||||
char *target_identifier;
|
char *target_identifier;
|
||||||
char *target_value;
|
char *target_value;
|
||||||
char *started_at;
|
char *started_at;
|
||||||
|
|
@ -231,6 +232,8 @@ typedef struct
|
||||||
char *execution_identifier;
|
char *execution_identifier;
|
||||||
GPtrArray *proposals;
|
GPtrArray *proposals;
|
||||||
} ApplicationOsintReviewContext;
|
} ApplicationOsintReviewContext;
|
||||||
|
static char *application_osint_output_to_utf8(GBytes *bytes);
|
||||||
|
static char *application_osint_create_timestamp(void);
|
||||||
/** @brief Contexte possédé pendant la révision d'une analyse EML. */
|
/** @brief Contexte possédé pendant la révision d'une analyse EML. */
|
||||||
typedef struct { Application *application; char *evidence_identifier; }
|
typedef struct { Application *application; char *evidence_identifier; }
|
||||||
ApplicationEmlReviewContext;
|
ApplicationEmlReviewContext;
|
||||||
|
|
@ -380,10 +383,153 @@ static void application_osint_action_context_free(
|
||||||
|
|
||||||
g_free(context->target_value);
|
g_free(context->target_value);
|
||||||
g_free(context->target_identifier);
|
g_free(context->target_identifier);
|
||||||
|
g_free(context->action_identifier);
|
||||||
g_free(context->started_at);
|
g_free(context->started_at);
|
||||||
g_free(context);
|
g_free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Extrait un pseudo final depuis une URL de profil social. */
|
||||||
|
static char *application_osint_search_target(const char *action_identifier,
|
||||||
|
const char *target_value)
|
||||||
|
{
|
||||||
|
char *target = g_strdup(target_value != NULL ? target_value : "");
|
||||||
|
char *query = NULL;
|
||||||
|
char *slash = NULL;
|
||||||
|
if (target == NULL) return NULL;
|
||||||
|
if (g_str_has_prefix(action_identifier, "social-"))
|
||||||
|
{
|
||||||
|
query = strchr(target, '?');
|
||||||
|
if (query != NULL) *query = '\0';
|
||||||
|
slash = strrchr(target, '/');
|
||||||
|
if (slash != NULL && slash[1] != '\0')
|
||||||
|
{
|
||||||
|
char *username = g_strdup(slash + 1);
|
||||||
|
g_free(target);
|
||||||
|
target = username;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Présente et archive la sortie d'une recherche sociale/email. */
|
||||||
|
static void application_on_osint_search_completed(BackgroundTask *task,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
ApplicationOsintActionContext *context = user_data;
|
||||||
|
const ToolTaskResult *task_result = NULL;
|
||||||
|
const ToolProcessResult *process_result = NULL;
|
||||||
|
GBytes *stdout_bytes = NULL;
|
||||||
|
GBytes *stderr_bytes = NULL;
|
||||||
|
char *stdout_text = NULL;
|
||||||
|
char *stderr_text = NULL;
|
||||||
|
char *details = NULL;
|
||||||
|
char *output_directory = NULL;
|
||||||
|
char *output_name = NULL;
|
||||||
|
char *output_path = NULL;
|
||||||
|
const InvestigationProject *project = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
if (context == NULL || context->application == NULL) return;
|
||||||
|
if (background_task_get_state(task) == BACKGROUND_TASK_STATE_CANCELLED)
|
||||||
|
{
|
||||||
|
main_window_set_status(context->application->main_window,
|
||||||
|
"Recherche OSINT annulée.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (background_task_get_state(task) != BACKGROUND_TASK_STATE_COMPLETED)
|
||||||
|
{
|
||||||
|
error = background_task_dup_error(task);
|
||||||
|
application_present_error(context->application, "Recherche OSINT impossible",
|
||||||
|
error != NULL ? error->message : "L'outil OSINT a échoué.");
|
||||||
|
g_clear_error(&error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task_result = tool_task_result_from_background_task(task);
|
||||||
|
process_result = tool_task_result_get_process_result(task_result);
|
||||||
|
stdout_bytes = tool_process_result_ref_stdout(process_result);
|
||||||
|
stderr_bytes = tool_process_result_ref_stderr(process_result);
|
||||||
|
stdout_text = application_osint_output_to_utf8(stdout_bytes);
|
||||||
|
stderr_text = application_osint_output_to_utf8(stderr_bytes);
|
||||||
|
project = investigation_session_get_project(context->application->session);
|
||||||
|
output_directory = project != NULL ? g_build_filename(
|
||||||
|
investigation_project_get_root_path(project), "02_Preuves_Traitees",
|
||||||
|
"Extractions", "OSINT", NULL) : NULL;
|
||||||
|
if (output_directory == NULL || g_mkdir_with_parents(output_directory, 0750) != 0)
|
||||||
|
goto failure;
|
||||||
|
output_name = g_strdup_printf("%s-%s.txt", context->target_identifier,
|
||||||
|
context->action_identifier);
|
||||||
|
output_path = g_build_filename(output_directory, output_name, NULL);
|
||||||
|
details = g_strdup_printf("Cible : %s\nAction : %s\n\n%s%s%s",
|
||||||
|
context->target_value, context->action_identifier,
|
||||||
|
stdout_text != NULL ? stdout_text : "",
|
||||||
|
stderr_text != NULL && stderr_text[0] != '\0' ? "\n\nErreur :\n" : "",
|
||||||
|
stderr_text != NULL ? stderr_text : "");
|
||||||
|
if (!g_file_set_contents(output_path, details, -1, &error)) goto failure;
|
||||||
|
application_message_dialog_present_details_action(
|
||||||
|
main_window_get_window(context->application->main_window),
|
||||||
|
APPLICATION_MESSAGE_DIALOG_INFORMATION, "Résultat de la recherche OSINT",
|
||||||
|
"La sortie publique a été archivée dans les preuves traitées.",
|
||||||
|
details, NULL, NULL, NULL, NULL);
|
||||||
|
goto cleanup;
|
||||||
|
failure:
|
||||||
|
application_present_error(context->application, "Archivage OSINT impossible",
|
||||||
|
error != NULL ? error->message : "La sortie n'a pas pu être conservée.");
|
||||||
|
cleanup:
|
||||||
|
g_clear_error(&error); g_clear_pointer(&stdout_bytes, g_bytes_unref);
|
||||||
|
g_clear_pointer(&stderr_bytes, g_bytes_unref); g_free(stdout_text);
|
||||||
|
g_free(stderr_text); g_free(details); g_free(output_directory);
|
||||||
|
g_free(output_name); g_free(output_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Lance Sherlock, Maigret ou Holehe selon l'action choisie. */
|
||||||
|
static void application_start_osint_search(Application *application,
|
||||||
|
const char *action_identifier, const char *target_identifier,
|
||||||
|
const char *target_value)
|
||||||
|
{
|
||||||
|
const char *tool_identifier = NULL;
|
||||||
|
const char *arguments[4] = { NULL, NULL, NULL, NULL };
|
||||||
|
char *search_target = NULL;
|
||||||
|
ToolTask *tool_task = NULL;
|
||||||
|
BackgroundTask *background_task = NULL;
|
||||||
|
ApplicationOsintActionContext *context = NULL;
|
||||||
|
GError *error = NULL;
|
||||||
|
if (g_strcmp0(action_identifier, "social-username-sherlock") == 0)
|
||||||
|
{ tool_identifier = "osint.sherlock"; arguments[0] = "--print-found";
|
||||||
|
arguments[1] = "--no-color"; }
|
||||||
|
else if (g_strcmp0(action_identifier, "social-username-maigret") == 0)
|
||||||
|
{ tool_identifier = "osint.maigret"; arguments[0] = "--json";
|
||||||
|
arguments[1] = "simple"; }
|
||||||
|
else if (g_strcmp0(action_identifier, "email-account-holehe") == 0)
|
||||||
|
{ tool_identifier = "osint.holehe"; arguments[0] = "--no-color"; }
|
||||||
|
else return;
|
||||||
|
search_target = application_osint_search_target(action_identifier, target_value);
|
||||||
|
arguments[2] = search_target;
|
||||||
|
tool_task = tool_task_new(tool_initializer_get_registry(application->tool_initializer),
|
||||||
|
tool_identifier, "Recherche OSINT", arguments, NULL, &error);
|
||||||
|
if (tool_task == NULL) goto failure;
|
||||||
|
context = g_new0(ApplicationOsintActionContext, 1);
|
||||||
|
context->application = application;
|
||||||
|
context->action_identifier = g_strdup(action_identifier);
|
||||||
|
context->target_identifier = g_strdup(target_identifier);
|
||||||
|
context->target_value = g_strdup(search_target);
|
||||||
|
context->started_at = application_osint_create_timestamp();
|
||||||
|
background_task = tool_task_get_background_task(tool_task);
|
||||||
|
if (context->action_identifier == NULL || context->target_identifier == NULL ||
|
||||||
|
context->target_value == NULL || context->started_at == NULL ||
|
||||||
|
!task_manager_add(application->task_manager, background_task, &error) ||
|
||||||
|
!tool_task_start(tool_task, application_on_osint_search_completed, context,
|
||||||
|
application_osint_action_context_free, &error)) goto failure;
|
||||||
|
context = NULL;
|
||||||
|
main_window_set_status(application->main_window,
|
||||||
|
"Recherche OSINT lancée ; progression disponible dans les tâches.");
|
||||||
|
goto cleanup;
|
||||||
|
failure:
|
||||||
|
application_osint_action_context_free(context);
|
||||||
|
application_present_error(application, "Recherche OSINT impossible",
|
||||||
|
error != NULL ? error->message : "Impossible de démarrer l'outil.");
|
||||||
|
cleanup:
|
||||||
|
g_clear_error(&error); tool_task_free(tool_task); g_free(search_target);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Libère le contexte du dialogue de métadonnées.
|
* @brief Libère le contexte du dialogue de métadonnées.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1678,6 +1824,15 @@ static void application_on_osint_action_requested(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (g_strcmp0(action_identifier, "social-username-sherlock") == 0 ||
|
||||||
|
g_strcmp0(action_identifier, "social-username-maigret") == 0 ||
|
||||||
|
g_strcmp0(action_identifier, "email-account-holehe") == 0)
|
||||||
|
{
|
||||||
|
application_start_osint_search(application, action_identifier,
|
||||||
|
target_identifier, target_value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
application_present_error(
|
application_present_error(
|
||||||
application,
|
application,
|
||||||
"Action OSINT inconnue",
|
"Action OSINT inconnue",
|
||||||
|
|
@ -7555,6 +7710,36 @@ static void application_on_activate(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Ajoute le répertoire privé des outils OSINT au PATH du processus. */
|
||||||
|
static void application_prepare_osint_tool_path(void)
|
||||||
|
{
|
||||||
|
const char *current_path = g_getenv("PATH");
|
||||||
|
const char *home_directory = g_get_home_dir();
|
||||||
|
char *osint_directory = NULL;
|
||||||
|
char *new_path = NULL;
|
||||||
|
|
||||||
|
if (home_directory == NULL || home_directory[0] == '\0') return;
|
||||||
|
osint_directory = g_build_filename(home_directory, ".local", "share",
|
||||||
|
"labfy-osint", "bin", NULL);
|
||||||
|
if (!g_file_test(osint_directory, G_FILE_TEST_IS_DIR))
|
||||||
|
{
|
||||||
|
g_free(osint_directory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (current_path != NULL && g_strstr_len(current_path, -1,
|
||||||
|
osint_directory) != NULL)
|
||||||
|
{
|
||||||
|
g_free(osint_directory);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new_path = g_strdup_printf("%s%s%s", osint_directory,
|
||||||
|
current_path != NULL && current_path[0] != '\0' ? G_SEARCHPATH_SEPARATOR_S :
|
||||||
|
"", current_path != NULL ? current_path : "");
|
||||||
|
g_setenv("PATH", new_path, TRUE);
|
||||||
|
g_free(new_path);
|
||||||
|
g_free(osint_directory);
|
||||||
|
}
|
||||||
|
|
||||||
Application *application_new(void)
|
Application *application_new(void)
|
||||||
{
|
{
|
||||||
Application *application = NULL;
|
Application *application = NULL;
|
||||||
|
|
@ -7565,6 +7750,8 @@ Application *application_new(void)
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
|
application_prepare_osint_tool_path();
|
||||||
|
|
||||||
application->task_manager =
|
application->task_manager =
|
||||||
task_manager_new();
|
task_manager_new();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,21 @@ static const char *const tool_catalog_qpdf_version_arguments[] =
|
||||||
"--version",
|
"--version",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
static const char *const tool_catalog_sherlock_version_arguments[] =
|
||||||
|
{
|
||||||
|
"--version",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const char *const tool_catalog_maigret_version_arguments[] =
|
||||||
|
{
|
||||||
|
"--version",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const char *const tool_catalog_holehe_version_arguments[] =
|
||||||
|
{
|
||||||
|
"--version",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Catalogue statique initial.
|
* @brief Catalogue statique initial.
|
||||||
|
|
@ -174,6 +189,30 @@ static const ToolCatalogEntry tool_catalog_entries[] =
|
||||||
.requirement = TOOL_REQUIREMENT_OPTIONAL,
|
.requirement = TOOL_REQUIREMENT_OPTIONAL,
|
||||||
.version_arguments = tool_catalog_qpdf_version_arguments,
|
.version_arguments = tool_catalog_qpdf_version_arguments,
|
||||||
.version_argument_count = 1
|
.version_argument_count = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.identifier = "osint.sherlock",
|
||||||
|
.display_name = "Sherlock",
|
||||||
|
.executable_name = "sherlock",
|
||||||
|
.requirement = TOOL_REQUIREMENT_OPTIONAL,
|
||||||
|
.version_arguments = tool_catalog_sherlock_version_arguments,
|
||||||
|
.version_argument_count = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.identifier = "osint.maigret",
|
||||||
|
.display_name = "Maigret",
|
||||||
|
.executable_name = "maigret",
|
||||||
|
.requirement = TOOL_REQUIREMENT_OPTIONAL,
|
||||||
|
.version_arguments = tool_catalog_maigret_version_arguments,
|
||||||
|
.version_argument_count = 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.identifier = "osint.holehe",
|
||||||
|
.display_name = "Holehe (vérification email)",
|
||||||
|
.executable_name = "holehe",
|
||||||
|
.requirement = TOOL_REQUIREMENT_OPTIONAL,
|
||||||
|
.version_arguments = tool_catalog_holehe_version_arguments,
|
||||||
|
.version_argument_count = 1
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,9 @@ OsintActionCatalog *osint_action_catalog_new_defaults(void)
|
||||||
OsintActionCatalog *catalog = g_try_new0(OsintActionCatalog, 1);
|
OsintActionCatalog *catalog = g_try_new0(OsintActionCatalog, 1);
|
||||||
OsintAction *demonstration_action = NULL;
|
OsintAction *demonstration_action = NULL;
|
||||||
OsintAction *dns_action = NULL;
|
OsintAction *dns_action = NULL;
|
||||||
|
OsintAction *sherlock_action = NULL;
|
||||||
|
OsintAction *maigret_action = NULL;
|
||||||
|
OsintAction *holehe_action = NULL;
|
||||||
if (catalog == NULL) return NULL;
|
if (catalog == NULL) return NULL;
|
||||||
catalog->actions = g_ptr_array_new_with_free_func(osint_action_free);
|
catalog->actions = g_ptr_array_new_with_free_func(osint_action_free);
|
||||||
demonstration_action = osint_action_new(
|
demonstration_action = osint_action_new(
|
||||||
|
|
@ -88,16 +91,41 @@ OsintActionCatalog *osint_action_catalog_new_defaults(void)
|
||||||
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "domain_name", "dns.dig", FALSE,
|
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "domain_name", "dns.dig", FALSE,
|
||||||
"L'outil requis n'a pas encore été vérifié."
|
"L'outil requis n'a pas encore été vérifié."
|
||||||
);
|
);
|
||||||
|
sherlock_action = osint_action_new(
|
||||||
|
"social-username-sherlock", "Rechercher le pseudo (Sherlock)",
|
||||||
|
"Recherche des profils publics correspondant au pseudo sélectionné.",
|
||||||
|
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "social_account", "osint.sherlock",
|
||||||
|
FALSE, "L'outil requis n'a pas encore été vérifié."
|
||||||
|
);
|
||||||
|
maigret_action = osint_action_new(
|
||||||
|
"social-username-maigret", "Rechercher le pseudo (Maigret)",
|
||||||
|
"Recherche complémentaire de profils publics par pseudo.",
|
||||||
|
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "social_account", "osint.maigret",
|
||||||
|
FALSE, "L'outil requis n'a pas encore été vérifié."
|
||||||
|
);
|
||||||
|
holehe_action = osint_action_new(
|
||||||
|
"email-account-holehe", "Rechercher l'email (Holehe)",
|
||||||
|
"Vérification publique optionnelle des services associés à l'email.",
|
||||||
|
OSINT_SELECTION_CONTEXT_KIND_ENTITY, "email_address", "osint.holehe",
|
||||||
|
FALSE, "L'outil requis n'a pas encore été vérifié."
|
||||||
|
);
|
||||||
if (catalog->actions == NULL || demonstration_action == NULL ||
|
if (catalog->actions == NULL || demonstration_action == NULL ||
|
||||||
dns_action == NULL)
|
dns_action == NULL || sherlock_action == NULL || maigret_action == NULL ||
|
||||||
|
holehe_action == NULL)
|
||||||
{
|
{
|
||||||
osint_action_free(demonstration_action);
|
osint_action_free(demonstration_action);
|
||||||
osint_action_free(dns_action);
|
osint_action_free(dns_action);
|
||||||
|
osint_action_free(sherlock_action);
|
||||||
|
osint_action_free(maigret_action);
|
||||||
|
osint_action_free(holehe_action);
|
||||||
osint_action_catalog_free(catalog);
|
osint_action_catalog_free(catalog);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
g_ptr_array_add(catalog->actions, demonstration_action);
|
g_ptr_array_add(catalog->actions, demonstration_action);
|
||||||
g_ptr_array_add(catalog->actions, dns_action);
|
g_ptr_array_add(catalog->actions, dns_action);
|
||||||
|
g_ptr_array_add(catalog->actions, sherlock_action);
|
||||||
|
g_ptr_array_add(catalog->actions, maigret_action);
|
||||||
|
g_ptr_array_add(catalog->actions, holehe_action);
|
||||||
return catalog;
|
return catalog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,6 +137,21 @@ static gint osint_action_compare(gconstpointer first, gconstpointer second)
|
||||||
return g_strcmp0((*a)->label, (*b)->label);
|
return g_strcmp0((*a)->label, (*b)->label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Regroupe les types de comptes sociaux pour les recherches publiques. */
|
||||||
|
static gboolean osint_action_social_type_matches(const char *expected,
|
||||||
|
const char *actual)
|
||||||
|
{
|
||||||
|
gboolean expected_social = g_strcmp0(expected, "social_account") == 0;
|
||||||
|
gboolean actual_social = actual != NULL &&
|
||||||
|
(g_strcmp0(actual, "social_account") == 0 ||
|
||||||
|
g_strcmp0(actual, "instagram_account") == 0 ||
|
||||||
|
g_strcmp0(actual, "tiktok_account") == 0 ||
|
||||||
|
g_strcmp0(actual, "facebook_account") == 0 ||
|
||||||
|
g_strcmp0(actual, "telegram_account") == 0 ||
|
||||||
|
g_strcmp0(actual, "x_account") == 0);
|
||||||
|
return expected_social && actual_social;
|
||||||
|
}
|
||||||
|
|
||||||
GPtrArray *osint_action_catalog_list_compatible(
|
GPtrArray *osint_action_catalog_list_compatible(
|
||||||
const OsintActionCatalog *catalog,
|
const OsintActionCatalog *catalog,
|
||||||
const OsintSelectionContext *context
|
const OsintSelectionContext *context
|
||||||
|
|
@ -126,9 +169,11 @@ GPtrArray *osint_action_catalog_list_compatible(
|
||||||
gboolean kind_matches = action->target_kind ==
|
gboolean kind_matches = action->target_kind ==
|
||||||
OSINT_SELECTION_CONTEXT_KIND_UNKNOWN ||
|
OSINT_SELECTION_CONTEXT_KIND_UNKNOWN ||
|
||||||
action->target_kind == osint_selection_context_get_kind(context);
|
action->target_kind == osint_selection_context_get_kind(context);
|
||||||
|
const char *context_type = osint_selection_context_get_type(context);
|
||||||
gboolean type_matches = action->compatible_type == NULL ||
|
gboolean type_matches = action->compatible_type == NULL ||
|
||||||
g_strcmp0(action->compatible_type,
|
g_strcmp0(action->compatible_type, context_type) == 0 ||
|
||||||
osint_selection_context_get_type(context)) == 0;
|
osint_action_social_type_matches(action->compatible_type,
|
||||||
|
context_type);
|
||||||
if (kind_matches && type_matches)
|
if (kind_matches && type_matches)
|
||||||
g_ptr_array_add(compatible_actions, action);
|
g_ptr_array_add(compatible_actions, action);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ struct EntityDetailsPanel
|
||||||
GtkWidget *root_revealer;
|
GtkWidget *root_revealer;
|
||||||
GtkWidget *frame;
|
GtkWidget *frame;
|
||||||
GtkWidget *add_relation_button;
|
GtkWidget *add_relation_button;
|
||||||
|
GtkWidget *osint_button;
|
||||||
GtkWidget *close_button;
|
GtkWidget *close_button;
|
||||||
|
|
||||||
GtkWidget *entity_title_label;
|
GtkWidget *entity_title_label;
|
||||||
|
|
@ -40,6 +41,7 @@ struct EntityDetailsPanel
|
||||||
GtkWidget *person_evidence_summary_label;
|
GtkWidget *person_evidence_summary_label;
|
||||||
|
|
||||||
char *selected_entity_identifier;
|
char *selected_entity_identifier;
|
||||||
|
char *selected_entity_type;
|
||||||
|
|
||||||
EntityDetailsPanelCloseCallback close_callback;
|
EntityDetailsPanelCloseCallback close_callback;
|
||||||
gpointer close_user_data;
|
gpointer close_user_data;
|
||||||
|
|
@ -59,7 +61,32 @@ struct EntityDetailsPanel
|
||||||
gpointer person_name_user_data;
|
gpointer person_name_user_data;
|
||||||
EntityDetailsPanelPersonEvidenceCallback person_evidence_callback;
|
EntityDetailsPanelPersonEvidenceCallback person_evidence_callback;
|
||||||
gpointer person_evidence_user_data;
|
gpointer person_evidence_user_data;
|
||||||
|
EntityDetailsPanelOsintCallback osint_callback;
|
||||||
|
gpointer osint_user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** @brief Indique si un type représente un compte social. */
|
||||||
|
static gboolean entity_details_panel_is_social_type(const char *type)
|
||||||
|
{
|
||||||
|
return g_strcmp0(type, "social_account") == 0 ||
|
||||||
|
g_strcmp0(type, "instagram_account") == 0 ||
|
||||||
|
g_strcmp0(type, "tiktok_account") == 0 ||
|
||||||
|
g_strcmp0(type, "facebook_account") == 0 ||
|
||||||
|
g_strcmp0(type, "telegram_account") == 0 ||
|
||||||
|
g_strcmp0(type, "x_account") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @brief Transmet la demande de recherche OSINT depuis la fiche. */
|
||||||
|
static void entity_details_panel_on_osint_clicked(GtkButton *button,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
EntityDetailsPanel *panel = user_data;
|
||||||
|
(void) button;
|
||||||
|
if (panel != NULL && panel->osint_callback != NULL &&
|
||||||
|
panel->selected_entity_identifier != NULL)
|
||||||
|
panel->osint_callback(panel->selected_entity_identifier,
|
||||||
|
panel->osint_user_data);
|
||||||
|
}
|
||||||
/** @brief Relaie la demande de gestion des preuves d'une personne. */
|
/** @brief Relaie la demande de gestion des preuves d'une personne. */
|
||||||
static void entity_details_panel_on_person_evidence_clicked(GtkButton *button,
|
static void entity_details_panel_on_person_evidence_clicked(GtkButton *button,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
|
|
@ -418,6 +445,8 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
||||||
gtk_button_new_from_icon_name(
|
gtk_button_new_from_icon_name(
|
||||||
"list-add-symbolic"
|
"list-add-symbolic"
|
||||||
);
|
);
|
||||||
|
details_panel->osint_button = gtk_button_new_from_icon_name(
|
||||||
|
"system-search-symbolic");
|
||||||
|
|
||||||
details_panel->close_button =
|
details_panel->close_button =
|
||||||
gtk_button_new_from_icon_name(
|
gtk_button_new_from_icon_name(
|
||||||
|
|
@ -461,6 +490,7 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
||||||
if (details_panel->root_revealer == NULL ||
|
if (details_panel->root_revealer == NULL ||
|
||||||
details_panel->frame == NULL ||
|
details_panel->frame == NULL ||
|
||||||
details_panel->add_relation_button == NULL ||
|
details_panel->add_relation_button == NULL ||
|
||||||
|
details_panel->osint_button == NULL ||
|
||||||
details_panel->close_button == NULL ||
|
details_panel->close_button == NULL ||
|
||||||
content_box == NULL ||
|
content_box == NULL ||
|
||||||
header_box == NULL ||
|
header_box == NULL ||
|
||||||
|
|
@ -588,6 +618,10 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
||||||
details_panel->add_relation_button,
|
details_panel->add_relation_button,
|
||||||
"flat"
|
"flat"
|
||||||
);
|
);
|
||||||
|
gtk_widget_set_tooltip_text(details_panel->osint_button,
|
||||||
|
"Recherches OSINT compatibles");
|
||||||
|
gtk_widget_add_css_class(details_panel->osint_button, "flat");
|
||||||
|
gtk_widget_set_sensitive(details_panel->osint_button, FALSE);
|
||||||
|
|
||||||
gtk_widget_set_sensitive(
|
gtk_widget_set_sensitive(
|
||||||
details_panel->add_relation_button,
|
details_panel->add_relation_button,
|
||||||
|
|
@ -609,6 +643,8 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
||||||
header_label
|
header_label
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gtk_box_append(GTK_BOX(header_box), details_panel->osint_button);
|
||||||
|
|
||||||
gtk_box_append(
|
gtk_box_append(
|
||||||
GTK_BOX(header_box),
|
GTK_BOX(header_box),
|
||||||
details_panel->add_relation_button
|
details_panel->add_relation_button
|
||||||
|
|
@ -880,6 +916,9 @@ EntityDetailsPanel *entity_details_panel_new(void)
|
||||||
details_panel->frame
|
details_panel->frame
|
||||||
);
|
);
|
||||||
|
|
||||||
|
g_signal_connect(
|
||||||
|
details_panel->osint_button, "clicked",
|
||||||
|
G_CALLBACK(entity_details_panel_on_osint_clicked), details_panel);
|
||||||
g_signal_connect(
|
g_signal_connect(
|
||||||
details_panel->add_relation_button,
|
details_panel->add_relation_button,
|
||||||
"clicked",
|
"clicked",
|
||||||
|
|
@ -937,6 +976,7 @@ void entity_details_panel_set_entity(
|
||||||
&details_panel->selected_entity_identifier,
|
&details_panel->selected_entity_identifier,
|
||||||
g_free
|
g_free
|
||||||
);
|
);
|
||||||
|
g_clear_pointer(&details_panel->selected_entity_type, g_free);
|
||||||
|
|
||||||
if (entity_record == NULL)
|
if (entity_record == NULL)
|
||||||
{
|
{
|
||||||
|
|
@ -953,6 +993,12 @@ void entity_details_panel_set_entity(
|
||||||
entity_record
|
entity_record
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
details_panel->selected_entity_type = g_strdup(
|
||||||
|
entity_record_get_type_identifier(entity_record));
|
||||||
|
gtk_widget_set_sensitive(details_panel->osint_button,
|
||||||
|
details_panel->osint_callback != NULL &&
|
||||||
|
(g_strcmp0(details_panel->selected_entity_type, "email_address") == 0 ||
|
||||||
|
entity_details_panel_is_social_type(details_panel->selected_entity_type)));
|
||||||
|
|
||||||
gboolean is_person = g_strcmp0(entity_record_get_type_identifier(
|
gboolean is_person = g_strcmp0(entity_record_get_type_identifier(
|
||||||
entity_record), "person") == 0;
|
entity_record), "person") == 0;
|
||||||
|
|
@ -1098,6 +1144,9 @@ void entity_details_panel_clear(
|
||||||
&details_panel->selected_entity_identifier,
|
&details_panel->selected_entity_identifier,
|
||||||
g_free
|
g_free
|
||||||
);
|
);
|
||||||
|
g_clear_pointer(&details_panel->selected_entity_type, g_free);
|
||||||
|
if (details_panel->osint_button != NULL)
|
||||||
|
gtk_widget_set_sensitive(details_panel->osint_button, FALSE);
|
||||||
|
|
||||||
entity_details_panel_update_add_relation_button(
|
entity_details_panel_update_add_relation_button(
|
||||||
details_panel
|
details_panel
|
||||||
|
|
@ -1246,6 +1295,18 @@ void entity_details_panel_set_person_evidence_callback(
|
||||||
details_panel->person_evidence_callback = callback;
|
details_panel->person_evidence_callback = callback;
|
||||||
details_panel->person_evidence_user_data = user_data;
|
details_panel->person_evidence_user_data = user_data;
|
||||||
}
|
}
|
||||||
|
void entity_details_panel_set_osint_callback(EntityDetailsPanel *details_panel,
|
||||||
|
EntityDetailsPanelOsintCallback callback, gpointer user_data)
|
||||||
|
{
|
||||||
|
if (details_panel == NULL) return;
|
||||||
|
details_panel->osint_callback = callback;
|
||||||
|
details_panel->osint_user_data = user_data;
|
||||||
|
if (details_panel->osint_button != NULL)
|
||||||
|
gtk_widget_set_sensitive(details_panel->osint_button,
|
||||||
|
callback != NULL && details_panel->selected_entity_type != NULL &&
|
||||||
|
(g_strcmp0(details_panel->selected_entity_type, "email_address") == 0 ||
|
||||||
|
entity_details_panel_is_social_type(details_panel->selected_entity_type)));
|
||||||
|
}
|
||||||
void entity_details_panel_set_person_evidences(EntityDetailsPanel *panel,
|
void entity_details_panel_set_person_evidences(EntityDetailsPanel *panel,
|
||||||
const GPtrArray *records)
|
const GPtrArray *records)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -444,6 +444,18 @@ static void workspace_update_osint_tools_menu(
|
||||||
g_clear_pointer(&compatible_actions, g_ptr_array_unref);
|
g_clear_pointer(&compatible_actions, g_ptr_array_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @brief Ouvre le menu OSINT depuis le bouton de la fiche entité. */
|
||||||
|
static void workspace_on_entity_osint_requested(const char *entity_identifier,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
Workspace *workspace = user_data;
|
||||||
|
(void) entity_identifier;
|
||||||
|
if (workspace == NULL || workspace->osint_tools_popover == NULL) return;
|
||||||
|
workspace_update_osint_tools_menu(workspace,
|
||||||
|
workspace->osint_selection_context);
|
||||||
|
gtk_popover_popup(GTK_POPOVER(workspace->osint_tools_popover));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Ajoute une ligne de métadonnée dans la grille.
|
* @brief Ajoute une ligne de métadonnée dans la grille.
|
||||||
*
|
*
|
||||||
|
|
@ -1945,6 +1957,8 @@ Workspace *workspace_new(void)
|
||||||
entity_details_panel_set_person_evidence_callback(
|
entity_details_panel_set_person_evidence_callback(
|
||||||
workspace->entity_details_panel,
|
workspace->entity_details_panel,
|
||||||
workspace_on_person_evidence_requested, workspace);
|
workspace_on_person_evidence_requested, workspace);
|
||||||
|
entity_details_panel_set_osint_callback(workspace->entity_details_panel,
|
||||||
|
workspace_on_entity_osint_requested, workspace);
|
||||||
|
|
||||||
gtk_overlay_set_child(
|
gtk_overlay_set_child(
|
||||||
GTK_OVERLAY(
|
GTK_OVERLAY(
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,34 @@ static void test_non_domain_actions(void)
|
||||||
osint_action_catalog_free(catalog);
|
osint_action_catalog_free(catalog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_social_and_email_actions(void)
|
||||||
|
{
|
||||||
|
OsintActionCatalog *catalog = osint_action_catalog_new_defaults();
|
||||||
|
OsintSelectionContext *social = create_entity_context("social_account");
|
||||||
|
OsintSelectionContext *email = create_entity_context("email_address");
|
||||||
|
OsintSelectionContext *instagram = create_entity_context("instagram_account");
|
||||||
|
OsintSelectionContext *facebook = create_entity_context("facebook_account");
|
||||||
|
GPtrArray *actions = osint_action_catalog_list_compatible(catalog, social);
|
||||||
|
GPtrArray *email_actions = osint_action_catalog_list_compatible(catalog, email);
|
||||||
|
GPtrArray *instagram_actions = osint_action_catalog_list_compatible(catalog, instagram);
|
||||||
|
GPtrArray *facebook_actions = osint_action_catalog_list_compatible(catalog, facebook);
|
||||||
|
g_assert_cmpuint(actions->len, ==, 3U);
|
||||||
|
g_assert_cmpuint(email_actions->len, ==, 2U);
|
||||||
|
g_assert_cmpuint(instagram_actions->len, ==, 3U);
|
||||||
|
g_assert_cmpuint(facebook_actions->len, ==, 3U);
|
||||||
|
g_assert_cmpstr(osint_action_get_identifier(g_ptr_array_index(email_actions, 1)),
|
||||||
|
==, "email-account-holehe");
|
||||||
|
g_ptr_array_unref(actions);
|
||||||
|
g_ptr_array_unref(email_actions);
|
||||||
|
g_ptr_array_unref(instagram_actions);
|
||||||
|
g_ptr_array_unref(facebook_actions);
|
||||||
|
osint_selection_context_free(social);
|
||||||
|
osint_selection_context_free(email);
|
||||||
|
osint_selection_context_free(instagram);
|
||||||
|
osint_selection_context_free(facebook);
|
||||||
|
osint_action_catalog_free(catalog);
|
||||||
|
}
|
||||||
|
|
||||||
static void test_invalid_arguments(void)
|
static void test_invalid_arguments(void)
|
||||||
{
|
{
|
||||||
OsintActionCatalog *catalog = osint_action_catalog_new_defaults();
|
OsintActionCatalog *catalog = osint_action_catalog_new_defaults();
|
||||||
|
|
@ -92,6 +120,7 @@ int main(int argc, char **argv)
|
||||||
g_test_init(&argc, &argv, NULL);
|
g_test_init(&argc, &argv, NULL);
|
||||||
g_test_add_func("/osint-action-catalog/domain", test_domain_actions);
|
g_test_add_func("/osint-action-catalog/domain", test_domain_actions);
|
||||||
g_test_add_func("/osint-action-catalog/non-domain", test_non_domain_actions);
|
g_test_add_func("/osint-action-catalog/non-domain", test_non_domain_actions);
|
||||||
|
g_test_add_func("/osint-action-catalog/social-email", test_social_and_email_actions);
|
||||||
g_test_add_func("/osint-action-catalog/invalid", test_invalid_arguments);
|
g_test_add_func("/osint-action-catalog/invalid", test_invalid_arguments);
|
||||||
g_test_add_func("/osint-action-catalog/tool-states", test_tool_states);
|
g_test_add_func("/osint-action-catalog/tool-states", test_tool_states);
|
||||||
return g_test_run();
|
return g_test_run();
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,24 @@ static const ExpectedToolCatalogEntry expected_catalog_entries[] =
|
||||||
.display_name = "qpdf",
|
.display_name = "qpdf",
|
||||||
.executable_name = "qpdf",
|
.executable_name = "qpdf",
|
||||||
.version_argument = "--version"
|
.version_argument = "--version"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.identifier = "osint.sherlock",
|
||||||
|
.display_name = "Sherlock",
|
||||||
|
.executable_name = "sherlock",
|
||||||
|
.version_argument = "--version"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.identifier = "osint.maigret",
|
||||||
|
.display_name = "Maigret",
|
||||||
|
.executable_name = "maigret",
|
||||||
|
.version_argument = "--version"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.identifier = "osint.holehe",
|
||||||
|
.display_name = "Holehe (vérification email)",
|
||||||
|
.executable_name = "holehe",
|
||||||
|
.version_argument = "--version"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue