feat: add asynchronous evidence integrity task
This commit is contained in:
parent
a4765e8de2
commit
5ad959315a
10 changed files with 4302 additions and 3 deletions
34
Makefile
34
Makefile
|
|
@ -37,6 +37,10 @@ EVIDENCE_IMPORT_DIALOG_TEST_CFLAGS := \
|
||||||
EVIDENCE_IMPORT_DIALOG_TEST_LDFLAGS := \
|
EVIDENCE_IMPORT_DIALOG_TEST_LDFLAGS := \
|
||||||
$(shell $(PKG_CONFIG) --libs gtk4)
|
$(shell $(PKG_CONFIG) --libs gtk4)
|
||||||
|
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_TEST_CFLAGS := \
|
||||||
|
$(TEST_CFLAGS) \
|
||||||
|
-Wpedantic
|
||||||
|
|
||||||
SRC := $(shell find src -name "*.c")
|
SRC := $(shell find src -name "*.c")
|
||||||
|
|
||||||
OBJ := $(SRC:.c=.o)
|
OBJ := $(SRC:.c=.o)
|
||||||
|
|
@ -64,6 +68,7 @@ TEST_TOOL_TASK := tests/test_tool_task
|
||||||
TEST_TOOL_CATALOG := tests/test_tool_catalog
|
TEST_TOOL_CATALOG := tests/test_tool_catalog
|
||||||
TEST_TOOL_INITIALIZER := tests/test_tool_initializer
|
TEST_TOOL_INITIALIZER := tests/test_tool_initializer
|
||||||
TEST_FILE_HASH := tests/test_file_hash
|
TEST_FILE_HASH := tests/test_file_hash
|
||||||
|
TEST_EVIDENCE_INTEGRITY_VERIFIER := tests/test_evidence_integrity_verifier
|
||||||
TEST_EVIDENCE_COPY := tests/test_evidence_copy
|
TEST_EVIDENCE_COPY := tests/test_evidence_copy
|
||||||
TEST_EVIDENCE_IMPORTER := tests/test_evidence_importer
|
TEST_EVIDENCE_IMPORTER := tests/test_evidence_importer
|
||||||
TEST_EVIDENCE_IMPORT_TASK := tests/test_evidence_import_task
|
TEST_EVIDENCE_IMPORT_TASK := tests/test_evidence_import_task
|
||||||
|
|
@ -74,6 +79,7 @@ TEST_EVIDENCE_LIST_ITEM := tests/test_evidence_list_item
|
||||||
TEST_EVIDENCE_LIST_MODEL := tests/test_evidence_list_model
|
TEST_EVIDENCE_LIST_MODEL := tests/test_evidence_list_model
|
||||||
TEST_EVIDENCE_CATEGORY_ITEM := tests/test_evidence_category_item
|
TEST_EVIDENCE_CATEGORY_ITEM := tests/test_evidence_category_item
|
||||||
TEST_EVIDENCE_CATEGORY_MODEL := tests/test_evidence_category_model
|
TEST_EVIDENCE_CATEGORY_MODEL := tests/test_evidence_category_model
|
||||||
|
TEST_EVIDENCE_INTEGRITY_TASK := tests/test_evidence_integrity_task
|
||||||
|
|
||||||
all: $(TARGET)
|
all: $(TARGET)
|
||||||
|
|
||||||
|
|
@ -254,6 +260,13 @@ $(TEST_FILE_HASH): \
|
||||||
-DFILE_HASH_ENABLE_TEST_HOOKS \
|
-DFILE_HASH_ENABLE_TEST_HOOKS \
|
||||||
$^ -o $@ $(TEST_LDFLAGS)
|
$^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
|
$(TEST_EVIDENCE_INTEGRITY_VERIFIER): \
|
||||||
|
tests/test_evidence_integrity_verifier.c \
|
||||||
|
src/core/evidence_integrity_verifier.c \
|
||||||
|
src/core/file_hash.c
|
||||||
|
$(CC) $(EVIDENCE_INTEGRITY_VERIFIER_TEST_CFLAGS) \
|
||||||
|
$^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
$(TEST_EVIDENCE_COPY): \
|
$(TEST_EVIDENCE_COPY): \
|
||||||
tests/test_evidence_copy.c \
|
tests/test_evidence_copy.c \
|
||||||
src/core/evidence_copy.c \
|
src/core/evidence_copy.c \
|
||||||
|
|
@ -336,6 +349,17 @@ $(TEST_EVIDENCE_CATEGORY_MODEL): \
|
||||||
src/models/evidence_record.c
|
src/models/evidence_record.c
|
||||||
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
$(CC) $(TEST_CFLAGS) $^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
|
$(TEST_EVIDENCE_INTEGRITY_TASK): \
|
||||||
|
tests/test_evidence_integrity_task.c \
|
||||||
|
src/core/evidence_integrity_task.c \
|
||||||
|
src/core/evidence_integrity_verifier.c \
|
||||||
|
src/core/file_hash.c \
|
||||||
|
src/core/background_task.c \
|
||||||
|
src/core/task_manager.c
|
||||||
|
$(CC) $(TEST_CFLAGS) \
|
||||||
|
-DFILE_HASH_ENABLE_TEST_HOOKS \
|
||||||
|
$^ -o $@ $(TEST_LDFLAGS)
|
||||||
|
|
||||||
test: \
|
test: \
|
||||||
$(TEST_NODE) \
|
$(TEST_NODE) \
|
||||||
$(TEST_TREE_MODEL) \
|
$(TEST_TREE_MODEL) \
|
||||||
|
|
@ -364,10 +388,12 @@ test: \
|
||||||
$(TEST_TOOL_CATALOG) \
|
$(TEST_TOOL_CATALOG) \
|
||||||
$(TEST_TOOL_INITIALIZER) \
|
$(TEST_TOOL_INITIALIZER) \
|
||||||
$(TEST_FILE_HASH) \
|
$(TEST_FILE_HASH) \
|
||||||
|
$(TEST_EVIDENCE_INTEGRITY_VERIFIER) \
|
||||||
$(TEST_EVIDENCE_COPY) \
|
$(TEST_EVIDENCE_COPY) \
|
||||||
$(TEST_EVIDENCE_IMPORTER) \
|
$(TEST_EVIDENCE_IMPORTER) \
|
||||||
$(TEST_EVIDENCE_IMPORT_TASK) \
|
$(TEST_EVIDENCE_IMPORT_TASK) \
|
||||||
$(TEST_EVIDENCE_IMPORT_DIALOG)
|
$(TEST_EVIDENCE_IMPORT_DIALOG) \
|
||||||
|
$(TEST_EVIDENCE_INTEGRITY_TASK)
|
||||||
@echo "Exécution des tests..."
|
@echo "Exécution des tests..."
|
||||||
@./$(TEST_NODE)
|
@./$(TEST_NODE)
|
||||||
@./$(TEST_TREE_MODEL)
|
@./$(TEST_TREE_MODEL)
|
||||||
|
|
@ -396,10 +422,12 @@ test: \
|
||||||
@$(TEST_TOOL_CATALOG)
|
@$(TEST_TOOL_CATALOG)
|
||||||
@$(TEST_TOOL_INITIALIZER)
|
@$(TEST_TOOL_INITIALIZER)
|
||||||
@$(TEST_FILE_HASH)
|
@$(TEST_FILE_HASH)
|
||||||
|
@$(TEST_EVIDENCE_INTEGRITY_VERIFIER)
|
||||||
@$(TEST_EVIDENCE_COPY)
|
@$(TEST_EVIDENCE_COPY)
|
||||||
@$(TEST_EVIDENCE_IMPORTER)
|
@$(TEST_EVIDENCE_IMPORTER)
|
||||||
@$(TEST_EVIDENCE_IMPORT_TASK)
|
@$(TEST_EVIDENCE_IMPORT_TASK)
|
||||||
@$(TEST_EVIDENCE_IMPORT_DIALOG)
|
@$(TEST_EVIDENCE_IMPORT_DIALOG)
|
||||||
|
@$(TEST_EVIDENCE_INTEGRITY_TASK)
|
||||||
@echo "Tous les tests sont valides."
|
@echo "Tous les tests sont valides."
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
|
|
@ -437,10 +465,12 @@ clean:
|
||||||
$(TEST_TOOL_CATALOG) \
|
$(TEST_TOOL_CATALOG) \
|
||||||
$(TEST_TOOL_INITIALIZER) \
|
$(TEST_TOOL_INITIALIZER) \
|
||||||
$(TEST_FILE_HASH) \
|
$(TEST_FILE_HASH) \
|
||||||
|
$(TEST_EVIDENCE_INTEGRITY_VERIFIER) \
|
||||||
$(TEST_EVIDENCE_COPY) \
|
$(TEST_EVIDENCE_COPY) \
|
||||||
$(TEST_EVIDENCE_IMPORTER) \
|
$(TEST_EVIDENCE_IMPORTER) \
|
||||||
$(TEST_EVIDENCE_IMPORT_TASK) \
|
$(TEST_EVIDENCE_IMPORT_TASK) \
|
||||||
$(TEST_EVIDENCE_IMPORT_DIALOG)
|
$(TEST_EVIDENCE_IMPORT_DIALOG) \
|
||||||
|
$(TEST_EVIDENCE_INTEGRITY_TASK)
|
||||||
|
|
||||||
|
|
||||||
.PHONY: clean run test
|
.PHONY: clean run test
|
||||||
|
|
|
||||||
80
include/core/evidence_integrity_task.h
Normal file
80
include/core/evidence_integrity_task.h
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file evidence_integrity_task.h
|
||||||
|
* @brief Tâche asynchrone de vérification d'intégrité d'une preuve.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_EVIDENCE_INTEGRITY_TASK_H
|
||||||
|
#define LABFY_INVESTIGATION_EVIDENCE_INTEGRITY_TASK_H
|
||||||
|
|
||||||
|
#include "core/background_task.h"
|
||||||
|
#include "core/task_manager.h"
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Codes d'erreur propres à la tâche de vérification.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_INVALID_ARGUMENT,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_VERIFY
|
||||||
|
} EvidenceIntegrityTaskError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Domaine d'erreur du module.
|
||||||
|
*/
|
||||||
|
#define EVIDENCE_INTEGRITY_TASK_ERROR \
|
||||||
|
evidence_integrity_task_error_quark()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Paramètres nécessaires à une vérification d'intégrité.
|
||||||
|
*
|
||||||
|
* Toutes les chaînes sont copiées avant le démarrage du worker.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const char *investigation_root_path;
|
||||||
|
const char *relative_path;
|
||||||
|
const char *expected_sha256;
|
||||||
|
} EvidenceIntegrityTaskRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le domaine d'erreur du module.
|
||||||
|
*/
|
||||||
|
GQuark evidence_integrity_task_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée, enregistre et démarre une tâche de vérification.
|
||||||
|
*
|
||||||
|
* Le résultat final est un EvidenceIntegrityVerificationResult emprunté
|
||||||
|
* à la BackgroundTask. Il reste valide tant que la tâche existe.
|
||||||
|
*
|
||||||
|
* En cas de succès :
|
||||||
|
*
|
||||||
|
* - TaskManager conserve une référence ;
|
||||||
|
* - le worker conserve une référence pendant son exécution ;
|
||||||
|
* - l'appelant reçoit sa référence initiale et doit la libérer avec
|
||||||
|
* background_task_unref().
|
||||||
|
*
|
||||||
|
* completion_data est transféré à BackgroundTask uniquement si le
|
||||||
|
* démarrage réussit. En cas d'échec, l'appelant en reste propriétaire.
|
||||||
|
*
|
||||||
|
* @param task_manager Gestionnaire recevant la tâche.
|
||||||
|
* @param request Paramètres de la vérification.
|
||||||
|
* @param completion_callback Callback final facultatif.
|
||||||
|
* @param completion_data Données du callback final.
|
||||||
|
* @param completion_data_destroy Destructeur de completion_data.
|
||||||
|
* @param error Emplacement facultatif recevant une erreur.
|
||||||
|
*
|
||||||
|
* @return Nouvelle tâche démarrée, ou NULL.
|
||||||
|
*/
|
||||||
|
BackgroundTask *evidence_integrity_task_start(
|
||||||
|
TaskManager *task_manager,
|
||||||
|
const EvidenceIntegrityTaskRequest *request,
|
||||||
|
BackgroundTaskCompletionCallback completion_callback,
|
||||||
|
gpointer completion_data,
|
||||||
|
GDestroyNotify completion_data_destroy,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
115
include/core/evidence_integrity_verifier.h
Normal file
115
include/core/evidence_integrity_verifier.h
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file evidence_integrity_verifier.h
|
||||||
|
* @brief Vérification de l'intégrité d'une preuve numérique.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef LABFY_INVESTIGATION_EVIDENCE_INTEGRITY_VERIFIER_H
|
||||||
|
#define LABFY_INVESTIGATION_EVIDENCE_INTEGRITY_VERIFIER_H
|
||||||
|
|
||||||
|
#include "models/evidence_record.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Erreurs techniques du vérificateur.
|
||||||
|
*/
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_INVALID_ARGUMENT,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_ROOT,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_CANCELLED,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_MEMORY
|
||||||
|
} EvidenceIntegrityVerifierError;
|
||||||
|
|
||||||
|
#define EVIDENCE_INTEGRITY_VERIFIER_ERROR \
|
||||||
|
evidence_integrity_verifier_error_quark()
|
||||||
|
|
||||||
|
GQuark evidence_integrity_verifier_error_quark(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Résultat opaque d'une vérification.
|
||||||
|
*/
|
||||||
|
typedef struct EvidenceIntegrityVerificationResult
|
||||||
|
EvidenceIntegrityVerificationResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie une preuve à partir de son chemin relatif.
|
||||||
|
*
|
||||||
|
* Le chemin est résolu sous investigation_root_path.
|
||||||
|
* Les chemins absolus, les composants "." et ".." et les liens
|
||||||
|
* symboliques sont refusés.
|
||||||
|
*
|
||||||
|
* Les résultats MISSING et ERROR sont des résultats métier normaux :
|
||||||
|
* la fonction retourne alors un objet résultat sans remplir GError.
|
||||||
|
*
|
||||||
|
* Une erreur technique d'argument, de racine, de mémoire ou une
|
||||||
|
* annulation retourne NULL.
|
||||||
|
*
|
||||||
|
* @param investigation_root_path Racine de l'enquête.
|
||||||
|
* @param relative_path Chemin relatif enregistré dans SQLite.
|
||||||
|
* @param expected_sha256 Empreinte enregistrée.
|
||||||
|
* @param cancellable Objet d'annulation facultatif.
|
||||||
|
* @param error Adresse recevant une erreur technique.
|
||||||
|
*
|
||||||
|
* @return Nouveau résultat possédé par l'appelant, ou NULL.
|
||||||
|
*/
|
||||||
|
EvidenceIntegrityVerificationResult *
|
||||||
|
evidence_integrity_verifier_verify(
|
||||||
|
const char *investigation_root_path,
|
||||||
|
const char *relative_path,
|
||||||
|
const char *expected_sha256,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le statut calculé.
|
||||||
|
*/
|
||||||
|
EvidenceIntegrityStatus
|
||||||
|
evidence_integrity_verification_result_get_status(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne l'empreinte recalculée.
|
||||||
|
*
|
||||||
|
* La chaîne est empruntée. Elle vaut NULL lorsque le fichier
|
||||||
|
* n'a pas pu être lu.
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
evidence_integrity_verification_result_get_computed_sha256(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne la taille effectivement lue.
|
||||||
|
*/
|
||||||
|
guint64 evidence_integrity_verification_result_get_size_bytes(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne un diagnostic technique facultatif.
|
||||||
|
*
|
||||||
|
* La chaîne est empruntée.
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
evidence_integrity_verification_result_get_diagnostic(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère un résultat.
|
||||||
|
*
|
||||||
|
* Cette fonction accepte NULL.
|
||||||
|
*/
|
||||||
|
void evidence_integrity_verification_result_free(
|
||||||
|
EvidenceIntegrityVerificationResult *result
|
||||||
|
);
|
||||||
|
|
||||||
|
G_END_DECLS
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
EVIDENCE_DAO_ERROR_INVALID_ARGUMENT,
|
EVIDENCE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
EVIDENCE_DAO_ERROR_NOT_FOUND,
|
||||||
EVIDENCE_DAO_ERROR_MEMORY,
|
EVIDENCE_DAO_ERROR_MEMORY,
|
||||||
EVIDENCE_DAO_ERROR_PREPARE,
|
EVIDENCE_DAO_ERROR_PREPARE,
|
||||||
EVIDENCE_DAO_ERROR_BIND,
|
EVIDENCE_DAO_ERROR_BIND,
|
||||||
|
|
@ -124,6 +125,25 @@ GPtrArray *evidence_dao_list_all(
|
||||||
GError **error
|
GError **error
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Met à jour le statut d'intégrité d'une preuve.
|
||||||
|
*
|
||||||
|
* Seule la colonne du statut d'intégrité est modifiée.
|
||||||
|
*
|
||||||
|
* @param evidence_dao DAO valide.
|
||||||
|
* @param identifier Identifiant UUID de la preuve.
|
||||||
|
* @param integrity_status Nouveau statut d'intégrité.
|
||||||
|
* @param error Adresse recevant une éventuelle erreur.
|
||||||
|
*
|
||||||
|
* @return TRUE si la mise à jour réussit, sinon FALSE.
|
||||||
|
*/
|
||||||
|
gboolean evidence_dao_update_integrity_status(
|
||||||
|
EvidenceDao *evidence_dao,
|
||||||
|
const char *identifier,
|
||||||
|
EvidenceIntegrityStatus integrity_status,
|
||||||
|
GError **error
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Compte les preuves persistées.
|
* @brief Compte les preuves persistées.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
522
src/core/evidence_integrity_task.c
Normal file
522
src/core/evidence_integrity_task.c
Normal file
|
|
@ -0,0 +1,522 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file evidence_integrity_task.c
|
||||||
|
* @brief Exécution asynchrone de la vérification d'intégrité.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#include "core/evidence_integrity_task.h"
|
||||||
|
|
||||||
|
#include "core/evidence_integrity_verifier.h"
|
||||||
|
|
||||||
|
#include <gio/gio.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copie privée des paramètres nécessaires au worker.
|
||||||
|
*/
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char *investigation_root_path;
|
||||||
|
char *relative_path;
|
||||||
|
char *expected_sha256;
|
||||||
|
} EvidenceIntegrityTaskData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère les données privées du worker.
|
||||||
|
*/
|
||||||
|
static void evidence_integrity_task_data_free(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceIntegrityTaskData *task_data =
|
||||||
|
user_data;
|
||||||
|
|
||||||
|
if (task_data == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->expected_sha256
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->relative_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data->investigation_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie les paramètres obligatoires.
|
||||||
|
*/
|
||||||
|
static gboolean evidence_integrity_task_request_is_valid(
|
||||||
|
const EvidenceIntegrityTaskRequest *request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (request == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->investigation_root_path == NULL ||
|
||||||
|
request->investigation_root_path[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->relative_path == NULL ||
|
||||||
|
request->relative_path[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->expected_sha256 == NULL ||
|
||||||
|
request->expected_sha256[0] == '\0')
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copie les paramètres avant le lancement du thread.
|
||||||
|
*/
|
||||||
|
static EvidenceIntegrityTaskData *
|
||||||
|
evidence_integrity_task_data_new(
|
||||||
|
const EvidenceIntegrityTaskRequest *request
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceIntegrityTaskData *task_data =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (!evidence_integrity_task_request_is_valid(
|
||||||
|
request
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_data =
|
||||||
|
g_try_new0(
|
||||||
|
EvidenceIntegrityTaskData,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task_data == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_data->investigation_root_path =
|
||||||
|
g_strdup(
|
||||||
|
request->investigation_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->relative_path =
|
||||||
|
g_strdup(
|
||||||
|
request->relative_path
|
||||||
|
);
|
||||||
|
|
||||||
|
task_data->expected_sha256 =
|
||||||
|
g_strdup(
|
||||||
|
request->expected_sha256
|
||||||
|
);
|
||||||
|
|
||||||
|
return task_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Libère le résultat de vérification d'une tâche.
|
||||||
|
*/
|
||||||
|
static void evidence_integrity_task_result_free(
|
||||||
|
gpointer user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
evidence_integrity_verification_result_free(
|
||||||
|
user_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Traduit une annulation métier en annulation GIO.
|
||||||
|
*
|
||||||
|
* BackgroundTask reconnaît l'état CANCELLED uniquement avec :
|
||||||
|
*
|
||||||
|
* G_IO_ERROR / G_IO_ERROR_CANCELLED.
|
||||||
|
*/
|
||||||
|
static void evidence_integrity_task_propagate_verify_error(
|
||||||
|
GError **error,
|
||||||
|
GError *verify_error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (verify_error != NULL &&
|
||||||
|
g_error_matches(
|
||||||
|
verify_error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_CANCELLED
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_clear_error(
|
||||||
|
&verify_error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
G_IO_ERROR,
|
||||||
|
G_IO_ERROR_CANCELLED,
|
||||||
|
"La vérification d'intégrité a été annulée."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verify_error != NULL)
|
||||||
|
{
|
||||||
|
g_propagate_error(
|
||||||
|
error,
|
||||||
|
verify_error
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_VERIFY,
|
||||||
|
"La vérification a échoué sans fournir d'erreur."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retourne le message final correspondant au statut métier.
|
||||||
|
*/
|
||||||
|
static const char *evidence_integrity_task_get_status_message(
|
||||||
|
EvidenceIntegrityStatus integrity_status
|
||||||
|
)
|
||||||
|
{
|
||||||
|
switch (integrity_status)
|
||||||
|
{
|
||||||
|
case EVIDENCE_INTEGRITY_STATUS_VALID:
|
||||||
|
return "Intégrité vérifiée : fichier intact";
|
||||||
|
|
||||||
|
case EVIDENCE_INTEGRITY_STATUS_MODIFIED:
|
||||||
|
return "Intégrité compromise : empreinte différente";
|
||||||
|
|
||||||
|
case EVIDENCE_INTEGRITY_STATUS_MISSING:
|
||||||
|
return "Vérification terminée : fichier absent";
|
||||||
|
|
||||||
|
case EVIDENCE_INTEGRITY_STATUS_ERROR:
|
||||||
|
return "Vérification terminée : erreur de lecture";
|
||||||
|
|
||||||
|
case EVIDENCE_INTEGRITY_STATUS_UNKNOWN:
|
||||||
|
default:
|
||||||
|
return "Vérification terminée";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Exécute la vérification dans le thread secondaire.
|
||||||
|
*/
|
||||||
|
static gboolean evidence_integrity_task_worker(
|
||||||
|
BackgroundTask *task,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
gpointer worker_data,
|
||||||
|
gpointer *result,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceIntegrityTaskData *task_data =
|
||||||
|
worker_data;
|
||||||
|
|
||||||
|
EvidenceIntegrityVerificationResult *verification_result =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
EvidenceIntegrityStatus integrity_status =
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_UNKNOWN;
|
||||||
|
|
||||||
|
GError *verify_error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (task == NULL ||
|
||||||
|
cancellable == NULL ||
|
||||||
|
task_data == NULL ||
|
||||||
|
result == NULL ||
|
||||||
|
error == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*result =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (g_cancellable_set_error_if_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
background_task_report_progress(
|
||||||
|
task,
|
||||||
|
0.10,
|
||||||
|
"Préparation de la vérification"
|
||||||
|
);
|
||||||
|
|
||||||
|
verification_result =
|
||||||
|
evidence_integrity_verifier_verify(
|
||||||
|
task_data->investigation_root_path,
|
||||||
|
task_data->relative_path,
|
||||||
|
task_data->expected_sha256,
|
||||||
|
cancellable,
|
||||||
|
&verify_error
|
||||||
|
);
|
||||||
|
|
||||||
|
if (verification_result == NULL)
|
||||||
|
{
|
||||||
|
evidence_integrity_task_propagate_verify_error(
|
||||||
|
error,
|
||||||
|
verify_error
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
integrity_status =
|
||||||
|
evidence_integrity_verification_result_get_status(
|
||||||
|
verification_result
|
||||||
|
);
|
||||||
|
|
||||||
|
background_task_report_progress(
|
||||||
|
task,
|
||||||
|
1.0,
|
||||||
|
evidence_integrity_task_get_status_message(
|
||||||
|
integrity_status
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
*result =
|
||||||
|
verification_result;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Transmet une erreur secondaire au code appelant.
|
||||||
|
*/
|
||||||
|
static void evidence_integrity_task_propagate_start_error(
|
||||||
|
GError **error,
|
||||||
|
GError *start_error,
|
||||||
|
const char *prefix
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (start_error == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_VERIFY,
|
||||||
|
"La tâche de vérification n'a pas pu être démarrée."
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error != NULL)
|
||||||
|
{
|
||||||
|
g_propagate_prefixed_error(
|
||||||
|
error,
|
||||||
|
start_error,
|
||||||
|
"%s",
|
||||||
|
prefix
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&start_error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark evidence_integrity_task_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string(
|
||||||
|
"evidence-integrity-task-error-quark"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
BackgroundTask *evidence_integrity_task_start(
|
||||||
|
TaskManager *task_manager,
|
||||||
|
const EvidenceIntegrityTaskRequest *request,
|
||||||
|
BackgroundTaskCompletionCallback completion_callback,
|
||||||
|
gpointer completion_data,
|
||||||
|
GDestroyNotify completion_data_destroy,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceIntegrityTaskData *task_data =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
BackgroundTask *task =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *evidence_name =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *task_title =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *start_error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task_manager == NULL ||
|
||||||
|
!evidence_integrity_task_request_is_valid(
|
||||||
|
request
|
||||||
|
))
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Les paramètres de la tâche de vérification sont invalides."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
task_data =
|
||||||
|
evidence_integrity_task_data_new(
|
||||||
|
request
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task_data == NULL)
|
||||||
|
{
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_VERIFY,
|
||||||
|
"Impossible d'allouer les données de la tâche "
|
||||||
|
"de vérification."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
evidence_name =
|
||||||
|
g_path_get_basename(
|
||||||
|
request->relative_path
|
||||||
|
);
|
||||||
|
|
||||||
|
task_title =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Vérifier l'intégrité : %s",
|
||||||
|
evidence_name
|
||||||
|
);
|
||||||
|
|
||||||
|
task =
|
||||||
|
background_task_new(
|
||||||
|
task_title
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
task_title
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
evidence_name
|
||||||
|
);
|
||||||
|
|
||||||
|
if (task == NULL)
|
||||||
|
{
|
||||||
|
evidence_integrity_task_data_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_TASK_ERROR_VERIFY,
|
||||||
|
"Impossible de créer la tâche de vérification."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!task_manager_add(
|
||||||
|
task_manager,
|
||||||
|
task,
|
||||||
|
&start_error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
evidence_integrity_task_data_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_integrity_task_propagate_start_error(
|
||||||
|
error,
|
||||||
|
start_error,
|
||||||
|
"Impossible d'ajouter la tâche : "
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!background_task_start(
|
||||||
|
task,
|
||||||
|
evidence_integrity_task_worker,
|
||||||
|
task_data,
|
||||||
|
evidence_integrity_task_data_free,
|
||||||
|
evidence_integrity_task_result_free,
|
||||||
|
completion_callback,
|
||||||
|
completion_data,
|
||||||
|
completion_data_destroy,
|
||||||
|
&start_error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* background_task_start() n'a pas pris possession
|
||||||
|
* de task_data ni de completion_data en cas d'échec.
|
||||||
|
*/
|
||||||
|
evidence_integrity_task_data_free(
|
||||||
|
task_data
|
||||||
|
);
|
||||||
|
|
||||||
|
task_manager_remove(
|
||||||
|
task_manager,
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
background_task_unref(
|
||||||
|
task
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_integrity_task_propagate_start_error(
|
||||||
|
error,
|
||||||
|
start_error,
|
||||||
|
"Impossible de démarrer la tâche : "
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
666
src/core/evidence_integrity_verifier.c
Normal file
666
src/core/evidence_integrity_verifier.c
Normal file
|
|
@ -0,0 +1,666 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* @file evidence_integrity_verifier.c
|
||||||
|
* @brief Vérification de l'intégrité d'une preuve numérique.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#define _XOPEN_SOURCE 700
|
||||||
|
|
||||||
|
#include "core/evidence_integrity_verifier.h"
|
||||||
|
|
||||||
|
#include "core/file_hash.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Résultat interne d'une vérification.
|
||||||
|
*/
|
||||||
|
struct EvidenceIntegrityVerificationResult
|
||||||
|
{
|
||||||
|
EvidenceIntegrityStatus status;
|
||||||
|
|
||||||
|
char *computed_sha256;
|
||||||
|
guint64 size_bytes;
|
||||||
|
|
||||||
|
char *diagnostic;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enregistre une erreur technique.
|
||||||
|
*/
|
||||||
|
static void evidence_integrity_verifier_set_error_literal(
|
||||||
|
GError **error,
|
||||||
|
EvidenceIntegrityVerifierError error_code,
|
||||||
|
const char *message
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (error == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR,
|
||||||
|
error_code,
|
||||||
|
message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie qu'une empreinte SHA-256 est canonique.
|
||||||
|
*/
|
||||||
|
static gboolean evidence_integrity_verifier_sha256_is_valid(
|
||||||
|
const char *sha256
|
||||||
|
)
|
||||||
|
{
|
||||||
|
gsize character_index = 0;
|
||||||
|
|
||||||
|
if (sha256 == NULL ||
|
||||||
|
strlen(sha256) != 64U)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (character_index = 0;
|
||||||
|
character_index < 64U;
|
||||||
|
character_index++)
|
||||||
|
{
|
||||||
|
if (!g_ascii_isdigit(sha256[character_index]) &&
|
||||||
|
(
|
||||||
|
sha256[character_index] < 'a' ||
|
||||||
|
sha256[character_index] > 'f'
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée un résultat métier.
|
||||||
|
*/
|
||||||
|
static EvidenceIntegrityVerificationResult *
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EvidenceIntegrityStatus status,
|
||||||
|
const char *computed_sha256,
|
||||||
|
guint64 size_bytes,
|
||||||
|
const char *diagnostic,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceIntegrityVerificationResult *result =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
result =
|
||||||
|
g_try_new0(
|
||||||
|
EvidenceIntegrityVerificationResult,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_MEMORY,
|
||||||
|
"Impossible d'allouer le résultat de la vérification."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
result->status =
|
||||||
|
status;
|
||||||
|
|
||||||
|
result->size_bytes =
|
||||||
|
size_bytes;
|
||||||
|
|
||||||
|
if (computed_sha256 != NULL)
|
||||||
|
{
|
||||||
|
result->computed_sha256 =
|
||||||
|
g_strdup(
|
||||||
|
computed_sha256
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diagnostic != NULL)
|
||||||
|
{
|
||||||
|
result->diagnostic =
|
||||||
|
g_strdup(
|
||||||
|
diagnostic
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie si une annulation a été demandée.
|
||||||
|
*/
|
||||||
|
static gboolean evidence_integrity_verifier_is_cancelled(
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (cancellable == NULL ||
|
||||||
|
!g_cancellable_is_cancelled(
|
||||||
|
cancellable
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_CANCELLED,
|
||||||
|
"La vérification d'intégrité a été annulée."
|
||||||
|
);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark evidence_integrity_verifier_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string(
|
||||||
|
"evidence-integrity-verifier-error-quark"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
EvidenceIntegrityVerificationResult *
|
||||||
|
evidence_integrity_verifier_verify(
|
||||||
|
const char *investigation_root_path,
|
||||||
|
const char *relative_path,
|
||||||
|
const char *expected_sha256,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceIntegrityVerificationResult *result =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *hash_error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char **path_components =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *resolved_root_path =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *current_path =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *next_path =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *computed_sha256 =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *diagnostic =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
struct stat root_status;
|
||||||
|
struct stat path_status;
|
||||||
|
|
||||||
|
guint64 size_bytes =
|
||||||
|
0;
|
||||||
|
|
||||||
|
guint component_index =
|
||||||
|
0;
|
||||||
|
|
||||||
|
gboolean is_last_component =
|
||||||
|
FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (investigation_root_path == NULL ||
|
||||||
|
investigation_root_path[0] == '\0' ||
|
||||||
|
relative_path == NULL ||
|
||||||
|
relative_path[0] == '\0' ||
|
||||||
|
!evidence_integrity_verifier_sha256_is_valid(
|
||||||
|
expected_sha256
|
||||||
|
))
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Les paramètres de la vérification sont invalides."
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evidence_integrity_verifier_is_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* La racine existe déjà lorsqu'une InvestigationSession est ouverte.
|
||||||
|
* realpath() résout son éventuel lien symbolique et la canonicalise.
|
||||||
|
*/
|
||||||
|
resolved_root_path =
|
||||||
|
realpath(
|
||||||
|
investigation_root_path,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resolved_root_path == NULL)
|
||||||
|
{
|
||||||
|
g_set_error(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_ROOT,
|
||||||
|
"Impossible de résoudre la racine '%s' : %s",
|
||||||
|
investigation_root_path,
|
||||||
|
g_strerror(errno)
|
||||||
|
);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat(
|
||||||
|
resolved_root_path,
|
||||||
|
&root_status
|
||||||
|
) != 0 ||
|
||||||
|
!S_ISDIR(root_status.st_mode))
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_ROOT,
|
||||||
|
"La racine de l'enquête n'est pas un dossier valide."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Un chemin SQLite doit toujours être relatif à l'enquête.
|
||||||
|
*/
|
||||||
|
if (g_path_is_absolute(
|
||||||
|
relative_path
|
||||||
|
))
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
"Le chemin enregistré est absolu.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
path_components =
|
||||||
|
g_strsplit(
|
||||||
|
relative_path,
|
||||||
|
G_DIR_SEPARATOR_S,
|
||||||
|
-1
|
||||||
|
);
|
||||||
|
|
||||||
|
if (path_components == NULL)
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_MEMORY,
|
||||||
|
"Impossible de décomposer le chemin de la preuve."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
current_path =
|
||||||
|
g_strdup(
|
||||||
|
resolved_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
if (current_path == NULL)
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_MEMORY,
|
||||||
|
"Impossible de conserver le chemin de la racine."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (component_index = 0;
|
||||||
|
path_components[component_index] != NULL;
|
||||||
|
component_index++)
|
||||||
|
{
|
||||||
|
const char *component =
|
||||||
|
path_components[component_index];
|
||||||
|
|
||||||
|
is_last_component =
|
||||||
|
path_components[component_index + 1U] == NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Le refus explicite évite toute traversée hors de la racine.
|
||||||
|
*/
|
||||||
|
if (component[0] == '\0' ||
|
||||||
|
g_strcmp0(component, ".") == 0 ||
|
||||||
|
g_strcmp0(component, "..") == 0)
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
"Le chemin contient un composant interdit.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_path =
|
||||||
|
g_build_filename(
|
||||||
|
current_path,
|
||||||
|
component,
|
||||||
|
NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
if (next_path == NULL)
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_MEMORY,
|
||||||
|
"Impossible de construire le chemin de la preuve."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
current_path
|
||||||
|
);
|
||||||
|
|
||||||
|
current_path =
|
||||||
|
next_path;
|
||||||
|
|
||||||
|
next_path =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
if (lstat(
|
||||||
|
current_path,
|
||||||
|
&path_status
|
||||||
|
) != 0)
|
||||||
|
{
|
||||||
|
if (errno == ENOENT ||
|
||||||
|
errno == ENOTDIR)
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_MISSING,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
"Le fichier de preuve est absent.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
diagnostic =
|
||||||
|
g_strdup_printf(
|
||||||
|
"Impossible d'inspecter '%s' : %s",
|
||||||
|
current_path,
|
||||||
|
g_strerror(errno)
|
||||||
|
);
|
||||||
|
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
diagnostic,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tous les liens symboliques sont refusés, y compris lorsqu'ils
|
||||||
|
* semblent rester à l'intérieur de l'enquête.
|
||||||
|
*/
|
||||||
|
if (S_ISLNK(path_status.st_mode))
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
"Le chemin de la preuve contient un lien symbolique.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_last_component &&
|
||||||
|
!S_ISDIR(path_status.st_mode))
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
"Un composant intermédiaire du chemin "
|
||||||
|
"n'est pas un dossier.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evidence_integrity_verifier_is_cancelled(
|
||||||
|
cancellable,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_hash_compute_sha256(
|
||||||
|
current_path,
|
||||||
|
cancellable,
|
||||||
|
&computed_sha256,
|
||||||
|
&size_bytes,
|
||||||
|
&hash_error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
if (g_error_matches(
|
||||||
|
hash_error,
|
||||||
|
FILE_HASH_ERROR,
|
||||||
|
FILE_HASH_ERROR_CANCELLED
|
||||||
|
))
|
||||||
|
{
|
||||||
|
evidence_integrity_verifier_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_INTEGRITY_VERIFIER_ERROR_CANCELLED,
|
||||||
|
"La vérification d'intégrité a été annulée."
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_error_matches(
|
||||||
|
hash_error,
|
||||||
|
FILE_HASH_ERROR,
|
||||||
|
FILE_HASH_ERROR_NOT_FOUND
|
||||||
|
))
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_MISSING,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
hash_error->message,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR,
|
||||||
|
NULL,
|
||||||
|
0,
|
||||||
|
hash_error != NULL
|
||||||
|
? hash_error->message
|
||||||
|
: "Le calcul SHA-256 a échoué.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(
|
||||||
|
computed_sha256,
|
||||||
|
expected_sha256
|
||||||
|
) == 0)
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID,
|
||||||
|
computed_sha256,
|
||||||
|
size_bytes,
|
||||||
|
NULL,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result =
|
||||||
|
evidence_integrity_verification_result_new(
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_MODIFIED,
|
||||||
|
computed_sha256,
|
||||||
|
size_bytes,
|
||||||
|
"L'empreinte recalculée diffère "
|
||||||
|
"de l'empreinte enregistrée.",
|
||||||
|
error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&hash_error
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
diagnostic
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
computed_sha256
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
next_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
current_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_strfreev(
|
||||||
|
path_components
|
||||||
|
);
|
||||||
|
|
||||||
|
free(
|
||||||
|
resolved_root_path
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
EvidenceIntegrityStatus
|
||||||
|
evidence_integrity_verification_result_get_status(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
return EVIDENCE_INTEGRITY_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
evidence_integrity_verification_result_get_computed_sha256(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->computed_sha256;
|
||||||
|
}
|
||||||
|
|
||||||
|
guint64 evidence_integrity_verification_result_get_size_bytes(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->size_bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *
|
||||||
|
evidence_integrity_verification_result_get_diagnostic(
|
||||||
|
const EvidenceIntegrityVerificationResult *result
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result->diagnostic;
|
||||||
|
}
|
||||||
|
|
||||||
|
void evidence_integrity_verification_result_free(
|
||||||
|
EvidenceIntegrityVerificationResult *result
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (result == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
result->diagnostic
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
result->computed_sha256
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -148,6 +148,14 @@ static const char *const evidence_dao_list_all_sql =
|
||||||
" preuves.imported_at ASC,"
|
" preuves.imported_at ASC,"
|
||||||
" preuves.id ASC;";
|
" preuves.id ASC;";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Requête de mise à jour du statut d'intégrité.
|
||||||
|
*/
|
||||||
|
static const char *const evidence_dao_update_integrity_status_sql =
|
||||||
|
"UPDATE preuves "
|
||||||
|
"SET integrity_status = ? "
|
||||||
|
"WHERE id = ?;";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Enregistre une erreur littérale.
|
* @brief Enregistre une erreur littérale.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1191,6 +1199,151 @@ cleanup:
|
||||||
return evidence_record;
|
return evidence_record;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean evidence_dao_update_integrity_status(
|
||||||
|
EvidenceDao *evidence_dao,
|
||||||
|
const char *identifier,
|
||||||
|
EvidenceIntegrityStatus integrity_status,
|
||||||
|
GError **error
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DatabaseStatement *statement =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
gboolean identifier_exists =
|
||||||
|
FALSE;
|
||||||
|
|
||||||
|
gboolean success =
|
||||||
|
FALSE;
|
||||||
|
|
||||||
|
g_return_val_if_fail(
|
||||||
|
error == NULL || *error == NULL,
|
||||||
|
FALSE
|
||||||
|
);
|
||||||
|
|
||||||
|
if (evidence_dao == NULL ||
|
||||||
|
evidence_dao->database == NULL ||
|
||||||
|
identifier == NULL ||
|
||||||
|
!g_uuid_string_is_valid(
|
||||||
|
identifier
|
||||||
|
))
|
||||||
|
{
|
||||||
|
evidence_dao_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Le DAO ou l'identifiant de preuve est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (integrity_status <
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_UNKNOWN ||
|
||||||
|
integrity_status >
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_ERROR)
|
||||||
|
{
|
||||||
|
evidence_dao_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_DAO_ERROR_INVALID_ARGUMENT,
|
||||||
|
"Le statut d'intégrité demandé est invalide."
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cette vérification permet de distinguer une preuve absente
|
||||||
|
* d'une mise à jour SQLite ayant réellement échoué.
|
||||||
|
*/
|
||||||
|
if (!evidence_dao_value_exists(
|
||||||
|
evidence_dao,
|
||||||
|
evidence_dao_identifier_exists_sql,
|
||||||
|
identifier,
|
||||||
|
&identifier_exists,
|
||||||
|
error
|
||||||
|
))
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!identifier_exists)
|
||||||
|
{
|
||||||
|
evidence_dao_set_error_literal(
|
||||||
|
error,
|
||||||
|
EVIDENCE_DAO_ERROR_NOT_FOUND,
|
||||||
|
"La preuve à mettre à jour n'existe pas."
|
||||||
|
);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
statement =
|
||||||
|
database_statement_prepare(
|
||||||
|
evidence_dao->database,
|
||||||
|
evidence_dao_update_integrity_status_sql
|
||||||
|
);
|
||||||
|
|
||||||
|
if (statement == NULL)
|
||||||
|
{
|
||||||
|
evidence_dao_set_database_error(
|
||||||
|
evidence_dao,
|
||||||
|
error,
|
||||||
|
EVIDENCE_DAO_ERROR_PREPARE,
|
||||||
|
"Impossible de préparer la mise à jour "
|
||||||
|
"du statut d'intégrité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!database_statement_bind_int64(
|
||||||
|
statement,
|
||||||
|
1,
|
||||||
|
(int64_t) integrity_status
|
||||||
|
) ||
|
||||||
|
!database_statement_bind_text(
|
||||||
|
statement,
|
||||||
|
2,
|
||||||
|
identifier
|
||||||
|
))
|
||||||
|
{
|
||||||
|
evidence_dao_set_database_error(
|
||||||
|
evidence_dao,
|
||||||
|
error,
|
||||||
|
EVIDENCE_DAO_ERROR_BIND,
|
||||||
|
"Impossible de lier les paramètres "
|
||||||
|
"du statut d'intégrité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (database_statement_step(
|
||||||
|
statement
|
||||||
|
) != DATABASE_STATEMENT_STEP_DONE)
|
||||||
|
{
|
||||||
|
evidence_dao_set_database_error(
|
||||||
|
evidence_dao,
|
||||||
|
error,
|
||||||
|
EVIDENCE_DAO_ERROR_EXECUTE,
|
||||||
|
"Impossible de mettre à jour "
|
||||||
|
"le statut d'intégrité"
|
||||||
|
);
|
||||||
|
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
success =
|
||||||
|
TRUE;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
database_statement_finalize(
|
||||||
|
statement
|
||||||
|
);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean evidence_dao_count(
|
gboolean evidence_dao_count(
|
||||||
EvidenceDao *evidence_dao,
|
EvidenceDao *evidence_dao,
|
||||||
guint64 *out_count,
|
guint64 *out_count,
|
||||||
|
|
|
||||||
|
|
@ -468,6 +468,75 @@ static TestEvidenceDaoFixture test_evidence_dao_fixture_create(void)
|
||||||
return fixture;
|
return fixture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Crée une preuve destinée aux tests de statut d'intégrité.
|
||||||
|
*/
|
||||||
|
static EvidenceRecord *test_evidence_dao_create_integrity_record(
|
||||||
|
const char *identifier,
|
||||||
|
EvidenceIntegrityStatus integrity_status
|
||||||
|
)
|
||||||
|
{
|
||||||
|
EvidenceRecord *evidence_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *internal_name =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
char *relative_path =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
assert(identifier != NULL);
|
||||||
|
|
||||||
|
internal_name =
|
||||||
|
g_strdup_printf(
|
||||||
|
"%s.bin",
|
||||||
|
identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
relative_path =
|
||||||
|
g_strdup_printf(
|
||||||
|
"01_Preuves_Originales/Documents/%s.bin",
|
||||||
|
identifier
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(internal_name != NULL);
|
||||||
|
assert(relative_path != NULL);
|
||||||
|
|
||||||
|
evidence_record =
|
||||||
|
evidence_record_new(
|
||||||
|
identifier,
|
||||||
|
"preuve_integrite.bin",
|
||||||
|
internal_name,
|
||||||
|
relative_path,
|
||||||
|
"document",
|
||||||
|
128,
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
||||||
|
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||||
|
"2026-07-20T10:00:00Z",
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
integrity_status,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(evidence_record != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
relative_path
|
||||||
|
);
|
||||||
|
|
||||||
|
g_free(
|
||||||
|
internal_name
|
||||||
|
);
|
||||||
|
|
||||||
|
return evidence_record;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Détruit une fixture et ses fichiers temporaires.
|
* @brief Détruit une fixture et ses fichiers temporaires.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1743,13 +1812,315 @@ static void test_evidence_dao_list_invalid_arguments(void)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie la mise à jour d'une preuve vers VALID.
|
||||||
|
*/
|
||||||
|
static void test_evidence_dao_update_integrity_valid(void)
|
||||||
|
{
|
||||||
|
TestEvidenceDaoFixture fixture =
|
||||||
|
test_evidence_dao_fixture_create();
|
||||||
|
|
||||||
|
EvidenceRecord *inserted_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
EvidenceRecord *loaded_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
const char *identifier =
|
||||||
|
"12345678-1111-4111-8111-111111111111";
|
||||||
|
|
||||||
|
inserted_record =
|
||||||
|
test_evidence_dao_create_integrity_record(
|
||||||
|
identifier,
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_UNKNOWN
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_dao_insert(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
inserted_record,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_dao_update_integrity_status(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
identifier,
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
loaded_record =
|
||||||
|
evidence_dao_find_by_identifier(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
identifier,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(loaded_record != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_record_get_integrity_status(
|
||||||
|
loaded_record
|
||||||
|
) == EVIDENCE_INTEGRITY_STATUS_VALID
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_record_free(
|
||||||
|
loaded_record
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_record_free(
|
||||||
|
inserted_record
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie la mise à jour d'une preuve vers MODIFIED.
|
||||||
|
*/
|
||||||
|
static void test_evidence_dao_update_integrity_modified(void)
|
||||||
|
{
|
||||||
|
TestEvidenceDaoFixture fixture =
|
||||||
|
test_evidence_dao_fixture_create();
|
||||||
|
|
||||||
|
EvidenceRecord *inserted_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
EvidenceRecord *loaded_record =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
const char *identifier =
|
||||||
|
"12345678-2222-4222-8222-222222222222";
|
||||||
|
|
||||||
|
inserted_record =
|
||||||
|
test_evidence_dao_create_integrity_record(
|
||||||
|
identifier,
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_dao_insert(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
inserted_record,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_dao_update_integrity_status(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
identifier,
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_MODIFIED,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
loaded_record =
|
||||||
|
evidence_dao_find_by_identifier(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
identifier,
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(loaded_record != NULL);
|
||||||
|
assert(error == NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
evidence_record_get_integrity_status(
|
||||||
|
loaded_record
|
||||||
|
) == EVIDENCE_INTEGRITY_STATUS_MODIFIED
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_record_free(
|
||||||
|
loaded_record
|
||||||
|
);
|
||||||
|
|
||||||
|
evidence_record_free(
|
||||||
|
inserted_record
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le signalement d'une preuve inexistante.
|
||||||
|
*/
|
||||||
|
static void test_evidence_dao_update_integrity_missing(void)
|
||||||
|
{
|
||||||
|
TestEvidenceDaoFixture fixture =
|
||||||
|
test_evidence_dao_fixture_create();
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!evidence_dao_update_integrity_status(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
"12345678-3333-4333-8333-333333333333",
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error != NULL);
|
||||||
|
assert(error->domain == EVIDENCE_DAO_ERROR);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->code ==
|
||||||
|
(gint) EVIDENCE_DAO_ERROR_NOT_FOUND
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le refus d'un statut hors de l'énumération.
|
||||||
|
*/
|
||||||
|
static void test_evidence_dao_update_integrity_invalid_status(void)
|
||||||
|
{
|
||||||
|
TestEvidenceDaoFixture fixture =
|
||||||
|
test_evidence_dao_fixture_create();
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!evidence_dao_update_integrity_status(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
"12345678-4444-4444-8444-444444444444",
|
||||||
|
(EvidenceIntegrityStatus)
|
||||||
|
(EVIDENCE_INTEGRITY_STATUS_ERROR + 1),
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error != NULL);
|
||||||
|
assert(error->domain == EVIDENCE_DAO_ERROR);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->code ==
|
||||||
|
(gint) EVIDENCE_DAO_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Vérifie le refus des arguments invalides.
|
||||||
|
*/
|
||||||
|
static void test_evidence_dao_update_integrity_invalid_arguments(void)
|
||||||
|
{
|
||||||
|
TestEvidenceDaoFixture fixture =
|
||||||
|
test_evidence_dao_fixture_create();
|
||||||
|
|
||||||
|
GError *error =
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!evidence_dao_update_integrity_status(
|
||||||
|
NULL,
|
||||||
|
"12345678-5555-4555-8555-555555555555",
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->code ==
|
||||||
|
(gint) EVIDENCE_DAO_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!evidence_dao_update_integrity_status(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
NULL,
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->code ==
|
||||||
|
(gint) EVIDENCE_DAO_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
!evidence_dao_update_integrity_status(
|
||||||
|
fixture.evidence_dao,
|
||||||
|
"identifiant-invalide",
|
||||||
|
EVIDENCE_INTEGRITY_STATUS_VALID,
|
||||||
|
&error
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert(error != NULL);
|
||||||
|
|
||||||
|
assert(
|
||||||
|
error->code ==
|
||||||
|
(gint) EVIDENCE_DAO_ERROR_INVALID_ARGUMENT
|
||||||
|
);
|
||||||
|
|
||||||
|
g_clear_error(
|
||||||
|
&error
|
||||||
|
);
|
||||||
|
|
||||||
|
test_evidence_dao_fixture_clear(
|
||||||
|
&fixture
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
test_evidence_dao_new_null_database();
|
test_evidence_dao_new_null_database();
|
||||||
test_evidence_dao_new_valid();
|
test_evidence_dao_new_valid();
|
||||||
test_evidence_dao_free_null();
|
test_evidence_dao_free_null();
|
||||||
test_evidence_dao_insert_valid_full();
|
test_evidence_dao_insert_valid_full();
|
||||||
test_evidence_dao_insert_valid_full();
|
|
||||||
test_evidence_dao_insert_optional_null();
|
test_evidence_dao_insert_optional_null();
|
||||||
test_evidence_dao_insert_duplicate_sha256();
|
test_evidence_dao_insert_duplicate_sha256();
|
||||||
test_evidence_dao_insert_duplicate_identifier();
|
test_evidence_dao_insert_duplicate_identifier();
|
||||||
|
|
@ -1764,6 +2135,11 @@ int main(void)
|
||||||
test_evidence_dao_list_empty();
|
test_evidence_dao_list_empty();
|
||||||
test_evidence_dao_list_order();
|
test_evidence_dao_list_order();
|
||||||
test_evidence_dao_list_invalid_arguments();
|
test_evidence_dao_list_invalid_arguments();
|
||||||
|
test_evidence_dao_update_integrity_valid();
|
||||||
|
test_evidence_dao_update_integrity_modified();
|
||||||
|
test_evidence_dao_update_integrity_missing();
|
||||||
|
test_evidence_dao_update_integrity_invalid_status();
|
||||||
|
test_evidence_dao_update_integrity_invalid_arguments();
|
||||||
|
|
||||||
printf(
|
printf(
|
||||||
"EvidenceDao : tests de construction valides.\n"
|
"EvidenceDao : tests de construction valides.\n"
|
||||||
|
|
|
||||||
1321
tests/test_evidence_integrity_task.c
Normal file
1321
tests/test_evidence_integrity_task.c
Normal file
File diff suppressed because it is too large
Load diff
1016
tests/test_evidence_integrity_verifier.c
Normal file
1016
tests/test_evidence_integrity_verifier.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue