diff --git a/include/widgets/entity_details_panel.h b/include/widgets/entity_details_panel.h index 509fce9..4eba95b 100644 --- a/include/widgets/entity_details_panel.h +++ b/include/widgets/entity_details_panel.h @@ -69,6 +69,9 @@ typedef void (*EntityDetailsPanelPersonNameCallback)( /** @brief Callback appelé pour gérer les preuves d'une personne. */ typedef void (*EntityDetailsPanelPersonEvidenceCallback)( 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é. @@ -175,6 +178,9 @@ void entity_details_panel_set_person_name_callback( void entity_details_panel_set_person_evidence_callback( EntityDetailsPanel *details_panel, 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. * @param details_panel Volet à mettre à jour. diff --git a/src/core/application.c b/src/core/application.c index 8330fe4..3675bbf 100644 --- a/src/core/application.c +++ b/src/core/application.c @@ -218,6 +218,7 @@ typedef struct typedef struct { Application *application; + char *action_identifier; char *target_identifier; char *target_value; char *started_at; @@ -231,6 +232,8 @@ typedef struct char *execution_identifier; GPtrArray *proposals; } 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. */ typedef struct { Application *application; char *evidence_identifier; } ApplicationEmlReviewContext; @@ -380,10 +383,153 @@ static void application_osint_action_context_free( g_free(context->target_value); g_free(context->target_identifier); + g_free(context->action_identifier); g_free(context->started_at); 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. */ @@ -1678,6 +1824,15 @@ static void application_on_osint_action_requested( 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, "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 = NULL; @@ -7565,6 +7750,8 @@ Application *application_new(void) 1 ); + application_prepare_osint_tool_path(); + application->task_manager = task_manager_new(); diff --git a/src/core/tool_catalog.c b/src/core/tool_catalog.c index 0a2d124..72de867 100644 --- a/src/core/tool_catalog.c +++ b/src/core/tool_catalog.c @@ -84,6 +84,21 @@ static const char *const tool_catalog_qpdf_version_arguments[] = "--version", 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. @@ -174,6 +189,30 @@ static const ToolCatalogEntry tool_catalog_entries[] = .requirement = TOOL_REQUIREMENT_OPTIONAL, .version_arguments = tool_catalog_qpdf_version_arguments, .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 } }; diff --git a/src/models/osint_action_catalog.c b/src/models/osint_action_catalog.c index 1a75857..87718d4 100644 --- a/src/models/osint_action_catalog.c +++ b/src/models/osint_action_catalog.c @@ -75,6 +75,9 @@ OsintActionCatalog *osint_action_catalog_new_defaults(void) OsintActionCatalog *catalog = g_try_new0(OsintActionCatalog, 1); OsintAction *demonstration_action = NULL; OsintAction *dns_action = NULL; + OsintAction *sherlock_action = NULL; + OsintAction *maigret_action = NULL; + OsintAction *holehe_action = NULL; if (catalog == NULL) return NULL; catalog->actions = g_ptr_array_new_with_free_func(osint_action_free); 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, "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 || - dns_action == NULL) + dns_action == NULL || sherlock_action == NULL || maigret_action == NULL || + holehe_action == NULL) { osint_action_free(demonstration_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); return NULL; } g_ptr_array_add(catalog->actions, demonstration_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; } @@ -109,6 +137,21 @@ static gint osint_action_compare(gconstpointer first, gconstpointer second) 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( const OsintActionCatalog *catalog, const OsintSelectionContext *context @@ -126,9 +169,11 @@ GPtrArray *osint_action_catalog_list_compatible( gboolean kind_matches = action->target_kind == OSINT_SELECTION_CONTEXT_KIND_UNKNOWN || 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 || - g_strcmp0(action->compatible_type, - osint_selection_context_get_type(context)) == 0; + g_strcmp0(action->compatible_type, context_type) == 0 || + osint_action_social_type_matches(action->compatible_type, + context_type); if (kind_matches && type_matches) g_ptr_array_add(compatible_actions, action); } diff --git a/src/widgets/entity_details_panel.c b/src/widgets/entity_details_panel.c index e3d3fdc..9245f77 100644 --- a/src/widgets/entity_details_panel.c +++ b/src/widgets/entity_details_panel.c @@ -19,6 +19,7 @@ struct EntityDetailsPanel GtkWidget *root_revealer; GtkWidget *frame; GtkWidget *add_relation_button; + GtkWidget *osint_button; GtkWidget *close_button; GtkWidget *entity_title_label; @@ -40,6 +41,7 @@ struct EntityDetailsPanel GtkWidget *person_evidence_summary_label; char *selected_entity_identifier; + char *selected_entity_type; EntityDetailsPanelCloseCallback close_callback; gpointer close_user_data; @@ -59,7 +61,32 @@ struct EntityDetailsPanel gpointer person_name_user_data; EntityDetailsPanelPersonEvidenceCallback person_evidence_callback; 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. */ static void entity_details_panel_on_person_evidence_clicked(GtkButton *button, gpointer user_data) @@ -418,6 +445,8 @@ EntityDetailsPanel *entity_details_panel_new(void) gtk_button_new_from_icon_name( "list-add-symbolic" ); + details_panel->osint_button = gtk_button_new_from_icon_name( + "system-search-symbolic"); details_panel->close_button = gtk_button_new_from_icon_name( @@ -461,6 +490,7 @@ EntityDetailsPanel *entity_details_panel_new(void) if (details_panel->root_revealer == NULL || details_panel->frame == NULL || details_panel->add_relation_button == NULL || + details_panel->osint_button == NULL || details_panel->close_button == NULL || content_box == NULL || header_box == NULL || @@ -588,6 +618,10 @@ EntityDetailsPanel *entity_details_panel_new(void) details_panel->add_relation_button, "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( details_panel->add_relation_button, @@ -609,6 +643,8 @@ EntityDetailsPanel *entity_details_panel_new(void) header_label ); + gtk_box_append(GTK_BOX(header_box), details_panel->osint_button); + gtk_box_append( GTK_BOX(header_box), details_panel->add_relation_button @@ -880,6 +916,9 @@ EntityDetailsPanel *entity_details_panel_new(void) details_panel->frame ); + g_signal_connect( + details_panel->osint_button, "clicked", + G_CALLBACK(entity_details_panel_on_osint_clicked), details_panel); g_signal_connect( details_panel->add_relation_button, "clicked", @@ -937,6 +976,7 @@ void entity_details_panel_set_entity( &details_panel->selected_entity_identifier, g_free ); + g_clear_pointer(&details_panel->selected_entity_type, g_free); if (entity_record == NULL) { @@ -953,6 +993,12 @@ void entity_details_panel_set_entity( 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( entity_record), "person") == 0; @@ -1098,6 +1144,9 @@ void entity_details_panel_clear( &details_panel->selected_entity_identifier, 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( details_panel @@ -1246,6 +1295,18 @@ void entity_details_panel_set_person_evidence_callback( details_panel->person_evidence_callback = callback; 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, const GPtrArray *records) { diff --git a/src/widgets/workspace.c b/src/widgets/workspace.c index d080d47..7d410ba 100644 --- a/src/widgets/workspace.c +++ b/src/widgets/workspace.c @@ -444,6 +444,18 @@ static void workspace_update_osint_tools_menu( 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. * @@ -1945,6 +1957,8 @@ Workspace *workspace_new(void) entity_details_panel_set_person_evidence_callback( workspace->entity_details_panel, 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( diff --git a/tests/test_osint_action_catalog.c b/tests/test_osint_action_catalog.c index ee0637d..8560041 100644 --- a/tests/test_osint_action_catalog.c +++ b/tests/test_osint_action_catalog.c @@ -50,6 +50,34 @@ static void test_non_domain_actions(void) 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) { 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_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/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/tool-states", test_tool_states); return g_test_run(); diff --git a/tests/test_tool_catalog.c b/tests/test_tool_catalog.c index 1dde2d0..f251bdf 100644 --- a/tests/test_tool_catalog.c +++ b/tests/test_tool_catalog.c @@ -86,6 +86,24 @@ static const ExpectedToolCatalogEntry expected_catalog_entries[] = .display_name = "qpdf", .executable_name = "qpdf", .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" } };