15 Commits

Author SHA1 Message Date
3524d33b6b feat: add integration tests with snapshot for some CPS cards in kits 2024-10-07 20:57:49 +02:00
0cbc89a91a feat: implement group2, CPS situation for SSV_LireCartePS 2024-10-07 19:24:55 +02:00
f55ac6f7df feat: Une enums for deserializable fields in CPS Holder group (01) 2024-10-07 12:12:18 +02:00
0fd14762f4 feat: Take the size into account for Block reading, to handle missing fields 2024-10-07 12:11:08 +02:00
137e41430e feat: use an enum instead of raw ID for CPS type 2024-10-06 14:53:53 +02:00
cb4d352f12 feat: raw (non-deserialized) implementation of the 01 group of LireCartePS 2024-10-05 11:39:51 +02:00
4e3387cef9 feat: implement a full SSV_LireConfig output parsing, using deku for a declarative bytes parsing
Co-authored-by: theo <t.lettermann@criteo.com>
2024-10-04 22:16:58 +02:00
79c16751e3 feat: implémentation partielle de la fonction get_config et de ses erreurs 2024-10-02 12:20:34 +02:00
b62e21771a feat: implement LireCartePS with hardcoded reader and all errors 2024-10-02 12:20:28 +02:00
405f923bc6 feat: Implémentation de la gestion des erreurs numériques de la librairie C pour la fonction InitLIB2
Co-authored-by: theo <t.lettermann@criteo.com>
2024-10-02 12:17:43 +02:00
a4773e5cf4 feat: Création de la crate fsv, couche de haut niveau pour l'usage des librairies FSV 2024-10-02 12:16:05 +02:00
97b4d6c443 feat: improve the fsv-sys README, and add a PROGESS.md for implementation tracking 2024-10-02 12:13:23 +02:00
6034e7f9db feat: Gestion des versions multiples de FSV dans le wrapper exposant les fonctions de la librairie 2024-10-02 12:13:22 +02:00
6c78db945e feat: handle multi-version bindings generation 2024-10-02 12:13:22 +02:00
27595bd4f9 feat: Première implémentation de bindings pour FSV SESAM-Vitale
- Création de la crates/fsv-sys
- Ajout des headers de la FSV 1.40.14.13 dans crates/fsv-sys/vendor
- Génération des bindings depuis ces headers avec bindgen
- Implémentation d'une structure de loading de la librairie au runtime
- Implémentation d'une macro permettant de générer facilement la couche d'accès aux fonctions de la librairie
2024-10-02 12:13:02 +02:00
10 changed files with 68 additions and 207 deletions

View File

@ -2017,7 +2017,6 @@ name = "fsv"
version = "0.1.0"
dependencies = [
"anyhow",
"chrono",
"deku",
"env_logger",
"fsv-sys",
@ -2035,7 +2034,6 @@ name = "fsv-sys"
version = "0.1.0"
dependencies = [
"bindgen",
"chrono",
"libc",
"libloading 0.8.5",
"thiserror",

View File

@ -16,6 +16,3 @@ thiserror.workspace = true
[build-dependencies]
bindgen = "0.70.1"
[dev-dependencies]
chrono = "0.4.38"

View File

@ -14,13 +14,13 @@
| SSV_InitLIB2 |
| SSV_LireConfig |
| SSV_LireCartePS |
| SSV_LireDroitsVitale |
## SGD
| Fonctions implémentées |
|------------------------|
## SRT
| Fonctions implémentées |

View File

@ -13,6 +13,13 @@
Les détails de l'avancement de l'implémentation des bindings FSV sont donnés dans le fichier [PROGRESS.md](PROGRESS.md)
| Module | Progression |
|-------------|------------------------------------|
| [SSV](#ssv) | ![](https://geps.dev/progress/5) |
| [SGD](#sgd) | ![](https://geps.dev/progress/0) |
| [SRT](#srt) | ![](https://geps.dev/progress/0) |
| [STS](#sts) | ![](https://geps.dev/progress/0) |
## Utilisation
### Pré-requis
@ -32,5 +39,5 @@ Les détails de l'avancement de l'implémentation des bindings FSV sont donnés
### Pré-requis
- Pour la génération des bindings lors de la phase de `build` à l'aide de `bindgen`, il est nécessaire d'avoir installé `clang` ([documentation](https://rust-lang.github.io/rust-bindgen/requirements.html)).
- Pour la génération des bindings lors de la pahse de `build` à l'aide de `bindgen`, il est nécessaire d'avoir installé `clang` ([documentation](https://rust-lang.github.io/rust-bindgen/requirements.html)).

View File

@ -109,15 +109,6 @@ impl SSVLibrary<V1_40_14> {
pZDataOut: *mut *mut libc::c_void,
pTailleZone: *mut usize
});
ssv_function!(BINDINGS_V1_40_14::SSV_LireDroitsVitale, ssv_lire_droits_vitale, {
NomRessourcePS: *const i8,
NomRessourceLecteur: *const i8,
CodePorteurPS: *const i8,
DateConsultation: *const i8,
pZDataOut: *mut *mut libc::c_void,
pTailleZone: *mut usize
});
}
impl SSVLibrary<V1_40_13> {
@ -137,15 +128,6 @@ impl SSVLibrary<V1_40_13> {
pZDataOut: *mut *mut libc::c_void,
pTailleZone: *mut usize
});
ssv_function!(BINDINGS_V1_40_13::SSV_LireDroitsVitale, ssv_lire_droits_vitale, {
NomRessourcePS: *const i8,
NomRessourceLecteur: *const i8,
CodePorteurPS: *const i8,
DateConsultation: *const i8,
pZDataOut: *mut *mut libc::c_void,
pTailleZone: *mut usize
});
}
pub fn get_library_path(version: &SupportedFsvVersion) -> String {
@ -180,103 +162,51 @@ mod test {
use super::*;
mod common {
use super::*;
const CPS_READER_NAME: &str = "Gemalto PC Twin Reader (645D94C3) 00 00";
const CPS_PIN: &str = "1234";
const VITALE_READER_NAME: &str = "XXXXXX";
pub fn init_library() -> SSVLibrary<V1_40_13> {
let lib_path = &get_library_path(&SupportedFsvVersion::V1_40_13);
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
let sesam_ini_str =
CString::new(sesam_ini_path(&SupportedFsvVersion::V1_40_13)).expect("CString::new failed");
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
assert_eq!(result, 0);
ssv_library
}
pub fn lire_config(ssv_library: &SSVLibrary<V1_40_13>) {
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe { ssv_library.ssv_lire_config(&mut buffer_ptr, &mut size) }.unwrap();
assert_eq!(result, 0);
unsafe { libc::free(buffer_ptr) };
}
pub fn lire_carte_ps(ssv_library: &SSVLibrary<V1_40_13>) {
let nom_ressource_ps =
CString::new(CPS_READER_NAME).expect("CString::new failed");
let nom_ressource_lecteur =
CString::new("useless parameter").expect("CString::new failed");
let code_porteur_ps = CString::new(CPS_PIN).expect("CString::new failed");
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe {
ssv_library.ssv_lire_carte_ps(
nom_ressource_ps.as_ptr(),
nom_ressource_lecteur.as_ptr(),
code_porteur_ps.as_ptr(),
&mut buffer_ptr,
&mut size,
)
}.unwrap();
assert_eq!(result, 0);
unsafe { libc::free(buffer_ptr) };
}
pub fn lire_droits_vitale(ssv_library: &SSVLibrary<V1_40_13>) {
let nom_ressource_ps =
CString::new(CPS_READER_NAME).expect("CString::new failed");
let nom_ressource_lecteur =
CString::new(VITALE_READER_NAME).expect("CString::new failed");
let code_porteur_ps = CString::new(CPS_PIN).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 buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe {
ssv_library.ssv_lire_droits_vitale(
nom_ressource_ps.as_ptr(),
nom_ressource_lecteur.as_ptr(),
code_porteur_ps.as_ptr(),
date_consultation.as_ptr(),
&mut buffer_ptr,
&mut size,
)
}.unwrap();
assert_eq!(result, 0);
unsafe { libc::free(buffer_ptr) };
}
}
#[test]
fn test_initlib2() {
let _ssv_library = common::init_library();
let lib_path = &get_library_path(&SupportedFsvVersion::V1_40_13);
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
let sesam_ini_str =
CString::new(sesam_ini_path(&SupportedFsvVersion::V1_40_13)).expect("CString::new failed");
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
assert_eq!(result, 0);
}
#[test]
fn test_lire_config() {
let ssv_library = common::init_library();
common::lire_config(&ssv_library);
}
fn test_lire_config_and_carte_ps() {
let lib_path = &get_library_path(&SupportedFsvVersion::V1_40_13);
let ssv_library = SSVLibrary::<V1_40_13>::new(lib_path).expect("SSVLibrary::new failed");
#[test]
#[ignore="This test requires a CPS card to be inserted in the reader"]
fn test_lire_carte_ps() {
let ssv_library = common::init_library();
common::lire_carte_ps(&ssv_library);
}
let sesam_ini_str =
CString::new(sesam_ini_path(&SupportedFsvVersion::V1_40_13)).expect("CString::new failed");
let result = unsafe { ssv_library.ssv_init_lib2(sesam_ini_str.as_ptr()) }.unwrap();
assert_eq!(result, 0);
#[test]
#[ignore="This test requires a CPS card and a Vitale card to be inserted in the readers"]
fn test_lire_droits_vitale() {
let ssv_library = common::init_library();
common::lire_droits_vitale(&ssv_library);
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe { ssv_library.ssv_lire_config(&mut buffer_ptr, &mut size) }.unwrap();
assert_eq!(result, 0);
unsafe { libc::free(buffer_ptr) };
let nom_ressource_ps =
CString::new("Gemalto PC Twin Reader (645D94C3) 00 00").expect("CString::new failed");
let nom_ressource_lecteur =
CString::new("Gemalto PC Twin Reader (645D94C3) 00 00").expect("CString::new failed");
let code_porteur_ps = CString::new("1234").expect("CString::new failed");
let mut buffer_ptr: *mut libc::c_void = ptr::null_mut();
let mut size: libc::size_t = 0;
let result = unsafe {
ssv_library.ssv_lire_carte_ps(
nom_ressource_ps.as_ptr(),
nom_ressource_lecteur.as_ptr(),
code_porteur_ps.as_ptr(),
&mut buffer_ptr,
&mut size,
)
}
.unwrap();
assert_eq!(result, 0);
unsafe { libc::free(buffer_ptr) };
}
}

View File

@ -18,7 +18,6 @@ utils = { path = "../utils" }
#[dev-dependencies]
log = "0.4.22"
env_logger = "0.11.5"
chrono = "0.4.38"
[dev-dependencies]
insta = "1.40.0"

View File

@ -3,8 +3,6 @@ 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,
@ -19,7 +17,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 format des données issues du lecteur est incompatible avec cette version de SSV.
/// - 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.")]

View File

@ -37,9 +37,6 @@ 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<Self, Error> {
let library = match version {
SupportedFsvVersion::V1_40_13 => {
@ -80,18 +77,18 @@ impl SSV {
/// # Read the CPS card
/// Implement: SSV_LireCartePS
pub fn read_professional_card(&self, pin_code: &str) -> Result<Data, Error> {
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");
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(
cps_pcsc_reader_name.as_ptr(),
vitale_pcsc_reader_name.as_ptr(),
pcsc_reader_name.as_ptr(),
pcsc_reader_name.as_ptr(),
pin_code.as_ptr(),
&mut out_buffer_ptr,
&mut out_buffer_size)
@ -99,8 +96,8 @@ impl SSV {
},
SsvLibraryVersion::V1_40_14(library) => {
unsafe { library.ssv_lire_carte_ps(
cps_pcsc_reader_name.as_ptr(),
vitale_pcsc_reader_name.as_ptr(),
pcsc_reader_name.as_ptr(),
pcsc_reader_name.as_ptr(),
pin_code.as_ptr(),
&mut out_buffer_ptr,
&mut out_buffer_size)
@ -152,58 +149,6 @@ impl SSV {
unsafe { libc::free(out_buffer_ptr) };
Ok(config_blocks)
}
pub fn get_vitale_card_rights(&self, pin_code: &str) -> Result<Data, Error> {
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)]
@ -240,7 +185,7 @@ mod tests {
#[test]
#[ignore="
WARNING: Read the card with PIN 1234 - Risk of blocking the card if it's not the right card
WARNING: Read the card with PIN 1234 - Risk of blocking the card
WARNING: This test will only work with GILBERT's PHARMOFFICE card (titulaire kit pharmacie)
"]
fn test_read_professional_card_good_pin() -> Result<()> {
@ -269,7 +214,7 @@ mod tests {
}
#[test]
#[ignore="WARNING: Read the card with PIN 0000 - Risk of blocking the card if it's not the right card"]
#[ignore="WARNING: Read the card with PIN 0000 - Risk of blocking the card"]
fn test_read_professional_card_bad_pin() -> Result<()> {
let lib = setup::init()?;
let pin_code = "0000";
@ -301,17 +246,4 @@ 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(())
}
}

View File

@ -17,6 +17,6 @@
if (user.avatar) {
return user.avatar;
}
return 'https://i.pravatar.cc/150?u=' + user.name;
return 'https://avatar.iran.liara.run/username?username=' + user.name;
};
</script>

View File

@ -29,15 +29,15 @@
const users: User[] = [
{ id: 1, name: 'John Doe', avatar: 'https://img.daisyui.com/images/stock/photo-1534528741775-53994a69daeb.webp' },
{ id: 2, name: 'Jane Doe', avatar: 'https://i.pravatar.cc/150?u=JANEDOE728' },
{ id: 3, name: 'Michel Moulin' },
{ id: 4, name: 'Jean Paris' },
{ id: 5, name: 'Marie Dupont' },
{ id: 6, name: 'Émilie Fournier' },
{ id: 7, name: 'Pierre Lefevre' },
{ id: 8, name: 'Sophie Lemoine' },
{ id: 9, name: 'Lucie Simon' },
{ id: 10, name: 'Kevin Boucher' },
{ id: 2, name: 'Jane Doe', avatar: 'https://avatar.iran.liara.run/public' },
{ id: 3, name: 'Michel Moulin', avatar: '' },
{ id: 4, name: 'Jean Paris', avatar: '' },
{ id: 5, name: 'Marie Dupont', avatar: '' },
{ id: 6, name: 'Émilie Fournier', avatar: '' },
{ id: 7, name: 'Pierre Lefevre', avatar: '' },
{ id: 8, name: 'Sophie Lemoine', avatar: '' },
{ id: 9, name: 'Lucie Simon', avatar: '' },
{ id: 10, name: 'Kevin Boucher', avatar: '' },
];
const loginModal = useTemplateRef('login_modal');