keyfork: impl basic `recover mnemonic`
This commit is contained in:
parent
d2965745e8
commit
c5d1a6d62c
|
@ -21,9 +21,14 @@ pub enum RecoverSubcommands {
|
|||
/// Combine remotely decrypted shards. The shards should be sent using the command `keyfork
|
||||
/// shard transport`.
|
||||
RemoteShard {},
|
||||
|
||||
/// Read a mnemonic from input.
|
||||
Mnemonic {},
|
||||
}
|
||||
|
||||
impl RecoverSubcommands {
|
||||
/// Return the 128-bit or 256-bit entropy for a bip39 mnemonic. This is _not_ the same as the
|
||||
/// 512-bit seed used by bip32.
|
||||
fn handle(&self) -> Result<Vec<u8>> {
|
||||
match self {
|
||||
RecoverSubcommands::Shard {
|
||||
|
@ -51,6 +56,27 @@ impl RecoverSubcommands {
|
|||
remote_decrypt(&mut seed)?;
|
||||
Ok(seed)
|
||||
}
|
||||
RecoverSubcommands::Mnemonic {} => {
|
||||
use keyfork_prompt::{
|
||||
default_terminal,
|
||||
validators::{
|
||||
mnemonic::{MnemonicChoiceValidator, WordLength},
|
||||
Validator,
|
||||
},
|
||||
PromptHandler,
|
||||
};
|
||||
let mut term = default_terminal()?;
|
||||
let validator = MnemonicChoiceValidator {
|
||||
word_lengths: [WordLength::Count(12), WordLength::Count(24)],
|
||||
};
|
||||
let mnemonic = term.prompt_validated_wordlist(
|
||||
"Mnemonic: ",
|
||||
&Default::default(),
|
||||
3,
|
||||
validator.to_fn(),
|
||||
)?;
|
||||
Ok(mnemonic.entropy())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -142,6 +142,47 @@ pub mod mnemonic {
|
|||
}
|
||||
}
|
||||
|
||||
/// A mnemonic of a given choice of lengths. For example, a 128-bit or 256-bit bip32 seed.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum MnemonicChoiceValidationError {
|
||||
/// The provided mnemonic did not match any of the valid ranges.
|
||||
#[error("Invalid word length: {0} was not in any {1:?}")]
|
||||
InvalidLength(usize, Vec<WordLength>),
|
||||
|
||||
/// A mnemonic could not be parsed from the provided mnemonic.
|
||||
#[error("{0}")]
|
||||
MnemonicFromStrError(#[from] MnemonicFromStrError),
|
||||
}
|
||||
|
||||
/// Validate a single mnemonic against a set of possible word lengths.
|
||||
#[derive(Clone)]
|
||||
pub struct MnemonicChoiceValidator<const N: usize> {
|
||||
/// The accepted [`WordLength`] of the mnemonic.
|
||||
pub word_lengths: [WordLength; N],
|
||||
}
|
||||
|
||||
impl<const N: usize> Validator for MnemonicChoiceValidator<N> {
|
||||
type Output = Mnemonic;
|
||||
type Error = MnemonicChoiceValidationError;
|
||||
|
||||
fn to_fn(&self) -> Box<dyn Fn(String) -> Result<Self::Output, Self::Error>> {
|
||||
let word_lengths = self.word_lengths.clone();
|
||||
Box::new(move |s: String| {
|
||||
let count = s.split_whitespace().count();
|
||||
for word_length in &word_lengths {
|
||||
if word_length.matches(count) {
|
||||
let m = Mnemonic::from_str(&s)?;
|
||||
return Ok(m);
|
||||
}
|
||||
}
|
||||
Err(MnemonicChoiceValidationError::InvalidLength(
|
||||
count,
|
||||
word_lengths.to_vec(),
|
||||
))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// A mnemonic in the set of mnemonics could not be validated from the given inputs.
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum MnemonicSetValidationError {
|
||||
|
|
Loading…
Reference in New Issue