287 lines
14 KiB
C
287 lines
14 KiB
C
/******************************************************************************
|
|
* @file osint_execution_dao.c
|
|
* @brief Persistance de la provenance des exécutions OSINT.
|
|
******************************************************************************/
|
|
|
|
#include "dao/osint_execution_dao.h"
|
|
|
|
#include "database/error.h"
|
|
#include "database/statement.h"
|
|
|
|
struct OsintExecutionDao { Database *database; };
|
|
|
|
static const char *const insert_sql =
|
|
"INSERT INTO osint_executions(id,tool_identifier,tool_version,"
|
|
"action_identifier,selection_id,selection_kind,target_value,arguments,"
|
|
"started_at,finished_at,exit_code,final_state,stdout_raw,stderr_raw,"
|
|
"output_sha256) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?);";
|
|
static const char *const find_sql =
|
|
"SELECT id,tool_identifier,tool_version,action_identifier,selection_id,"
|
|
"selection_kind,target_value,arguments,started_at,finished_at,exit_code,"
|
|
"final_state,stdout_raw,stderr_raw,output_sha256 FROM osint_executions "
|
|
"WHERE id=?;";
|
|
static const char *const list_by_selection_sql =
|
|
"SELECT id,tool_identifier,tool_version,action_identifier,selection_id,"
|
|
"selection_kind,target_value,arguments,started_at,finished_at,exit_code,"
|
|
"final_state,stdout_raw,stderr_raw,output_sha256 FROM osint_executions "
|
|
"WHERE (selection_kind=? AND selection_id=?) "
|
|
"OR (?='entity' AND id IN (SELECT execution_id "
|
|
"FROM osint_execution_entities WHERE entity_id=?)) "
|
|
"OR (?='relation' AND id IN (SELECT execution_id "
|
|
"FROM osint_execution_relations WHERE relation_id=?)) "
|
|
"ORDER BY finished_at DESC,id DESC;";
|
|
static const char *const list_linked_objects_sql =
|
|
"SELECT 'Entité',entity_id,disposition FROM osint_execution_entities "
|
|
"WHERE execution_id=? UNION ALL "
|
|
"SELECT 'Relation',relation_id,disposition FROM osint_execution_relations "
|
|
"WHERE execution_id=? ORDER BY 1,2;";
|
|
|
|
static void osint_execution_dao_set_error(
|
|
OsintExecutionDao *dao, GError **error, const char *context
|
|
)
|
|
{
|
|
if (error != NULL && *error == NULL)
|
|
g_set_error(error, G_IO_ERROR, G_IO_ERROR_FAILED, "%s : %s", context,
|
|
dao != NULL && database_error_get_message(dao->database) != NULL
|
|
? database_error_get_message(dao->database) : "erreur SQLite");
|
|
}
|
|
|
|
OsintExecutionDao *osint_execution_dao_new(Database *database, GError **error)
|
|
{
|
|
if (database == NULL)
|
|
{
|
|
g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
|
"La connexion de provenance OSINT est absente.");
|
|
return NULL;
|
|
}
|
|
OsintExecutionDao *dao = g_try_new0(OsintExecutionDao, 1);
|
|
if (dao != NULL) dao->database = database;
|
|
return dao;
|
|
}
|
|
|
|
void osint_execution_dao_free(OsintExecutionDao *dao) { g_free(dao); }
|
|
|
|
gboolean osint_execution_dao_insert(
|
|
OsintExecutionDao *dao, const OsintExecutionRecord *record, GError **error
|
|
)
|
|
{
|
|
DatabaseStatement *statement = NULL;
|
|
GBytes *stdout_raw = NULL;
|
|
GBytes *stderr_raw = NULL;
|
|
gboolean success = FALSE;
|
|
if (dao == NULL || record == NULL) return FALSE;
|
|
statement = database_statement_prepare(dao->database, insert_sql);
|
|
if (statement == NULL) goto cleanup;
|
|
stdout_raw = osint_execution_record_ref_stdout(record);
|
|
stderr_raw = osint_execution_record_ref_stderr(record);
|
|
success = database_statement_bind_text(statement, 1,
|
|
osint_execution_record_get_identifier(record)) &&
|
|
database_statement_bind_text(statement, 2,
|
|
osint_execution_record_get_tool_identifier(record)) &&
|
|
(osint_execution_record_get_tool_version(record) != NULL
|
|
? database_statement_bind_text(statement, 3,
|
|
osint_execution_record_get_tool_version(record))
|
|
: database_statement_bind_null(statement, 3)) &&
|
|
database_statement_bind_text(statement, 4,
|
|
osint_execution_record_get_action_identifier(record)) &&
|
|
database_statement_bind_text(statement, 5,
|
|
osint_execution_record_get_selection_identifier(record)) &&
|
|
database_statement_bind_text(statement, 6,
|
|
osint_execution_record_get_selection_kind(record)) &&
|
|
database_statement_bind_text(statement, 7,
|
|
osint_execution_record_get_target_value(record)) &&
|
|
database_statement_bind_text(statement, 8,
|
|
osint_execution_record_get_arguments(record)) &&
|
|
database_statement_bind_text(statement, 9,
|
|
osint_execution_record_get_started_at(record)) &&
|
|
database_statement_bind_text(statement, 10,
|
|
osint_execution_record_get_finished_at(record)) &&
|
|
(osint_execution_record_has_exit_code(record)
|
|
? database_statement_bind_int64(statement, 11,
|
|
osint_execution_record_get_exit_code(record))
|
|
: database_statement_bind_null(statement, 11)) &&
|
|
database_statement_bind_text(statement, 12,
|
|
osint_execution_record_get_final_state(record)) &&
|
|
database_statement_bind_blob(statement, 13, stdout_raw) &&
|
|
database_statement_bind_blob(statement, 14, stderr_raw) &&
|
|
database_statement_bind_text(statement, 15,
|
|
osint_execution_record_get_output_sha256(record)) &&
|
|
database_statement_step(statement) == DATABASE_STATEMENT_STEP_DONE;
|
|
cleanup:
|
|
if (!success) osint_execution_dao_set_error(dao, error,
|
|
"Impossible d'insérer l'exécution OSINT");
|
|
g_clear_pointer(&stdout_raw, g_bytes_unref);
|
|
g_clear_pointer(&stderr_raw, g_bytes_unref);
|
|
database_statement_finalize(statement);
|
|
return success;
|
|
}
|
|
|
|
static OsintExecutionRecord *osint_execution_dao_read_record(
|
|
DatabaseStatement *statement, GError **error
|
|
)
|
|
{
|
|
OsintExecutionRecord *record = NULL;
|
|
char *values[12] = {0};
|
|
GBytes *stdout_raw = NULL;
|
|
GBytes *stderr_raw = NULL;
|
|
int64_t exit_code = 0;
|
|
bool exit_is_null = true;
|
|
if (!database_statement_column_text(statement, 0, &values[0]) ||
|
|
!database_statement_column_text(statement, 1, &values[1]) ||
|
|
!database_statement_column_text(statement, 2, &values[2]) ||
|
|
!database_statement_column_text(statement, 3, &values[3]) ||
|
|
!database_statement_column_text(statement, 4, &values[4]) ||
|
|
!database_statement_column_text(statement, 5, &values[5]) ||
|
|
!database_statement_column_text(statement, 6, &values[6]) ||
|
|
!database_statement_column_text(statement, 7, &values[7]) ||
|
|
!database_statement_column_text(statement, 8, &values[8]) ||
|
|
!database_statement_column_text(statement, 9, &values[9]) ||
|
|
!database_statement_column_is_null(statement, 10, &exit_is_null) ||
|
|
(!exit_is_null && !database_statement_column_int64(statement, 10, &exit_code)) ||
|
|
!database_statement_column_text(statement, 11, &values[10]) ||
|
|
!database_statement_column_blob(statement, 12, &stdout_raw) ||
|
|
!database_statement_column_blob(statement, 13, &stderr_raw) ||
|
|
!database_statement_column_text(statement, 14, &values[11])) goto cleanup;
|
|
record = osint_execution_record_new(
|
|
values[0], values[1], values[2], values[3], values[4], values[5],
|
|
values[6], values[7], values[8], values[9], !exit_is_null,
|
|
(gint) exit_code, values[10], stdout_raw, stderr_raw, values[11], error);
|
|
cleanup:
|
|
for (guint index = 0; index < G_N_ELEMENTS(values); index++) g_free(values[index]);
|
|
g_clear_pointer(&stdout_raw, g_bytes_unref);
|
|
g_clear_pointer(&stderr_raw, g_bytes_unref);
|
|
return record;
|
|
}
|
|
|
|
OsintExecutionRecord *osint_execution_dao_find_by_identifier(
|
|
OsintExecutionDao *dao, const char *identifier, GError **error
|
|
)
|
|
{
|
|
DatabaseStatement *statement = NULL;
|
|
OsintExecutionRecord *record = NULL;
|
|
if (dao == NULL || identifier == NULL) return NULL;
|
|
statement = database_statement_prepare(dao->database, find_sql);
|
|
if (statement != NULL && database_statement_bind_text(statement, 1, identifier) &&
|
|
database_statement_step(statement) == DATABASE_STATEMENT_STEP_ROW)
|
|
record = osint_execution_dao_read_record(statement, error);
|
|
if (record == NULL && error != NULL && *error == NULL)
|
|
osint_execution_dao_set_error(dao, error,
|
|
"Impossible de lire l'exécution OSINT");
|
|
database_statement_finalize(statement);
|
|
return record;
|
|
}
|
|
|
|
GPtrArray *osint_execution_dao_list_by_selection(
|
|
OsintExecutionDao *dao, const char *selection_kind,
|
|
const char *selection_identifier, GError **error
|
|
)
|
|
{
|
|
DatabaseStatement *statement = NULL;
|
|
GPtrArray *records = NULL;
|
|
DatabaseStatementStepResult step = DATABASE_STATEMENT_STEP_ERROR;
|
|
if (dao == NULL || selection_identifier == NULL ||
|
|
(g_strcmp0(selection_kind, "entity") != 0 &&
|
|
g_strcmp0(selection_kind, "relation") != 0)) return NULL;
|
|
statement = database_statement_prepare(dao->database, list_by_selection_sql);
|
|
records = g_ptr_array_new_with_free_func(
|
|
(GDestroyNotify) osint_execution_record_free);
|
|
if (statement == NULL || records == NULL ||
|
|
!database_statement_bind_text(statement, 1, selection_kind) ||
|
|
!database_statement_bind_text(statement, 2, selection_identifier) ||
|
|
!database_statement_bind_text(statement, 3, selection_kind) ||
|
|
!database_statement_bind_text(statement, 4, selection_identifier) ||
|
|
!database_statement_bind_text(statement, 5, selection_kind) ||
|
|
!database_statement_bind_text(statement, 6, selection_identifier))
|
|
goto failure;
|
|
while ((step = database_statement_step(statement)) == DATABASE_STATEMENT_STEP_ROW)
|
|
{
|
|
OsintExecutionRecord *record = osint_execution_dao_read_record(statement, error);
|
|
if (record == NULL) goto failure;
|
|
g_ptr_array_add(records, record);
|
|
}
|
|
if (step != DATABASE_STATEMENT_STEP_DONE) goto failure;
|
|
database_statement_finalize(statement);
|
|
return records;
|
|
failure:
|
|
osint_execution_dao_set_error(dao, error,
|
|
"Impossible de lister l'historique OSINT");
|
|
database_statement_finalize(statement);
|
|
g_clear_pointer(&records, g_ptr_array_unref);
|
|
return NULL;
|
|
}
|
|
|
|
GPtrArray *osint_execution_dao_list_linked_objects(
|
|
OsintExecutionDao *dao, const char *execution_identifier, GError **error
|
|
)
|
|
{
|
|
DatabaseStatement *statement = NULL;
|
|
GPtrArray *objects = NULL;
|
|
DatabaseStatementStepResult step = DATABASE_STATEMENT_STEP_ERROR;
|
|
if (dao == NULL || execution_identifier == NULL) return NULL;
|
|
statement = database_statement_prepare(dao->database, list_linked_objects_sql);
|
|
objects = g_ptr_array_new_with_free_func(g_free);
|
|
if (statement == NULL || objects == NULL ||
|
|
!database_statement_bind_text(statement, 1, execution_identifier) ||
|
|
!database_statement_bind_text(statement, 2, execution_identifier))
|
|
goto failure;
|
|
while ((step = database_statement_step(statement)) == DATABASE_STATEMENT_STEP_ROW)
|
|
{
|
|
char *kind = NULL; char *identifier = NULL; char *disposition = NULL;
|
|
char *description = NULL;
|
|
if (!database_statement_column_text(statement, 0, &kind) ||
|
|
!database_statement_column_text(statement, 1, &identifier) ||
|
|
!database_statement_column_text(statement, 2, &disposition))
|
|
{ g_free(kind); g_free(identifier); g_free(disposition); goto failure; }
|
|
description = g_strdup_printf("%s %s — %s", kind, identifier,
|
|
g_strcmp0(disposition, "created") == 0 ? "créée" : "réutilisée");
|
|
g_free(kind); g_free(identifier); g_free(disposition);
|
|
if (description == NULL) goto failure;
|
|
g_ptr_array_add(objects, description);
|
|
}
|
|
if (step != DATABASE_STATEMENT_STEP_DONE) goto failure;
|
|
database_statement_finalize(statement);
|
|
return objects;
|
|
failure:
|
|
osint_execution_dao_set_error(dao, error,
|
|
"Impossible de lister les objets liés à l'exécution OSINT");
|
|
database_statement_finalize(statement);
|
|
g_clear_pointer(&objects, g_ptr_array_unref);
|
|
return NULL;
|
|
}
|
|
|
|
static gboolean osint_execution_dao_link(
|
|
OsintExecutionDao *dao, const char *table, const char *object_column,
|
|
const char *execution_identifier, const char *object_identifier,
|
|
const char *disposition, GError **error
|
|
)
|
|
{
|
|
char *sql = NULL;
|
|
DatabaseStatement *statement = NULL;
|
|
gboolean success = FALSE;
|
|
if (dao == NULL || execution_identifier == NULL || object_identifier == NULL ||
|
|
(g_strcmp0(disposition, "created") != 0 &&
|
|
g_strcmp0(disposition, "reused") != 0)) return FALSE;
|
|
sql = g_strdup_printf(
|
|
"INSERT OR IGNORE INTO %s(execution_id,%s,disposition) VALUES(?,?,?);",
|
|
table, object_column);
|
|
statement = database_statement_prepare(dao->database, sql);
|
|
success = statement != NULL &&
|
|
database_statement_bind_text(statement, 1, execution_identifier) &&
|
|
database_statement_bind_text(statement, 2, object_identifier) &&
|
|
database_statement_bind_text(statement, 3, disposition) &&
|
|
database_statement_step(statement) == DATABASE_STATEMENT_STEP_DONE;
|
|
if (!success) osint_execution_dao_set_error(dao, error,
|
|
"Impossible de lier la provenance OSINT");
|
|
database_statement_finalize(statement); g_free(sql); return success;
|
|
}
|
|
|
|
gboolean osint_execution_dao_link_entity(
|
|
OsintExecutionDao *dao, const char *execution_identifier,
|
|
const char *entity_identifier, const char *disposition, GError **error)
|
|
{ return osint_execution_dao_link(dao, "osint_execution_entities", "entity_id",
|
|
execution_identifier, entity_identifier, disposition, error); }
|
|
gboolean osint_execution_dao_link_relation(
|
|
OsintExecutionDao *dao, const char *execution_identifier,
|
|
const char *relation_identifier, const char *disposition, GError **error)
|
|
{ return osint_execution_dao_link(dao, "osint_execution_relations", "relation_id",
|
|
execution_identifier, relation_identifier, disposition, error); }
|