webauthn_authenticator_rs/ui/
cli.rs

1use crate::ui::*;
2#[cfg(feature = "qrcode")]
3use qrcode::{render::unicode::Dense1x2, QrCode};
4use std::io::{stderr, Write};
5
6/// Basic CLI [UiCallback] implementation, available with `--features ui-cli`.
7///
8/// This gets input from `stdin` and sends messages to `stderr`.
9///
10/// This is only intended for testing, and doesn't implement much functionality
11/// (like localization).
12///
13/// **Tip**: to get QR codes for `cable` authenticators, enable the `qrcode`
14/// feature.
15#[derive(Debug)]
16pub struct Cli {}
17
18impl UiCallback for Cli {
19    fn request_pin(&self) -> Option<String> {
20        rpassword::prompt_password_stderr("Enter PIN: ").ok()
21    }
22
23    fn request_touch(&self) {
24        let mut stderr = stderr();
25        writeln!(stderr, "Touch the authenticator").ok();
26    }
27
28    fn processing(&self) {
29        let mut stderr = stderr();
30        writeln!(stderr, "Processing...").ok();
31    }
32
33    fn fingerprint_enrollment_feedback(
34        &self,
35        remaining_samples: u32,
36        feedback: Option<EnrollSampleStatus>,
37    ) {
38        let mut stderr = stderr();
39        writeln!(stderr, "Need {remaining_samples} more sample(s)").ok();
40        if let Some(feedback) = feedback {
41            writeln!(stderr, "Last impression was {feedback:?}").ok();
42        }
43    }
44
45    fn cable_qr_code(&self, request_type: CableRequestType, url: String) {
46        match request_type {
47            CableRequestType::DiscoverableMakeCredential | CableRequestType::MakeCredential => {
48                println!("Scan the QR code with your mobile device to create a new credential with caBLE:");
49            }
50            CableRequestType::GetAssertion => {
51                println!("Scan the QR code with your mobile device to sign in with caBLE:");
52            }
53        }
54        println!("This feature requires Android with Google Play, or iOS 16 or later.");
55
56        #[cfg(feature = "qrcode")]
57        {
58            let qr = QrCode::new(&url).expect("Could not create QR code");
59
60            let code = qr
61                .render::<Dense1x2>()
62                .dark_color(Dense1x2::Light)
63                .light_color(Dense1x2::Dark)
64                .build();
65
66            println!("{}", code);
67        }
68
69        #[cfg(not(feature = "qrcode"))]
70        {
71            println!("QR code support not available in this build!")
72        }
73        println!("{url}");
74    }
75
76    fn dismiss_qr_code(&self) {
77        println!("caBLE authenticator detected, connecting...");
78    }
79
80    fn cable_status_update(&self, state: CableState) {
81        println!("caBLE status: {state:?}");
82    }
83}