keyfork-prompt: split on word boundaries for textual prompts
This commit is contained in:
parent
df7be182e4
commit
f157a8c954
|
@ -9,6 +9,6 @@ pub fn main() -> Result<()> {
|
||||||
let string = mgr.prompt_wordlist("Mnemonic: ", &Default::default())?;
|
let string = mgr.prompt_wordlist("Mnemonic: ", &Default::default())?;
|
||||||
let mnemonic = Mnemonic::from_str(&string).unwrap();
|
let mnemonic = Mnemonic::from_str(&string).unwrap();
|
||||||
let entropy = mnemonic.entropy();
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,11 @@ pub enum Error {
|
||||||
|
|
||||||
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
||||||
|
pub enum Message {
|
||||||
|
Text(String),
|
||||||
|
Data(String),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PromptManager<R, W> {
|
pub struct PromptManager<R, W> {
|
||||||
read: BufReader<R>,
|
read: BufReader<R>,
|
||||||
write: W,
|
write: W,
|
||||||
|
@ -243,40 +248,59 @@ where
|
||||||
Ok(passphrase)
|
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 = AlternateScreen::new(&mut self.write)?;
|
||||||
let mut terminal = RawMode::new(&mut terminal)?;
|
let mut terminal = RawMode::new(&mut terminal)?;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// TODO: split on word boundaries
|
let (cols, _) = terminal::size()?;
|
||||||
|
|
||||||
terminal
|
terminal
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
.queue(terminal::Clear(terminal::ClearType::All))?
|
||||||
.queue(cursor::MoveTo(0, 0))?;
|
.queue(cursor::MoveTo(0, 0))?;
|
||||||
let mut lines = prompt.lines().peekable();
|
|
||||||
while let Some(line) = lines.next() {
|
use Message::*;
|
||||||
terminal.queue(Print(line))?;
|
match &prompt {
|
||||||
if lines.peek().is_some() {
|
Text(text) => {
|
||||||
terminal
|
for line in text.lines() {
|
||||||
.queue(cursor::MoveDown(1))?
|
let mut written_chars = 0;
|
||||||
.queue(cursor::MoveToColumn(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
|
terminal
|
||||||
.queue(cursor::DisableBlinking)?
|
.queue(cursor::DisableBlinking)?
|
||||||
.queue(cursor::MoveDown(1))?
|
|
||||||
.queue(cursor::MoveToColumn(0))?
|
|
||||||
.queue(PrintStyledContent(" OK ".negative()))?
|
.queue(PrintStyledContent(" OK ".negative()))?
|
||||||
.flush()?;
|
.flush()?;
|
||||||
|
|
||||||
match read()? {
|
match read()? {
|
||||||
Event::Key(k) => match k.code {
|
Event::Key(k) => match k.code {
|
||||||
KeyCode::Enter | KeyCode::Char(' ') => break,
|
KeyCode::Enter | KeyCode::Char(' ') | KeyCode::Char('q') => break,
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
terminal.queue(cursor::EnableBlinking)?.flush()?;
|
terminal.queue(cursor::EnableBlinking)?.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -11,7 +11,7 @@ use aes_gcm::{aead::Aead, aes::cipher::consts::U12, Aes256Gcm, KeyInit, Nonce};
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
|
|
||||||
use keyfork_mnemonic_util::{Mnemonic, Wordlist};
|
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};
|
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>;
|
type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||||
|
@ -85,7 +85,7 @@ fn run() -> Result<()> {
|
||||||
let our_mnemonic =
|
let our_mnemonic =
|
||||||
Mnemonic::from_entropy(PublicKey::from(&our_key).as_bytes(), Default::default())?;
|
Mnemonic::from_entropy(PublicKey::from(&our_key).as_bytes(), Default::default())?;
|
||||||
// TODO: Encode using `qrencode -t ansiutf8 -m 2`
|
// 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
|
let shared_secret = our_key
|
||||||
.diffie_hellman(&PublicKey::from(their_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
|
// safety: size of out_bytes is constant and always % 4 == 0
|
||||||
let mnemonic = unsafe { Mnemonic::from_raw_entropy(&out_bytes, Default::default()) };
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
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::{
|
use super::openpgp::{
|
||||||
self,
|
self,
|
||||||
|
@ -146,7 +146,7 @@ impl SmartcardManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
#[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)
|
Ok(None)
|
||||||
|
@ -246,7 +246,7 @@ impl DecryptionHelper for &mut SmartcardManager {
|
||||||
pin.replace(temp_pin);
|
pin.replace(temp_pin);
|
||||||
}
|
}
|
||||||
Err(CardError::CardStatus(StatusBytes::IncorrectParametersCommandDataField)) => {
|
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(_) => {}
|
Err(_) => {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue