Compare commits
No commits in common. "6c25cb8f31886697640eeb6b629c28aa5e2d6678" and "920e04ba23868e5b25c919c35e849befa762a894" have entirely different histories.
6c25cb8f31
...
920e04ba23
|
@ -1078,7 +1078,6 @@ name = "keyfork-prompt"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"keyfork-mnemonic-util",
|
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -64,13 +64,8 @@ impl Wordlist {
|
||||||
Arc::new(self)
|
Arc::new(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether the Wordlist contains a given word.
|
|
||||||
pub fn contains(&self, word: &str) -> bool {
|
|
||||||
self.0.iter().any(|w| w.as_str() == word)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given an index, get a word from the wordlist.
|
/// Given an index, get a word from the wordlist.
|
||||||
pub fn get_word(&self, word: usize) -> Option<&String> {
|
fn get_word(&self, word: usize) -> Option<&String> {
|
||||||
self.0.get(word)
|
self.0.get(word)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,6 @@ edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[features]
|
|
||||||
default = ["mnemonic"]
|
|
||||||
mnemonic = ["keyfork-mnemonic-util"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = { version = "0.27.0", default-features = false, features = ["use-dev-tty", "events"] }
|
crossterm = { version = "0.27.0", default-features = false, features = ["use-dev-tty", "events"] }
|
||||||
keyfork-mnemonic-util = { version = "0.1.0", path = "../keyfork-mnemonic-util", optional = true }
|
|
||||||
thiserror = "1.0.51"
|
thiserror = "1.0.51"
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use std::{io::{stdin, stdout}, str::FromStr};
|
use std::io::{stdin, stdout};
|
||||||
|
|
||||||
use keyfork_prompt::*;
|
use keyfork_prompt::*;
|
||||||
use keyfork_mnemonic_util::Mnemonic;
|
|
||||||
|
|
||||||
pub fn main() -> Result<()> {
|
pub fn main() -> Result<()> {
|
||||||
let mut mgr = PromptManager::new(stdin(), stdout())?;
|
let mut mgr = PromptManager::new(stdin(), stdout())?;
|
||||||
|
mgr.prompt_input("Mnemonic: ")?;
|
||||||
|
mgr.prompt_message("Please press enter.")?;
|
||||||
mgr.prompt_passphrase("Passphrase: ")?;
|
mgr.prompt_passphrase("Passphrase: ")?;
|
||||||
let string = mgr.prompt_wordlist("Mnemonic: ", &Default::default())?;
|
mgr.prompt_message("Please press space bar.")?;
|
||||||
let mnemonic = Mnemonic::from_str(&string).unwrap();
|
|
||||||
let entropy = mnemonic.entropy();
|
|
||||||
mgr.prompt_message(&format!("Your entropy is: {entropy:X?}"))?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,6 @@ use std::{
|
||||||
os::fd::AsRawFd,
|
os::fd::AsRawFd,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "mnemonic")]
|
|
||||||
use keyfork_mnemonic_util::Wordlist;
|
|
||||||
|
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
cursor,
|
cursor,
|
||||||
event::{read, Event, KeyCode},
|
event::{read, Event, KeyCode},
|
||||||
|
@ -72,104 +69,6 @@ where
|
||||||
Ok(line)
|
Ok(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "mnemonic")]
|
|
||||||
pub fn prompt_wordlist(&mut self, prompt: &str, wordlist: &Wordlist) -> Result<String> {
|
|
||||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
|
||||||
let mut terminal = RawMode::new(&mut terminal)?;
|
|
||||||
|
|
||||||
terminal
|
|
||||||
.queue(terminal::Clear(terminal::ClearType::All))?
|
|
||||||
.queue(cursor::MoveTo(0, 0))?;
|
|
||||||
let mut lines = prompt.lines().peekable();
|
|
||||||
let mut prefix_length = 0;
|
|
||||||
while let Some(line) = lines.next() {
|
|
||||||
prefix_length = line.len();
|
|
||||||
terminal.queue(Print(line))?;
|
|
||||||
if lines.peek().is_some() {
|
|
||||||
terminal
|
|
||||||
.queue(cursor::MoveDown(1))?
|
|
||||||
.queue(cursor::MoveToColumn(0))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
terminal.flush()?;
|
|
||||||
|
|
||||||
let (mut cols, mut _rows) = terminal::size()?;
|
|
||||||
let mut input = String::new();
|
|
||||||
|
|
||||||
loop {
|
|
||||||
match read()? {
|
|
||||||
Event::Resize(new_cols, new_rows) => {
|
|
||||||
cols = new_cols;
|
|
||||||
_rows = new_rows;
|
|
||||||
}
|
|
||||||
Event::Key(k) => match k.code {
|
|
||||||
KeyCode::Enter => {
|
|
||||||
input.push('\n');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
KeyCode::Backspace => {
|
|
||||||
input.pop();
|
|
||||||
}
|
|
||||||
KeyCode::Char(' ') => {
|
|
||||||
if !input.chars().rev().next().is_some_and(char::is_whitespace) {
|
|
||||||
input.push(' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
KeyCode::Char(c) => {
|
|
||||||
input.push(c);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
},
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
|
|
||||||
let usable_space = cols as usize - prefix_length - 1;
|
|
||||||
|
|
||||||
terminal
|
|
||||||
.queue(cursor::MoveToColumn(prefix_length as u16))?
|
|
||||||
.queue(terminal::Clear(terminal::ClearType::UntilNewLine))?
|
|
||||||
.flush()?;
|
|
||||||
|
|
||||||
let printable_input_start = if input.len() > usable_space {
|
|
||||||
let start_index = input.len() - usable_space;
|
|
||||||
input
|
|
||||||
.chars()
|
|
||||||
.enumerate()
|
|
||||||
.skip(start_index)
|
|
||||||
.skip_while(|(_, ch)| !ch.is_whitespace())
|
|
||||||
.next()
|
|
||||||
.expect("any printable character")
|
|
||||||
.0
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
|
||||||
|
|
||||||
let printable_input = &input[printable_input_start..];
|
|
||||||
let mut iter = printable_input.split_whitespace().peekable();
|
|
||||||
|
|
||||||
while let Some(word) = iter.next() {
|
|
||||||
if wordlist.contains(word) {
|
|
||||||
terminal.queue(PrintStyledContent(word.green()))?;
|
|
||||||
} else {
|
|
||||||
terminal.queue(PrintStyledContent(word.red()))?;
|
|
||||||
}
|
|
||||||
if iter.peek().is_some()
|
|
||||||
|| printable_input
|
|
||||||
.chars()
|
|
||||||
.rev()
|
|
||||||
.next()
|
|
||||||
.is_some_and(char::is_whitespace)
|
|
||||||
{
|
|
||||||
terminal.queue(Print(" "))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
terminal.flush()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: return secrecy::Secret<String>
|
// TODO: return secrecy::Secret<String>
|
||||||
pub fn prompt_passphrase(&mut self, prompt: &str) -> Result<String> {
|
pub fn prompt_passphrase(&mut self, prompt: &str) -> Result<String> {
|
||||||
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
let mut terminal = AlternateScreen::new(&mut self.write)?;
|
||||||
|
@ -179,9 +78,7 @@ where
|
||||||
.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();
|
let mut lines = prompt.lines().peekable();
|
||||||
let mut prefix_length = 0;
|
|
||||||
while let Some(line) = lines.next() {
|
while let Some(line) = lines.next() {
|
||||||
prefix_length = line.len();
|
|
||||||
terminal.queue(Print(line))?;
|
terminal.queue(Print(line))?;
|
||||||
if lines.peek().is_some() {
|
if lines.peek().is_some() {
|
||||||
terminal
|
terminal
|
||||||
|
@ -191,25 +88,16 @@ where
|
||||||
}
|
}
|
||||||
terminal.flush()?;
|
terminal.flush()?;
|
||||||
|
|
||||||
let (mut cols, mut _rows) = terminal::size()?;
|
|
||||||
|
|
||||||
let mut passphrase = String::new();
|
let mut passphrase = String::new();
|
||||||
loop {
|
loop {
|
||||||
match read()? {
|
match read()? {
|
||||||
Event::Resize(new_cols, new_rows) => {
|
|
||||||
cols = new_cols;
|
|
||||||
_rows = new_rows;
|
|
||||||
}
|
|
||||||
Event::Key(k) => match k.code {
|
Event::Key(k) => match k.code {
|
||||||
KeyCode::Enter => {
|
KeyCode::Enter => {
|
||||||
passphrase.push('\n');
|
passphrase.push('\n');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
KeyCode::Backspace => {
|
KeyCode::Backspace => {
|
||||||
let passphrase_len = passphrase.len();
|
if passphrase.pop().is_some() {
|
||||||
if passphrase.pop().is_some()
|
|
||||||
&& prefix_length + passphrase_len < cols as usize
|
|
||||||
{
|
|
||||||
terminal
|
terminal
|
||||||
.queue(cursor::MoveLeft(1))?
|
.queue(cursor::MoveLeft(1))?
|
||||||
.queue(Print(" "))?
|
.queue(Print(" "))?
|
||||||
|
@ -218,9 +106,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Char(c) => {
|
KeyCode::Char(c) => {
|
||||||
if prefix_length + passphrase.len() < (cols - 1) as usize {
|
terminal.queue(Print("*"))?.flush()?;
|
||||||
terminal.queue(Print("*"))?.flush()?;
|
|
||||||
}
|
|
||||||
passphrase.push(c);
|
passphrase.push(c);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
Loading…
Reference in New Issue