use anyhow::Result;
use image::Luma;
use qrcode::QrCode;
use smart_id_rust_client::client::smart_id_client::SmartIdClient;
use smart_id_rust_client::config::SmartIDConfig;
use smart_id_rust_client::models::api::authentication_session::{
AuthenticationCertificateLevel, AuthenticationDeviceLinkRequest,
};
use smart_id_rust_client::models::api::session_status::SessionStatusResponse;
use smart_id_rust_client::models::api::signature_session::SignatureDeviceLinkRequest;
use smart_id_rust_client::models::common::SchemeName;
use smart_id_rust_client::models::device_link::DeviceLinkType;
use smart_id_rust_client::models::interaction::Interaction;
use smart_id_rust_client::models::signature::{HashingAlgorithm, SignatureAlgorithm};
use tracing::{info, Level};
use tracing_subscriber::fmt::format::FmtSpan;
use tracing_subscriber::fmt::SubscriberBuilder;
#[tokio::main]
async fn main() -> Result<()> {
init_tracing();
let _cfg = SmartIDConfig {
root_url: "https://sid.demo.sk.ee".to_string(),
api_path: "/smart-id-rp/v3".to_string(),
scheme_name: SchemeName::smart_id_demo,
relying_party_uuid: "test-uuid".to_string(),
relying_party_name: "test-name".to_string(),
client_request_timeout: Some(30000),
long_polling_timeout: 120000,
};
let cfg = SmartIDConfig::load_from_env()?;
info!("Config: {:?}", cfg);
let smart_id_client = SmartIdClient::new(&cfg, None, vec![], vec![]);
let authentication_session_status =
uc_authentication_request_example(&cfg, &smart_id_client).await?;
let document_number = authentication_session_status
.clone()
.result
.unwrap()
.document_number
.unwrap();
info!(
"Authentication Result: \n {:?}",
authentication_session_status
);
let digest = "YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE=".to_string();
let signature =
uc_signature_request_example(&cfg, &smart_id_client, digest, document_number).await?;
info!("Signature: \n {:?}", signature);
Ok(())
}
async fn uc_authentication_request_example(
cfg: &SmartIDConfig,
smart_id_client: &SmartIdClient,
) -> Result<SessionStatusResponse> {
let authentication_request = AuthenticationDeviceLinkRequest::new(
cfg,
vec![Interaction::DisplayTextAndPIN {
display_text_60: "Authenticate to Application: Test".to_string(),
}],
SignatureAlgorithm::RsassaPss,
AuthenticationCertificateLevel::QUALIFIED,
None, HashingAlgorithm::sha_256,
)?;
smart_id_client
.start_authentication_device_link_anonymous_session(authentication_request)
.await?;
let qr_code_link = smart_id_client.generate_device_link(DeviceLinkType::QR, "eng")?;
info!("{:?}", qr_code_link);
let app_to_app_link = smart_id_client.generate_device_link(DeviceLinkType::App2App, "eng")?;
info!("{:?}", app_to_app_link);
let web_to_app_link = smart_id_client.generate_device_link(DeviceLinkType::Web2App, "eng")?;
info!("{:?}", web_to_app_link);
open_qr_in_computer_image_viewer(qr_code_link.clone(), "auth_qr_code")?;
let result = smart_id_client.get_session_status().await?;
info!("{:?}", result.clone().result.unwrap().end_result);
Ok(result)
}
async fn uc_signature_request_example(
cfg: &SmartIDConfig,
smart_id_client: &SmartIdClient,
digest: String,
document_number: String,
) -> Result<String> {
let signature_request = SignatureDeviceLinkRequest::new(
cfg,
vec![Interaction::DisplayTextAndPIN {
display_text_60: "Sign document".to_string(),
}],
digest,
SignatureAlgorithm::RsassaPss,
HashingAlgorithm::sha_256,
None, )?;
smart_id_client
.start_signature_device_link_document_session(signature_request, document_number)
.await?;
let qr_code_link = smart_id_client.generate_device_link(DeviceLinkType::QR, "eng")?;
info!("{:?}", qr_code_link);
let app_to_app_link = smart_id_client.generate_device_link(DeviceLinkType::App2App, "eng")?;
info!("{:?}", app_to_app_link);
let web_to_app_link = smart_id_client.generate_device_link(DeviceLinkType::Web2App, "eng")?;
info!("{:?}", web_to_app_link);
open_qr_in_computer_image_viewer(qr_code_link.clone(), "sign_qr_code")?;
let result = smart_id_client.get_session_status().await?;
let signature = result.signature.unwrap();
Ok(signature.get_value())
}
fn init_tracing() {
SubscriberBuilder::default()
.with_max_level(Level::INFO)
.with_span_events(FmtSpan::CLOSE)
.with_file(true)
.with_line_number(true)
.init();
}
fn open_qr_in_computer_image_viewer(qr_code_link: String, name: &str) -> Result<()> {
let code = QrCode::new(qr_code_link)?;
let image = code.render::<Luma<u8>>().build();
let file_path = format!("{}.png", name);
image.save(file_path.clone())?;
open::that(file_path)?;
Ok(())
}