From 3c1e691cb8f789b73eddeebe4950ee76acc4b209 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Tue, 1 Oct 2024 19:13:03 +0200 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20Cr=C3=A9ation=20de=20la=20crate=20f?= =?UTF-8?q?sv,=20couche=20de=20haut=20niveau=20pour=20l'usage=20des=20libr?= =?UTF-8?q?airies=20FSV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 9 +++++ Cargo.toml | 1 + crates/fsv/Cargo.toml | 10 ++++++ crates/fsv/src/lib.rs | 1 + crates/fsv/src/ssv.rs | 83 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 crates/fsv/Cargo.toml create mode 100644 crates/fsv/src/lib.rs create mode 100644 crates/fsv/src/ssv.rs diff --git a/Cargo.lock b/Cargo.lock index b9200a6..473e030 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1963,6 +1963,15 @@ dependencies = [ "libc", ] +[[package]] +name = "fsv" +version = "0.1.0" +dependencies = [ + "fsv-sys", + "thiserror", + "utils", +] + [[package]] name = "fsv-sys" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 5c19dfc..f7ad9d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "crates/backend", "crates/desktop", "crates/sesam-vitale", + "crates/fsv", "crates/fsv-sys", "crates/utils", "migration", diff --git a/crates/fsv/Cargo.toml b/crates/fsv/Cargo.toml new file mode 100644 index 0000000..385ee27 --- /dev/null +++ b/crates/fsv/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "fsv" +version = "0.1.0" +edition = "2021" + +[dependencies] +thiserror = "1.0.64" + +fsv-sys = { path = "../fsv-sys" } +utils = { path = "../utils" } \ No newline at end of file diff --git a/crates/fsv/src/lib.rs b/crates/fsv/src/lib.rs new file mode 100644 index 0000000..77a1012 --- /dev/null +++ b/crates/fsv/src/lib.rs @@ -0,0 +1 @@ +mod ssv; diff --git a/crates/fsv/src/ssv.rs b/crates/fsv/src/ssv.rs new file mode 100644 index 0000000..89cd354 --- /dev/null +++ b/crates/fsv/src/ssv.rs @@ -0,0 +1,83 @@ +use thiserror::Error; + +use fsv_sys::{get_library_path, Error as FsvError, SSVLibrary, SSVLibrary_Common, SUPPORTED_FSV_VERSIONS, V1_40_13, V1_40_14}; + +#[derive(Error, Debug)] +pub enum Error { + #[error(transparent)] + SysLibrary(#[from] FsvError) +} + +/// Enum to hold the different versions of the SSV library +enum SsvLibraryVersion { + V1_40_13(SSVLibrary), + V1_40_14(SSVLibrary), +} + +/// Struct to hold the SSV library and access its functions +pub struct SSV { + library: SsvLibraryVersion, +} + +impl SSV { + fn new(version: SUPPORTED_FSV_VERSIONS) -> Result { + let library = match version { + SUPPORTED_FSV_VERSIONS::V1_40_13 => { + let lib_path = get_library_path(&version); + let library = SSVLibrary::::new(&lib_path)?; + SsvLibraryVersion::V1_40_13(library) + }, + SUPPORTED_FSV_VERSIONS::V1_40_14 => { + let lib_path = get_library_path(&version); + let library = SSVLibrary::::new(&lib_path)?; + SsvLibraryVersion::V1_40_14(library) + }, + }; + Ok(Self { + library, + }) + } + + /// # Initialize the SSV library + /// Implement: SSV_InitLIB2 + pub fn init_library(&self, sesam_ini_path: &str) -> Result<(), Error> { + let sesam_ini_path = std::ffi::CString::new(sesam_ini_path).expect("CString::new failed"); + match &self.library { + SsvLibraryVersion::V1_40_13(library) => { + let result = unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }?; + println!("SSV_InitLIB2 result: {}", result); + }, + SsvLibraryVersion::V1_40_14(library) => { + let result = unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }?; + println!("SSV_InitLIB2 result: {}", result); + }, + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use std::env; + + use utils::config::load_config; + + use super::*; + + fn init() -> SSV { + load_config().unwrap(); + SSV::new(SUPPORTED_FSV_VERSIONS::V1_40_13).expect("SSV::new failed") + } + + #[test] + fn test_init_library() { + let lib = init(); + let sesam_ini_path = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set"); + lib.init_library(&sesam_ini_path).expect("init_library failed"); + } + + #[test] + fn test_ssv() { + assert_eq!("ssv", "ssv"); + } +} -- 2.45.2 From 203521fe0101883e2137caa86fabed666566b5da Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Tue, 1 Oct 2024 21:03:24 +0200 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20Impl=C3=A9mentation=20de=20la=20ges?= =?UTF-8?q?tion=20des=20erreurs=20num=C3=A9riques=20de=20la=20librairie=20?= =?UTF-8?q?C=20pour=20la=20fonction=20InitLIB2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: theo --- Cargo.lock | 2 + crates/fsv/Cargo.toml | 4 +- crates/fsv/src/ssv/errors_ssv.rs | 82 +++++++++++++++++++++++++++ crates/fsv/src/{ssv.rs => ssv/mod.rs} | 47 ++++++++++----- 4 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 crates/fsv/src/ssv/errors_ssv.rs rename crates/fsv/src/{ssv.rs => ssv/mod.rs} (61%) diff --git a/Cargo.lock b/Cargo.lock index 473e030..a06acdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1967,7 +1967,9 @@ dependencies = [ name = "fsv" version = "0.1.0" dependencies = [ + "anyhow", "fsv-sys", + "num_enum", "thiserror", "utils", ] diff --git a/crates/fsv/Cargo.toml b/crates/fsv/Cargo.toml index 385ee27..32f6d54 100644 --- a/crates/fsv/Cargo.toml +++ b/crates/fsv/Cargo.toml @@ -4,7 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] +anyhow = "1.0.89" +num_enum = "0.7.3" thiserror = "1.0.64" fsv-sys = { path = "../fsv-sys" } -utils = { path = "../utils" } \ No newline at end of file +utils = { path = "../utils" } diff --git a/crates/fsv/src/ssv/errors_ssv.rs b/crates/fsv/src/ssv/errors_ssv.rs new file mode 100644 index 0000000..0acf486 --- /dev/null +++ b/crates/fsv/src/ssv/errors_ssv.rs @@ -0,0 +1,82 @@ +use num_enum::FromPrimitive; +use thiserror::Error; + +#[derive(Error, Debug, Eq, PartialEq, FromPrimitive)] +#[repr(u16)] +pub enum SSVErrorCodes { + #[error("Le fichier `tablebin.smc` est inaccessible en lecture (inexistant ou pas de droits d'accès).")] + FileMissingTablebinMsc = 0xF610, // tablebin.smc + #[error("Le fichier `scripts.sms` est inaccessible en lecture (inexistant ou pas de droits d'accès).")] + FileMissingScriptsSms = 0xF611, // scripts.sms + #[error("Le fichier `tablebin.ssv` est inaccessible en lecture (inexistant ou pas de droits d'accès).")] + FileMissingTablebinSsv = 0xF612, // tablebin.ssv + #[error("Le fichier `script.ssv` est inaccessible en lecture (inexistant ou pas de droits d'accès).")] + FileMissingScriptSsv = 0xF613, // script.ssv + #[error("La version du fichier `tablebin.smc` est incompatible avec la bibliothèque des SSV.")] + FileVersionIncompatibleTablebinMsc = 0xF620, // tablebin.smc + #[error("La version du fichier `scripts.sms` est incompatible avec la bibliothèque des SSV.")] + FileVersionIncompatibleScriptsSms = 0xF621, // scripts.sms + #[error("La version du fichier `tablebin.ssv` est incompatible avec la bibliothèque des SSV.")] + FileVersionIncompatibleTablebinSsv = 0xF622, // tablebin.ssv + #[error("La version du fichier `script.ssv` est incompatible avec la bibliothèque des SSV.")] + FileVersionIncompatibleScriptSsv = 0xF623, // script.ssv + #[error("L'intégrité du fichier `tablebin.smc` est incorrecte.")] + FileIntegrityIncorrectTablebinMsc = 0xF630, // tablebin.smc + #[error("L'intégrité du fichier `scripts.sms` est incorrecte.")] + FileIntegrityIncorrectScriptsSms = 0xF631, // scripts.sms + #[error("L'intégrité du fichier `tablebin.ssv` est incorrecte.")] + FileIntegrityIncorrectTablebinSsv = 0xF632, // tablebin.ssv + #[error("L'intégrité du fichier `script.ssv` est incorrecte.")] + FileIntegrityIncorrectScriptSsv = 0xF633, // script.ssv + #[error("La structure interne du fichier `tablebin.smc` est invalide.")] + FileStructureInvalidTablebinMsc = 0xF640, // tablebin.smc + #[error("La structure interne du fichier `scripts.sms` est invalide.")] + FileStructureInvalidScriptsSms = 0xF641, // scripts.sms + #[error("La structure interne du fichier `tablebin.ssv` est invalide.")] + FileStructureInvalidTablebinSsv = 0xF642, // tablebin.ssv + #[error("La structure interne du fichier `script.ssv` est invalide.")] + FileStructureInvalidScriptSsv = 0xF643, // script.ssv + #[error("Le fichier `tablebin.smc` n'a pas pu être chargé en mémoire. Essayez de libérer de la mémoire.")] + FileLoadFailedTablebinMsc = 0xF650, // tablebin.smc + #[error("Le fichier `scripts.sms` n'a pas pu être chargé en mémoire. Essayez de libérer de la mémoire.")] + FileLoadFailedScriptsSms = 0xF651, // scripts.sms + #[error("Le fichier `tablebin.ssv` n'a pas pu être chargé en mémoire. Essayez de libérer de la mémoire.")] + FileLoadFailedTablebinSsv = 0xF652, // tablebin.ssv + #[error("Le fichier `script.ssv` n'a pas pu être chargé en mémoire. Essayez de libérer de la mémoire.")] + FileLoadFailedScriptSsv = 0xF653, // script.ssv + #[error("Le nom du fichier `tablebin.smc` est invalide.")] + FileNameInvalidTablebinMsc = 0xF660, // tablebin.smc + #[error("Le nom du fichier `scripts.sms` est invalide.")] + FileNameInvalidScriptsSms = 0xF661, // scripts.sms + #[error("Le nom du fichier `tablebin.ssv` est invalide.")] + FileNameInvalidTablebinSsv = 0xF662, // tablebin.ssv + #[error("Le nom du fichier `script.ssv` est invalide.")] + FileNameInvalidScriptSsv = 0xF663, // script.ssv + #[error("La fonction Initialiser Librairie est déjà appelée.")] + FunctionInitLib2AlreadyCalled = 0xF670, // Warning + #[error("Le fichier SESAM.INI est inaccessible en lecture (fichier ou droit d’accès manquant) ou ne contient pas le chemin des tables binaires des SSV.")] + SesamIniMissingFileOrTablebinPath = 0xF680, + #[error("Le chemin du répertoire de travail est absent du fichier SESAM.INI.")] + SesamIniMissingWorkDir = 0xF6F1, + #[error("Les fichiers d’extension adm ne sont pas accessibles en écriture.")] + AdmFilesNotWritable = 0xF6F2, // Warning + #[error("Aucune version de FSV du socle technique trouvé. Vérifier que la version du fichier script.sms est bonne.")] + NoFsvVersionFound = 0xF6F4, + #[error("Librairie SGD absente ou incomplète.")] + LibraryMissingOrIncompleteSGD = 0xF6F5, + #[error("Librairie SMC absente ou incomplète.")] + LibraryMissingOrIncompleteSMC = 0xF6F6, + #[error("Librairie SJS absente ou incomplète.")] + LibraryMissingOrIncompleteSJS = 0xF6F7, + #[error("Librairie SMS absente ou incomplète.")] + LibraryMissingOrIncompleteSMS = 0xF6F8, + #[error("Section MGC absente / clé RepertoireConfigTrace absente / fichier log4crc.xml non trouvé à l’emplacement indiqué par la clé RepertoireConfigTrace du fichier SESAM.INI.")] + SesamIniTracingConfigMissing = 0xFF22, // Warning + #[error("Interface Full PC/SC : problème de chargement de la librairie cryptographique ou erreur retournée par la librairie cryptographique.")] + PCSCInterfaceCryptoLibraryError = 0xFF25, + #[error("Valorisation incorrecte des paramètres de gestion de l'accès aux ressources dans le SESAM.INI. Vérifier les valeurs des clés tempoexclusivite, repetitionexclusivite, tempoexclusivitePCSC, repetitionexclusivitePCSC")] + SesamIniResourceAccessParamsIncorrect = 0xFF2A, + #[num_enum(catch_all)] + #[error("Erreur inattendue de la librairie SSV (code d'erreur: {0}).")] + Unexpected(u16), +} diff --git a/crates/fsv/src/ssv.rs b/crates/fsv/src/ssv/mod.rs similarity index 61% rename from crates/fsv/src/ssv.rs rename to crates/fsv/src/ssv/mod.rs index 89cd354..0cd773a 100644 --- a/crates/fsv/src/ssv.rs +++ b/crates/fsv/src/ssv/mod.rs @@ -1,11 +1,24 @@ use thiserror::Error; -use fsv_sys::{get_library_path, Error as FsvError, SSVLibrary, SSVLibrary_Common, SUPPORTED_FSV_VERSIONS, V1_40_13, V1_40_14}; +use fsv_sys::{ + get_library_path, + Error as FsvError, + SSVLibrary, + SSVLibraryCommon, + SupportedFsvVersion, + V1_40_13, + V1_40_14 +}; + +mod errors_ssv; +use errors_ssv::SSVErrorCodes; #[derive(Error, Debug)] pub enum Error { #[error(transparent)] - SysLibrary(#[from] FsvError) + FSVSysLibrary(#[from] FsvError), + #[error(transparent)] + SSVError(#[from] SSVErrorCodes), } /// Enum to hold the different versions of the SSV library @@ -20,14 +33,14 @@ pub struct SSV { } impl SSV { - fn new(version: SUPPORTED_FSV_VERSIONS) -> Result { + fn new(version: SupportedFsvVersion) -> Result { let library = match version { - SUPPORTED_FSV_VERSIONS::V1_40_13 => { + SupportedFsvVersion::V1_40_13 => { let lib_path = get_library_path(&version); let library = SSVLibrary::::new(&lib_path)?; SsvLibraryVersion::V1_40_13(library) }, - SUPPORTED_FSV_VERSIONS::V1_40_14 => { + SupportedFsvVersion::V1_40_14 => { let lib_path = get_library_path(&version); let library = SSVLibrary::::new(&lib_path)?; SsvLibraryVersion::V1_40_14(library) @@ -42,15 +55,17 @@ impl SSV { /// Implement: SSV_InitLIB2 pub fn init_library(&self, sesam_ini_path: &str) -> Result<(), Error> { let sesam_ini_path = std::ffi::CString::new(sesam_ini_path).expect("CString::new failed"); - match &self.library { + let result = match &self.library { SsvLibraryVersion::V1_40_13(library) => { - let result = unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }?; - println!("SSV_InitLIB2 result: {}", result); + unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }? }, SsvLibraryVersion::V1_40_14(library) => { - let result = unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }?; - println!("SSV_InitLIB2 result: {}", result); + unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }? }, + }; + if result != 0 { + let error = SSVErrorCodes::from(result); + return Err(Error::SSVError(error)); } Ok(()) } @@ -61,19 +76,21 @@ mod tests { use std::env; use utils::config::load_config; + use anyhow::Result; use super::*; - fn init() -> SSV { + fn init() -> Result { load_config().unwrap(); - SSV::new(SUPPORTED_FSV_VERSIONS::V1_40_13).expect("SSV::new failed") + Ok(SSV::new(SupportedFsvVersion::V1_40_13)?) } #[test] - fn test_init_library() { - let lib = init(); + fn test_init_library() -> Result<()> { + let lib = init()?; let sesam_ini_path = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set"); - lib.init_library(&sesam_ini_path).expect("init_library failed"); + lib.init_library(&sesam_ini_path)?; + Ok(()) } #[test] -- 2.45.2 From 2260b0cfa83fabedcad22c478d3372202b396b8e Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Wed, 2 Oct 2024 00:42:41 +0200 Subject: [PATCH 3/6] feat: implement LireCartePS with hardcoded reader and all errors --- Cargo.lock | 1 + crates/fsv/Cargo.toml | 3 +- crates/fsv/src/ssv/errors_ssv.rs | 93 ++++++++++++++++++++++++++++++++ crates/fsv/src/ssv/mod.rs | 91 ++++++++++++++++++++++++++++--- 4 files changed, 180 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a06acdc..3f85311 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1969,6 +1969,7 @@ version = "0.1.0" dependencies = [ "anyhow", "fsv-sys", + "libc", "num_enum", "thiserror", "utils", diff --git a/crates/fsv/Cargo.toml b/crates/fsv/Cargo.toml index 32f6d54..e7bcb4b 100644 --- a/crates/fsv/Cargo.toml +++ b/crates/fsv/Cargo.toml @@ -5,7 +5,8 @@ edition = "2021" [dependencies] anyhow = "1.0.89" -num_enum = "0.7.3" +libc = "0.2.159" +num_enum = { version = "0.7.3", features = ["complex-expressions"] } thiserror = "1.0.64" fsv-sys = { path = "../fsv-sys" } diff --git a/crates/fsv/src/ssv/errors_ssv.rs b/crates/fsv/src/ssv/errors_ssv.rs index 0acf486..350dcd2 100644 --- a/crates/fsv/src/ssv/errors_ssv.rs +++ b/crates/fsv/src/ssv/errors_ssv.rs @@ -4,6 +4,75 @@ use thiserror::Error; #[derive(Error, Debug, Eq, PartialEq, FromPrimitive)] #[repr(u16)] pub enum SSVErrorCodes { + #[error("La Carte du Professionnel de Santé est absente du lecteur.")] + CPSMissing = 0xF001, + #[error("La Carte du Professionnel de Santé bloquée après trois codes porteur erronés.")] + CPSBlocked = 0xF002, + #[error("Le code porteur présenté est erroné.")] + CPSPinWrong = 0xF003, + #[error("Carte du Professionnel de Santé non valide ou inexploitable par le Logiciel Lecteur. Vérifier la présence d'un Domaine d'Assurance Maladie (DAM).")] + CPSInvalid = 0xF004, + #[error("La Carte du Professionnel de Santé est retirée du lecteur.")] + CPSRemoved = 0xF005, + #[error("Message du lecteur incohérent. Débrancher et rebrancher le lecteur.")] + PCSCInconsistentMessage = 0xF0FF, + #[error("Le nom de lecteur fourni ne correspond à aucun lecteur reconnu.")] + PCSCReaderNotFound = 0xF101, + #[error("La fonction InitLIB2 n'est pas encore appelée ou la fonction TermLIB a déjà été appelée.")] + FunctionInitLib2NotCalled = 0xF600, + #[error("La bibliothèque SSV n’est pas chargée en mémoire. Vérifier que la fonction InitLIB2 a bien été appelée.")] + LibraryNotLoaded = 0xF690, // Warning + #[error("Carte vitale en opposition.")] + VitaleOpposition = 0xF6A1, + #[error("Zone de mémoire non allouée en sortie.")] + MemoryNotAllocated = 0xF800, + #[error("Erreur d'allocation de la zone de mémoire en sortie.")] + MemoryAllocationError = 0xF801, + #[error("Un des paramètres obligatoires d'entrée est non alloué ou invalide.")] + InputParameterNotAllocatedOrInvalid = 0xF802, + #[error("Zone de mémoire spécifiée en entrée non valide. Vérifier que la zone allouée ne dépasse pas la taille maximale autorisée (MAXBLOC).")] + InputMemoryInvalid = 0xF803, + #[error("Le format de la zone de mémoire d'entrée ou le nombre de zones mémoire est incorrect.")] + InputMemoryFormatIncorrect = 0xF810, + #[error("Problème lors de l’initialisation du protocole. Erreur du Ressource Manager PC/SC. Vérifiez le lecteur.")] + PCSCProtocolInitError = 0xFF01, + #[error("Time-out au niveau protocolaire ou transmission déjà en cours avec le lecteur. Vérifiez le lecteur et l'insertion de la carte.")] + PCSCProtocolTimeout = 0xFF02, + #[error("Taille insuffisante allouée en entrée d’une fonction du Resource Manager.")] + PCSCProtocolInputMemoryTooSmall = 0xFF03, + #[error("Erreur de transmission du protocole. Vérifiez le lecteur et l'insertion de la carte.")] + PCSCProtocolTransmissionError = 0xFF04, + #[error("Lecteur absent ou indisponible.")] + PCSCReaderMissingOrUnavailable = 0xFF05, + #[error("Le nom du lecteur transmis est inconnu du Resource Manager PC/SC.")] + PCSCReaderUnknown = 0xFF06, + #[error("Erreur inconnue remontée par le Resource Manager PC/SC.")] + PCSCUnknownError = 0xFF07, + #[error("Erreur interne Resource Manager PC/SC.")] + PCSCInternalError = 0xFF08, + #[error("Ressource PC/SC déjà prise en exclusivité. Vérifiez qu'une autre application n'utilise pas le lecteur.")] + PCSCResourceAlreadyExclusive = 0xFF09, + #[error("Protocole incompatible avec la carte à puce. Vérifiez l'insertion de la carte et son état.")] + PCSCProtocolIncompatible = 0xFF0A, + #[error("Paramètre incorrect. Erreur interne à la librairie SSV.")] + PCSCIncorrectParameter = 0xFF0B, + #[error("Carte absente. Insérez une carte dans le lecteur.")] + PCSCCardMissing = 0xFF0C, + #[error("L'état de la carte a été modifié (RAZ ou mise hors tension). Vérifiez si la carte n'a pas été retirée ou si une autre application n'utilise pas la carte.")] + PCSCCardStateChanged = 0xFF0D, + #[error("Carte muette ou non supportée. Vérifiez l'insertion de la carte.")] + PCSCCardUnsupported = 0xFF0E, + #[error("Code porteur CPS non renseigné.")] + CPSPinMissing = 0xFF21, + #[error("Ressource PC/SC déjà prise en exclusivité. Vérifiez que le processus en cours n'utilise pas déjà le lecteur.")] + PCSCReaderAlreadyExclusiveForCurrentProcess = 0xFF24, + #[error("Plusieurs lecteurs ou cartes de même type identifiés lors de la détection automatique.")] + PCSCDuplicatedReadersOrCardsDetected = 0xFF29, + #[error("Problème de chargement de la librairie cryptographique ou erreur retournée par la librairie cryptographique.")] + CryptoLibraryError = 0xFF30, + #[error("Erreurs internes aux Services SESAM-Vitale. Vérifiez les traces.")] + #[num_enum(alternatives = [0xFFF1..=0xFFFF])] + SSVInternalError = 0xFFF0, #[error("Le fichier `tablebin.smc` est inaccessible en lecture (inexistant ou pas de droits d'accès).")] FileMissingTablebinMsc = 0xF610, // tablebin.smc #[error("Le fichier `scripts.sms` est inaccessible en lecture (inexistant ou pas de droits d'accès).")] @@ -80,3 +149,27 @@ pub enum SSVErrorCodes { #[error("Erreur inattendue de la librairie SSV (code d'erreur: {0}).")] Unexpected(u16), } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_code_ranges() { + let error_code = 0xFFF1; + let error = SSVErrorCodes::from(error_code); + assert_eq!(error, SSVErrorCodes::SSVInternalError); + + let error_code = 0xFFF8; + let error = SSVErrorCodes::from(error_code); + assert_eq!(error, SSVErrorCodes::SSVInternalError); + } + + #[test] + fn test_catch_all() { + let error_code = 0xFBFF; // Not a valid error code + let error = SSVErrorCodes::from(error_code); + assert_eq!(error, SSVErrorCodes::Unexpected(0xFBFF)); + } +} + \ No newline at end of file diff --git a/crates/fsv/src/ssv/mod.rs b/crates/fsv/src/ssv/mod.rs index 0cd773a..fdd8d55 100644 --- a/crates/fsv/src/ssv/mod.rs +++ b/crates/fsv/src/ssv/mod.rs @@ -1,3 +1,5 @@ +use std::{ffi::CString, ptr}; + use thiserror::Error; use fsv_sys::{ @@ -54,7 +56,7 @@ impl SSV { /// # Initialize the SSV library /// Implement: SSV_InitLIB2 pub fn init_library(&self, sesam_ini_path: &str) -> Result<(), Error> { - let sesam_ini_path = std::ffi::CString::new(sesam_ini_path).expect("CString::new failed"); + let sesam_ini_path = CString::new(sesam_ini_path).expect("CString::new failed"); let result = match &self.library { SsvLibraryVersion::V1_40_13(library) => { unsafe { library.ssv_init_lib2(sesam_ini_path.as_ptr()) }? @@ -69,6 +71,51 @@ impl SSV { } Ok(()) } + + /// # Read the CPS card + /// Implement: SSV_LireCartePS + pub fn read_professional_card(&self, pin_code: &str) -> Result<(), Error> { + let pcsc_reader_name = "Gemalto PC Twin Reader (645D94C3) 00 00"; + + let pin_code = CString::new(pin_code).expect("CString::new failed"); + let pcsc_reader_name = CString::new(pcsc_reader_name).expect("CString::new failed"); + let mut out_buffer_ptr: *mut libc::c_void = ptr::null_mut(); + let mut out_buffer_size: libc::size_t = 0; + + let result = match &self.library { + SsvLibraryVersion::V1_40_13(library) => { + unsafe { library.ssv_lire_carte_ps( + pcsc_reader_name.as_ptr(), + pcsc_reader_name.as_ptr(), + pin_code.as_ptr(), + &mut out_buffer_ptr, + &mut out_buffer_size) + }? + }, + SsvLibraryVersion::V1_40_14(library) => { + unsafe { library.ssv_lire_carte_ps( + pcsc_reader_name.as_ptr(), + pcsc_reader_name.as_ptr(), + pin_code.as_ptr(), + &mut out_buffer_ptr, + &mut out_buffer_size) + }? + }, + }; + + if result != 0 { + // Free memory + unsafe { libc::free(out_buffer_ptr) }; + let error = SSVErrorCodes::from(result); + return Err(Error::SSVError(error)); + } + // Print 10 bytes of the buffer + let buffer = unsafe { std::slice::from_raw_parts(out_buffer_ptr as *const u8, 10) }; + println!("{:?}", buffer); + // Free memory + unsafe { libc::free(out_buffer_ptr) }; + Ok(()) + } } #[cfg(test)] @@ -80,16 +127,46 @@ mod tests { use super::*; - fn init() -> Result { - load_config().unwrap(); - Ok(SSV::new(SupportedFsvVersion::V1_40_13)?) + mod setup { + use super::*; + + pub fn init() -> Result { + load_config().unwrap(); + let sesam_ini_path = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set"); + let lib = SSV::new(SupportedFsvVersion::V1_40_13)?; + lib.init_library(&sesam_ini_path)?; + Ok(lib) + } } #[test] fn test_init_library() -> Result<()> { - let lib = init()?; - let sesam_ini_path = env::var("SESAM_INI_PATH").expect("SESAM_INI_PATH must be set"); - lib.init_library(&sesam_ini_path)?; + setup::init()?; + Ok(()) + } + + #[test] + fn test_read_professional_card_good_pin() -> Result<()> { + let lib = setup::init()?; + let pin_code = "1234"; + lib.read_professional_card(pin_code)?; + Ok(()) + } + + #[ignore] + #[test] + fn test_read_professional_card_bad_pin() -> Result<()> { + let lib = setup::init()?; + let pin_code = "0000"; + // Should return an error + let err = lib.read_professional_card(pin_code).unwrap_err(); + assert_eq!(err.to_string(), "Le code porteur présenté est erroné."); + match err { + Error::SSVError(err) => { + assert_eq!(err as SSVErrorCodes, SSVErrorCodes::CPSPinWrong); + }, + _ => panic!("Error type is not SSVError"), + } Ok(()) } -- 2.45.2 From d043915a29e73635f532c9e4184f64b70a8a4595 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Wed, 2 Oct 2024 01:00:04 +0200 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20impl=C3=A9mentation=20partielle=20d?= =?UTF-8?q?e=20la=20fonction=20get=5Fconfig=20et=20de=20ses=20erreurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fsv/src/ssv/errors_ssv.rs | 6 ++++++ crates/fsv/src/ssv/mod.rs | 35 ++++++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/crates/fsv/src/ssv/errors_ssv.rs b/crates/fsv/src/ssv/errors_ssv.rs index 350dcd2..6c32fd4 100644 --- a/crates/fsv/src/ssv/errors_ssv.rs +++ b/crates/fsv/src/ssv/errors_ssv.rs @@ -14,6 +14,12 @@ pub enum SSVErrorCodes { CPSInvalid = 0xF004, #[error("La Carte du Professionnel de Santé est retirée du lecteur.")] CPSRemoved = 0xF005, + /// - Sécurisation d'une série de lots en cours. + /// - Pour les fonctions TLA (sauf Identifier TLA) : Cette erreur survient lorsque le simulateur TLA est en mode 1.50. + /// - Lire Date Lecteur, Mettre à jour Date Lecteur, Lire Droits Vitale : Cette erreur peut survenir lorsque le Logiciel Lecteur ne connaît pas la fonction sollicitée, c'est-à-dire si la version du Logiciel Lecteur est antérieure à 2.00. + /// - Décharger Données Bénéficiaires : cette erreur peut survenir pour signaler que le + #[error("F022: Erreur commune à plusieurs fonctions.")] + F022 = 0xF022, #[error("Message du lecteur incohérent. Débrancher et rebrancher le lecteur.")] PCSCInconsistentMessage = 0xF0FF, #[error("Le nom de lecteur fourni ne correspond à aucun lecteur reconnu.")] diff --git a/crates/fsv/src/ssv/mod.rs b/crates/fsv/src/ssv/mod.rs index fdd8d55..d611c4c 100644 --- a/crates/fsv/src/ssv/mod.rs +++ b/crates/fsv/src/ssv/mod.rs @@ -116,6 +116,35 @@ impl SSV { unsafe { libc::free(out_buffer_ptr) }; Ok(()) } + + /// # Get the configuration of the SSV library + /// Implement: SSV_LireConfig + pub fn get_config(&self) -> Result<(), Error> { + let mut buffer_ptr: *mut libc::c_void = ptr::null_mut(); + let mut size: libc::size_t = 0; + + let result = match &self.library { + SsvLibraryVersion::V1_40_13(library) => { + unsafe { library.ssv_lire_config(&mut buffer_ptr, &mut size) }? + }, + SsvLibraryVersion::V1_40_14(library) => { + unsafe { library.ssv_lire_config(&mut buffer_ptr, &mut size) }? + }, + }; + + if result != 0 { + // Free memory + unsafe { libc::free(buffer_ptr) }; + let error = SSVErrorCodes::from(result); + return Err(Error::SSVError(error)); + } + // Print 10 bytes of the buffer + let buffer = unsafe { std::slice::from_raw_parts(buffer_ptr as *const u8, 10) }; + println!("{:?}", buffer); + // Free memory + unsafe { libc::free(buffer_ptr) }; + Ok(()) + } } #[cfg(test)] @@ -171,7 +200,9 @@ mod tests { } #[test] - fn test_ssv() { - assert_eq!("ssv", "ssv"); + fn test_get_config() -> Result<()> { + let lib = setup::init()?; + lib.get_config()?; + Ok(()) } } -- 2.45.2 From 5f7229c307bcadc3ac6573f30494bd64bb664699 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Wed, 9 Oct 2024 22:43:25 +0200 Subject: [PATCH 5/6] =?UTF-8?q?fixup!=20feat:=20Impl=C3=A9mentation=20de?= =?UTF-8?q?=20la=20gestion=20des=20erreurs=20num=C3=A9riques=20de=20la=20l?= =?UTF-8?q?ibrairie=20C=20pour=20la=20fonction=20InitLIB2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fsv/src/ssv/errors_ssv.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crates/fsv/src/ssv/errors_ssv.rs b/crates/fsv/src/ssv/errors_ssv.rs index 6c32fd4..ef4df9d 100644 --- a/crates/fsv/src/ssv/errors_ssv.rs +++ b/crates/fsv/src/ssv/errors_ssv.rs @@ -3,6 +3,8 @@ use thiserror::Error; #[derive(Error, Debug, Eq, PartialEq, FromPrimitive)] #[repr(u16)] +/// Liste des codes d'erreur retournés par la librairie C SSV +/// Documentation: Manuel de programmation SSV - Annexe A (p. 215) pub enum SSVErrorCodes { #[error("La Carte du Professionnel de Santé est absente du lecteur.")] CPSMissing = 0xF001, -- 2.45.2 From 1b94fefad39b3ee112c4e2cddf172ae02999c951 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Wed, 9 Oct 2024 22:45:01 +0200 Subject: [PATCH 6/6] =?UTF-8?q?fixup!=20feat:=20impl=C3=A9mentation=20part?= =?UTF-8?q?ielle=20de=20la=20fonction=20get=5Fconfig=20et=20de=20ses=20err?= =?UTF-8?q?eurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fsv/src/ssv/errors_ssv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fsv/src/ssv/errors_ssv.rs b/crates/fsv/src/ssv/errors_ssv.rs index ef4df9d..5646311 100644 --- a/crates/fsv/src/ssv/errors_ssv.rs +++ b/crates/fsv/src/ssv/errors_ssv.rs @@ -19,7 +19,7 @@ pub enum SSVErrorCodes { /// - Sécurisation d'une série de lots en cours. /// - Pour les fonctions TLA (sauf Identifier TLA) : Cette erreur survient lorsque le simulateur TLA est en mode 1.50. /// - Lire Date Lecteur, Mettre à jour Date Lecteur, Lire Droits Vitale : Cette erreur peut survenir lorsque le Logiciel Lecteur ne connaît pas la fonction sollicitée, c'est-à-dire si la version du Logiciel Lecteur est antérieure à 2.00. - /// - Décharger Données Bénéficiaires : cette erreur peut survenir pour signaler que le + /// - Décharger Données Bénéficiaires : cette erreur peut survenir pour signaler que le format des données issues du lecteur est incompatible avec cette version de SSV. #[error("F022: Erreur commune à plusieurs fonctions.")] F022 = 0xF022, #[error("Message du lecteur incohérent. Débrancher et rebrancher le lecteur.")] -- 2.45.2