From e7be91bdd40260dde8160c45134319d5e6f1ec64 Mon Sep 17 00:00:00 2001 From: ryan Date: Fri, 18 Apr 2025 17:12:28 -0400 Subject: [PATCH] keyfork-{shard,prompt}: add Yes/No prompt for verifying QR codes --- crates/keyfork-shard/src/lib.rs | 18 +++++++++++++---- crates/util/keyfork-prompt/src/lib.rs | 28 +++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/crates/keyfork-shard/src/lib.rs b/crates/keyfork-shard/src/lib.rs index 658f2a2..5fdf606 100644 --- a/crates/keyfork-shard/src/lib.rs +++ b/crates/keyfork-shard/src/lib.rs @@ -23,7 +23,7 @@ use keyfork_prompt::{ mnemonic::{MnemonicSetValidator, MnemonicValidator, WordLength}, Validator, }, - Message as PromptMessage, PromptHandler, + Message as PromptMessage, PromptHandler, YesNo, }; use sha2::{Digest, Sha256}; use x25519_dalek::{EphemeralSecret, PublicKey}; @@ -300,9 +300,19 @@ pub trait Format { let small_mnemonic = Mnemonic::from_raw_bytes(small_sum); let mut prompt = prompt.lock().expect(bug!(POISONED_MUTEX)); - prompt.prompt_message(PromptMessage::Text(format!( - "Is THIS your card???? If not, press ctrl+c!: {small_mnemonic}" - )))?; + let question = + format!("Do these words match the expected words? {small_mnemonic}"); + let response = keyfork_prompt::prompt_choice( + &mut **prompt, + &question, + &[YesNo::No, YesNo::Yes], + )?; + if response == YesNo::No { + prompt.prompt_message(PromptMessage::Text(String::from( + "Could not establish secure channel, exiting.", + )))?; + std::process::exit(1); + } pubkey_data = Some(data); break; diff --git a/crates/util/keyfork-prompt/src/lib.rs b/crates/util/keyfork-prompt/src/lib.rs index 79a0ddd..74f15be 100644 --- a/crates/util/keyfork-prompt/src/lib.rs +++ b/crates/util/keyfork-prompt/src/lib.rs @@ -83,6 +83,34 @@ impl Choice for &T { } } +/// A Yes/No Choice. +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum YesNo { + /// Yes. + Yes, + + /// No. + No, +} + +impl std::fmt::Display for YesNo { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + YesNo::Yes => f.write_str("Yes"), + YesNo::No => f.write_str("No"), + } + } +} + +impl Choice for YesNo { + fn identifier(&self) -> Option { + match self { + YesNo::Yes => Some('y'), + YesNo::No => Some('n'), + } + } +} + #[doc(hidden)] pub type BoxResult = std::result::Result<(), Box>;