1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::ui::*;
#[cfg(feature = "qrcode")]
use qrcode::{render::unicode::Dense1x2, QrCode};
use std::io::{stderr, Write};

/// Basic CLI [UiCallback] implementation, available with `--features ui-cli`.
///
/// This gets input from `stdin` and sends messages to `stderr`.
///
/// This is only intended for testing, and doesn't implement much functionality
/// (like localization).
///
/// **Tip**: to get QR codes for `cable` authenticators, enable the `qrcode`
/// feature.
#[derive(Debug)]
pub struct Cli {}

impl UiCallback for Cli {
    fn request_pin(&self) -> Option<String> {
        rpassword::prompt_password_stderr("Enter PIN: ").ok()
    }

    fn request_touch(&self) {
        let mut stderr = stderr();
        writeln!(stderr, "Touch the authenticator").ok();
    }

    fn processing(&self) {
        let mut stderr = stderr();
        writeln!(stderr, "Processing...").ok();
    }

    fn fingerprint_enrollment_feedback(
        &self,
        remaining_samples: u32,
        feedback: Option<EnrollSampleStatus>,
    ) {
        let mut stderr = stderr();
        writeln!(stderr, "Need {remaining_samples} more sample(s)").ok();
        if let Some(feedback) = feedback {
            writeln!(stderr, "Last impression was {feedback:?}").ok();
        }
    }

    fn cable_qr_code(&self, request_type: CableRequestType, url: String) {
        match request_type {
            CableRequestType::DiscoverableMakeCredential | CableRequestType::MakeCredential => {
                println!("Scan the QR code with your mobile device to create a new credential with caBLE:");
            }
            CableRequestType::GetAssertion => {
                println!("Scan the QR code with your mobile device to sign in with caBLE:");
            }
        }
        println!("This feature requires Android with Google Play, or iOS 16 or later.");

        #[cfg(feature = "qrcode")]
        {
            let qr = QrCode::new(&url).expect("Could not create QR code");

            let code = qr
                .render::<Dense1x2>()
                .dark_color(Dense1x2::Light)
                .light_color(Dense1x2::Dark)
                .build();

            println!("{}", code);
        }

        #[cfg(not(feature = "qrcode"))]
        {
            println!("QR code support not available in this build!")
        }
        println!("{url}");
    }

    fn dismiss_qr_code(&self) {
        println!("caBLE authenticator detected, connecting...");
    }

    fn cable_status_update(&self, state: CableState) {
        println!("caBLE status: {state:?}");
    }
}