From 21aa637af34c356b991eef89feef5d01f78e41a9 Mon Sep 17 00:00:00 2001 From: Florian Briand Date: Thu, 10 Oct 2024 15:39:43 +0200 Subject: [PATCH] feat: implement high level get_vitale_card_rights over SSV_LireDroitsVitale - without output data parsing --- Cargo.lock | 1 + crates/fsv/Cargo.toml | 1 + crates/fsv/src/ssv/mod.rs | 86 +++++++++++++++++++++++++++++++++++---- 3 files changed, 79 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ed28d3..8ad302c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2017,6 +2017,7 @@ name = "fsv" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "deku", "env_logger", "fsv-sys", diff --git a/crates/fsv/Cargo.toml b/crates/fsv/Cargo.toml index e6fdf3b..1dd50a4 100644 --- a/crates/fsv/Cargo.toml +++ b/crates/fsv/Cargo.toml @@ -18,6 +18,7 @@ utils = { path = "../utils" } #[dev-dependencies] log = "0.4.22" env_logger = "0.11.5" +chrono = "0.4.38" [dev-dependencies] insta = "1.40.0" diff --git a/crates/fsv/src/ssv/mod.rs b/crates/fsv/src/ssv/mod.rs index dbf7fc9..e774a9a 100644 --- a/crates/fsv/src/ssv/mod.rs +++ b/crates/fsv/src/ssv/mod.rs @@ -37,6 +37,9 @@ pub struct SSV { } impl SSV { + const CPS_READER_NAME: &'static str = "Gemalto PC Twin Reader (645D94C3) 00 00"; + const VITALE_READER_NAME: &'static str = "Gemalto PC Twin Reader (645D94C3) 00 00"; // TODO: Change this to the correct reader name + pub fn new(version: SupportedFsvVersion) -> Result { let library = match version { SupportedFsvVersion::V1_40_13 => { @@ -77,18 +80,18 @@ impl SSV { /// # Read the CPS card /// Implement: SSV_LireCartePS pub fn read_professional_card(&self, pin_code: &str) -> Result { - 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 cps_pcsc_reader_name = CString::new(SSV::CPS_READER_NAME).expect("CString::new failed"); + let vitale_pcsc_reader_name = CString::new(SSV::VITALE_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(), + cps_pcsc_reader_name.as_ptr(), + vitale_pcsc_reader_name.as_ptr(), pin_code.as_ptr(), &mut out_buffer_ptr, &mut out_buffer_size) @@ -96,8 +99,8 @@ impl SSV { }, SsvLibraryVersion::V1_40_14(library) => { unsafe { library.ssv_lire_carte_ps( - pcsc_reader_name.as_ptr(), - pcsc_reader_name.as_ptr(), + cps_pcsc_reader_name.as_ptr(), + vitale_pcsc_reader_name.as_ptr(), pin_code.as_ptr(), &mut out_buffer_ptr, &mut out_buffer_size) @@ -149,6 +152,58 @@ impl SSV { unsafe { libc::free(out_buffer_ptr) }; Ok(config_blocks) } + + pub fn get_vitale_card_rights(&self, pin_code: &str) -> Result { + let pin_code = CString::new(pin_code).expect("CString::new failed"); + let cps_pcsc_reader_name = CString::new(SSV::CPS_READER_NAME).expect("CString::new failed"); + let vitale_pcsc_reader_name = CString::new(SSV::VITALE_READER_NAME).expect("CString::new failed"); + // Today's date, in the format YYYYMMDD + let today = chrono::Local::now().format("%Y%m%d").to_string(); + let date_consultation = CString::new(today).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_droits_vitale( + cps_pcsc_reader_name.as_ptr(), + vitale_pcsc_reader_name.as_ptr(), + pin_code.as_ptr(), + date_consultation.as_ptr(), + &mut out_buffer_ptr, + &mut out_buffer_size) + }? + }, + SsvLibraryVersion::V1_40_14(library) => { + unsafe { library.ssv_lire_droits_vitale( + cps_pcsc_reader_name.as_ptr(), + vitale_pcsc_reader_name.as_ptr(), + pin_code.as_ptr(), + date_consultation.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)); + } + // Parse the buffer into a Data struct + let buffer = unsafe { std::slice::from_raw_parts(out_buffer_ptr as *const u8, out_buffer_size) }; + //////////////////////////// + println!("{:?}", buffer); + //////////////////////////// + let (_rest, vitale_blocks) = Data::from_bytes((buffer, 0)).unwrap(); + + // Free memory + unsafe { libc::free(out_buffer_ptr) }; + Ok(vitale_blocks) + } } #[cfg(test)] @@ -185,7 +240,7 @@ mod tests { #[test] #[ignore=" - WARNING: Read the card with PIN 1234 - Risk of blocking the card + WARNING: Read the card with PIN 1234 - Risk of blocking the card if it's not the right card WARNING: This test will only work with GILBERT's PHARMOFFICE card (titulaire kit pharmacie) "] fn test_read_professional_card_good_pin() -> Result<()> { @@ -214,7 +269,7 @@ mod tests { } #[test] - #[ignore="WARNING: Read the card with PIN 0000 - Risk of blocking the card"] + #[ignore="WARNING: Read the card with PIN 0000 - Risk of blocking the card if it's not the right card"] fn test_read_professional_card_bad_pin() -> Result<()> { let lib = setup::init()?; let pin_code = "0000"; @@ -246,4 +301,17 @@ mod tests { assert_eq!(header_content.ssv_version.0.revision, "20"); Ok(()) } + + #[test] + #[ignore=" + WARNING: Read the card with PIN 1234 - Risk of blocking the card if it's not the right card + WARNING: This test needs a CPS and a VITALE card available simultaneously + "] + fn test_get_vitale_card_rights() -> Result<()> { + let lib = setup::init()?; + let pin_code = "1234"; + let _cps_blocks = lib.read_professional_card(pin_code)?; + let _vitale_blocks = lib.get_vitale_card_rights(pin_code)?; + Ok(()) + } }