summaryrefslogtreecommitdiffstats
path: root/third_party/rust/authenticator/examples/reset.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/authenticator/examples/reset.rs')
-rw-r--r--third_party/rust/authenticator/examples/reset.rs140
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),
+ };
+}