diff --git a/Cargo.lock b/Cargo.lock index 70a6805..33a3568 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1352,7 +1352,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smart-id-rust-client" -version = "0.1.3" +version = "0.1.4" dependencies = [ "anyhow", "base64", diff --git a/Cargo.toml b/Cargo.toml index a7a0c02..c28832b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "smart-id-rust-client" -version = "0.1.3" +version = "0.1.4" description = "Smart ID Rust Client" homepage = "https://smart-id.com" authors = ["Michallis Pashidis "] diff --git a/README.MD b/README.MD index 2325fb4..a375485 100644 --- a/README.MD +++ b/README.MD @@ -58,4 +58,127 @@ cargo test ```zsh cargo doc --no-deps --open ``` - \ No newline at end of file + +## Example Client + +See the examples folder for a simple example client. +To create an SmartID account, download the app: +[SmartID App](https://www.smart-id.com/download/) + +The example application goes through the following use cases: +- Verify Certificate Existence +- SmartID Authentication +- SmartID Digital Signature + +The example is using a MOCK ID to simulate the SmartID user. + +```shell +cargo run --example smart_id_client +``` + +### Configuration +SmartID configuration can be loaded form environment variables: +```shell +/// Get default Config (from environment variables) +let cfg = get_config_from_env(); +``` + +Or using the builder pattern: +```shell +/// Config Builder +let cfg = SmartIDConfigBuilder::new().url("https://sid.demo.sk.ee/smart-id-rp/v2").build().expect("Error building config"); +``` + +### Verify Certificate Existence + +To check whether a user has been onboarded, use the `get_certificate_by_semantic_identifier`: +```shell +async fn uc_get_certificate_choice(cfg: &SmartIDConfig) -> Result<()> { + + /// Create the semantic identifier + let sem_id = SemanticsIdentifier::new_from_enum_mock(IdentityType::PNO, CountryCode::BE); + + /// Verify if a certificate exists for given id + let res = get_certificate_by_semantic_identifier(&cfg, sem_id).await; + match res { + Ok(r) => { + let cert = validate_response_success(r).map(|res| res.cert.unwrap().value.unwrap())?; + info!("Smart ID Certificate {:#?}", cert); + Ok(()) + } + Err(_) => Err(anyhow::anyhow!("Error getting certificate")) + } +} +``` + +### SmartID Authentication + +To authenticate a user, use the `authenticate_by_semantic_identifier`: +```shell +async fn uc_authenticate_by_semantic_identifier(cfg: &SmartIDConfig) -> Result<()> { + /// Create the semantic identifier + let sem_id = SemanticsIdentifier::new_from_enum_mock(IdentityType::PNO, CountryCode::BE); + + /// Define interactions + let interactions: Vec = vec![Interaction::diplay_text_and_pin("Authenticate to Application: ReadMyCards")]; + + /// Create hash + let hash_type = HashType::SHA256; + let hash = sha_digest("This is a test string".to_string().into_bytes(), &hash_type)?; + let b64_hash = base64::engine::general_purpose::STANDARD.encode(hash.as_ref()); + let verification_code_for_user = generate_verification_number(hash.as_ref().to_vec())?; + info!("Verification code for user: {}", verification_code_for_user); + + /// Ask user for authentication + let res = authenticate_by_semantic_identifier(&cfg, sem_id, interactions, b64_hash, hash_type).await; + + match res { + Ok(r) => { + let session_result = validate_response_success(r).map(|res| res.result)?; + info!("Smart ID Authentication result {:#?}", session_result); + Ok(()) + } + Err(_) => Err(anyhow::anyhow!("Error during authentication")) + } +} +``` + +### SmartID Digital Signature + +To sign a document as a user, use the `sign_by_semantic_identifier`: +```shell +async fn uc_sign_by_semantic_identifier(cfg: &SmartIDConfig) -> Result<()> { + /// Create the semantic identifier + let sem_id = SemanticsIdentifier::new_from_enum_mock(IdentityType::PNO, CountryCode::BE); + + /// Define interactions + let interactions: Vec = vec![Interaction::confirmation_message("Are you sure to sign document: something.pdf?"), Interaction::diplay_text_and_pin("Sign using ReadMyCards")]; + + /// Create hash + let hash_type = HashType::SHA256; + let hash = sha_digest("This is a test string".to_string().into_bytes(), &hash_type)?; + let b64_hash = base64::engine::general_purpose::STANDARD.encode(hash.as_ref()); + + /// Create verification cod + let verification_code_for_user = generate_verification_number(hash.as_ref().to_vec())?; + info!("Verification code for user: {}", verification_code_for_user); + + /// Ask user to sign + let res = sign_by_semantic_identifier(&cfg, sem_id, interactions, b64_hash, hash_type).await; + match res { + Ok(r) => { + match validate_response_success(r).map(|res| res.signature)? { + None => { + warn!("No signature"); + Ok(()) + } + Some(signature) => { + info!("Smart ID signature result {:#?}", signature); + Ok(()) + } + } + } + Err(_) => Err(anyhow::anyhow!("Error signing digest")) + } +} +``` \ No newline at end of file diff --git a/src/client/smart_id_connector.rs b/src/client/smart_id_connector.rs index c888b72..3363aa5 100644 --- a/src/client/smart_id_connector.rs +++ b/src/client/smart_id_connector.rs @@ -1,8 +1,7 @@ use crate::models::common::{SemanticsIdentifier}; use crate::models::session::SessionStatus; use anyhow::Result; -use tracing::debug; -use tracing::log::info; +use tracing::{debug, info}; use crate::client::reqwest_generic::{get, post}; use crate::models::requests::{AuthenticationSessionRequest, CertificateRequest, SignatureSessionRequest}; use crate::models::responses::{AuthenticationSessionResponse, CertificateChoiceResponse, SignatureSessionResponse};