keyfork-prompt: split on word boundaries for textual prompts

This commit is contained in:
Ryan Heywood 2023-12-28 17:54:38 -05:00
parent df7be182e4
commit f157a8c954
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
4 changed files with 45 additions and 21 deletions

View File

@ -9,6 +9,6 @@ pub fn main() -> Result<()> {
let string = mgr.prompt_wordlist("Mnemonic: ", &Default::default())?;
let mnemonic = Mnemonic::from_str(&string).unwrap();
let entropy = mnemonic.entropy();
mgr.prompt_message(&format!("Your entropy is: {entropy:X?}"))?;
mgr.prompt_message(Message::Text(format!("Your entropy is: {entropy:X?}")))?;
Ok(())
}

View File

@ -31,6 +31,11 @@ pub enum Error {
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub enum Message {
Text(String),
Data(String),
}
pub struct PromptManager<R, W> {
read: BufReader<R>,
write: W,
@ -243,40 +248,59 @@ where
Ok(passphrase)
}
pub fn prompt_message(&mut self, prompt: &str) -> Result<()> {
pub fn prompt_message(&mut self, prompt: Message) -> Result<()> {
let mut terminal = AlternateScreen::new(&mut self.write)?;
let mut terminal = RawMode::new(&mut terminal)?;
loop {
// TODO: split on word boundaries
let (cols, _) = terminal::size()?;
terminal
.queue(terminal::Clear(terminal::ClearType::All))?
.queue(cursor::MoveTo(0, 0))?;
let mut lines = prompt.lines().peekable();
while let Some(line) = lines.next() {
terminal.queue(Print(line))?;
if lines.peek().is_some() {
terminal
.queue(cursor::MoveDown(1))?
.queue(cursor::MoveToColumn(0))?;
use Message::*;
match &prompt {
Text(text) => {
for line in text.lines() {
let mut written_chars = 0;
for word in line.split_whitespace() {
let len = word.len() as u16;
written_chars += len + 1;
if written_chars > cols {
terminal
.queue(cursor::MoveDown(1))?
.queue(cursor::MoveToColumn(0))?;
written_chars = len + 1;
}
terminal.queue(Print(word))?.queue(Print(" "))?;
}
terminal
.queue(cursor::MoveDown(1))?
.queue(cursor::MoveToColumn(0))?;
}
}
Data(data) => {
for line in data.lines() {
terminal
.queue(Print(line))?
.queue(cursor::MoveDown(1))?
.queue(cursor::MoveToColumn(0))?;
}
}
}
terminal
.queue(cursor::DisableBlinking)?
.queue(cursor::MoveDown(1))?
.queue(cursor::MoveToColumn(0))?
.queue(PrintStyledContent(" OK ".negative()))?
.flush()?;
match read()? {
Event::Key(k) => match k.code {
KeyCode::Enter | KeyCode::Char(' ') => break,
KeyCode::Enter | KeyCode::Char(' ') | KeyCode::Char('q') => break,
_ => (),
},
_ => (),
}
}
terminal.queue(cursor::EnableBlinking)?.flush()?;
Ok(())

View File

@ -11,7 +11,7 @@ use aes_gcm::{aead::Aead, aes::cipher::consts::U12, Aes256Gcm, KeyInit, Nonce};
use x25519_dalek::{EphemeralSecret, PublicKey};
use keyfork_mnemonic_util::{Mnemonic, Wordlist};
use keyfork_prompt::PromptManager;
use keyfork_prompt::{PromptManager, Message};
use keyfork_shard::openpgp::{decrypt_one, discover_certs, openpgp::Cert, parse_messages};
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
@ -85,7 +85,7 @@ fn run() -> Result<()> {
let our_mnemonic =
Mnemonic::from_entropy(PublicKey::from(&our_key).as_bytes(), Default::default())?;
// TODO: Encode using `qrencode -t ansiutf8 -m 2`
pm.prompt_message(&format!("Our words: {our_mnemonic}"))?;
pm.prompt_message(Message::Text(format!("Our words: {our_mnemonic}")))?;
let shared_secret = our_key
.diffie_hellman(&PublicKey::from(their_key))
@ -109,7 +109,7 @@ fn run() -> Result<()> {
// safety: size of out_bytes is constant and always % 4 == 0
let mnemonic = unsafe { Mnemonic::from_raw_entropy(&out_bytes, Default::default()) };
pm.prompt_message(&format!("Our payload: {mnemonic}"))?;
pm.prompt_message(Message::Text(format!("Our payload: {mnemonic}")))?;
Ok(())
}

View File

@ -1,6 +1,6 @@
use std::collections::{HashMap, HashSet};
use keyfork_prompt::{default_prompt_manager, DefaultPromptManager, Error as PromptError};
use keyfork_prompt::{default_prompt_manager, DefaultPromptManager, Error as PromptError, Message};
use super::openpgp::{
self,
@ -146,7 +146,7 @@ impl SmartcardManager {
}
#[rustfmt::skip]
self.pm.prompt_message("Please plug in a smart card and press enter")?;
self.pm.prompt_message(Message::Text("Please plug in a smart card and press enter".to_string()))?;
}
Ok(None)
@ -246,7 +246,7 @@ impl DecryptionHelper for &mut SmartcardManager {
pin.replace(temp_pin);
}
Err(CardError::CardStatus(StatusBytes::IncorrectParametersCommandDataField)) => {
self.pm.prompt_message("Invalid PIN length entered.")?;
self.pm.prompt_message(Message::Text("Invalid PIN length entered.".to_string()))?;
}
Err(_) => {}
}