diff options
Diffstat (limited to 'third_party/rust/authenticator/examples/reset.rs')
-rw-r--r-- | third_party/rust/authenticator/examples/reset.rs | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/third_party/rust/authenticator/examples/reset.rs b/third_party/rust/authenticator/examples/reset.rs new file mode 100644 index 0000000000..1194cb2b06 --- /dev/null +++ b/third_party/rust/authenticator/examples/reset.rs @@ -0,0 +1,140 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use authenticator::{ + authenticatorservice::AuthenticatorService, + ctap2::commands::StatusCode, + errors::{AuthenticatorError, CommandError, HIDError}, + statecallback::StateCallback, + StatusUpdate, +}; +use getopts::Options; +use std::env; +use std::sync::mpsc::{channel, RecvError}; + +fn print_usage(program: &str, opts: Options) { + let brief = format!("Usage: {program} [options]"); + print!("{}", opts.usage(&brief)); +} + +fn main() { + env_logger::init(); + + let args: Vec<String> = env::args().collect(); + let program = args[0].clone(); + + let mut opts = Options::new(); + opts.optflag("x", "no-u2f-usb-hid", "do not enable u2f-usb-hid platforms"); + opts.optflag("h", "help", "print this help menu").optopt( + "t", + "timeout", + "timeout in seconds", + "SEC", + ); + opts.optflag("h", "help", "print this help menu"); + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => panic!("{}", f.to_string()), + }; + if matches.opt_present("help") { + print_usage(&program, opts); + return; + } + + let mut manager = AuthenticatorService::new() + .expect("The auth service should initialize safely"); + + if !matches.opt_present("no-u2f-usb-hid") { + manager.add_u2f_usb_hid_platform_transports(); + } + + let timeout_ms = match matches.opt_get_default::<u64>("timeout", 25) { + Ok(timeout_s) => { + println!("Using {}s as the timeout", &timeout_s); + timeout_s * 1_000 + } + Err(e) => { + println!("{e}"); + print_usage(&program, opts); + return; + } + }; + + println!( + "NOTE: Please unplug all devices, type in 'yes' and plug in the device that should be reset." + ); + loop { + let mut s = String::new(); + println!("ATTENTION: Resetting a device will wipe all credentials! Do you wish to continue? [yes/N]"); + std::io::stdin() + .read_line(&mut s) + .expect("Did not enter a correct string"); + let trimmed = s.trim(); + if trimmed.is_empty() || trimmed == "N" || trimmed == "n" { + println!("Exiting without reset."); + return; + } + if trimmed == "y" { + println!("Please type in the whole word 'yes'"); + continue; + } + if trimmed == "yes" { + break; + } + } + + let (status_tx, status_rx) = channel::<StatusUpdate>(); + let (reset_tx, reset_rx) = channel(); + let rs_tx = reset_tx; + let callback = StateCallback::new(Box::new(move |rv| { + let _ = rs_tx.send(rv); + })); + + if let Err(e) = manager.reset(timeout_ms, status_tx, callback) { + panic!("Couldn't register: {:?}", e); + }; + + loop { + match status_rx.recv() { + Ok(StatusUpdate::SelectDeviceNotice) => { + println!("ERROR: Please unplug all other tokens that should not be reset!"); + // Needed to give the tokens enough time to start blinking + // otherwise we may cancel pre-maturely and this binary will hang + std::thread::sleep(std::time::Duration::from_millis(200)); + manager.cancel().unwrap(); + return; + } + Ok(StatusUpdate::DeviceSelected(dev_info)) => { + println!("STATUS: Continuing with device: {dev_info}"); + } + Ok(StatusUpdate::PresenceRequired) => { + println!("STATUS: waiting for user presence"); + break; + } + Ok(StatusUpdate::PinUvError(..)) => panic!("Reset should never ask for a PIN!"), + Ok(_) => { /* Ignore all other updates */ } + Err(RecvError) => { + println!("RecvError"); + return; + } + } + } + + let reset_result = reset_rx + .recv() + .expect("Problem receiving, unable to continue"); + match reset_result { + Ok(()) => { + println!("Token successfully reset!"); + } + Err(AuthenticatorError::HIDError(HIDError::Command(CommandError::StatusCode( + StatusCode::NotAllowed, + _, + )))) => { + println!("Resetting is only allowed within the first 10 seconds after powering up."); + println!("Please unplug your device, plug it back in and try again."); + } + Err(e) => panic!("Reset failed: {:?}", e), + }; +} |