cli: Confirm recovered pubkeys (#7316)
* cli: Confirm recovered pubkeys * cargo clippy
This commit is contained in:
parent
b7d4330dd4
commit
186709ed75
|
@ -36,7 +36,7 @@ pub fn keypair_of(matches: &ArgMatches<'_>, name: &str) -> Option<Keypair> {
|
|||
if let Some(value) = matches.value_of(name) {
|
||||
if value == ASK_KEYWORD {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
keypair_from_seed_phrase(name, skip_validation).ok()
|
||||
keypair_from_seed_phrase(name, skip_validation, true).ok()
|
||||
} else {
|
||||
read_keypair_file(value).ok()
|
||||
}
|
||||
|
|
|
@ -2,11 +2,18 @@ use crate::ArgConstant;
|
|||
use bip39::{Language, Mnemonic, Seed};
|
||||
use clap::values_t;
|
||||
use rpassword::prompt_password_stderr;
|
||||
use solana_sdk::signature::{
|
||||
use solana_sdk::{
|
||||
pubkey::Pubkey,
|
||||
signature::{
|
||||
keypair_from_seed, keypair_from_seed_phrase_and_passphrase, read_keypair_file, Keypair,
|
||||
KeypairUtil,
|
||||
},
|
||||
};
|
||||
use std::{
|
||||
error,
|
||||
io::{stdin, stdout, Write},
|
||||
process::exit,
|
||||
};
|
||||
use std::error;
|
||||
|
||||
// Keyword used to indicate that the user should be asked for a keypair seed phrase
|
||||
pub const ASK_KEYWORD: &str = "ASK";
|
||||
|
@ -54,9 +61,12 @@ pub fn prompt_passphrase(prompt: &str) -> Result<String, Box<dyn error::Error>>
|
|||
}
|
||||
|
||||
/// Reads user input from stdin to retrieve a seed phrase and passphrase for keypair derivation
|
||||
/// Optionally skips validation of seed phrase
|
||||
/// Optionally confirms recovered public key
|
||||
pub fn keypair_from_seed_phrase(
|
||||
keypair_name: &str,
|
||||
skip_validation: bool,
|
||||
confirm_pubkey: bool,
|
||||
) -> Result<Keypair, Box<dyn error::Error>> {
|
||||
let seed_phrase = prompt_password_stderr(&format!("[{}] seed phrase: ", keypair_name))?;
|
||||
let seed_phrase = seed_phrase.trim();
|
||||
|
@ -65,18 +75,32 @@ pub fn keypair_from_seed_phrase(
|
|||
keypair_name,
|
||||
);
|
||||
|
||||
if skip_validation {
|
||||
let keypair = if skip_validation {
|
||||
let passphrase = prompt_passphrase(&passphrase_prompt)?;
|
||||
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)
|
||||
keypair_from_seed_phrase_and_passphrase(&seed_phrase, &passphrase)?
|
||||
} else {
|
||||
let sanitized = sanitize_seed_phrase(seed_phrase);
|
||||
let mnemonic = Mnemonic::from_phrase(sanitized, Language::English)?;
|
||||
let passphrase = prompt_passphrase(&passphrase_prompt)?;
|
||||
let seed = Seed::new(&mnemonic, &passphrase);
|
||||
keypair_from_seed(seed.as_bytes())
|
||||
keypair_from_seed(seed.as_bytes())?
|
||||
};
|
||||
|
||||
if confirm_pubkey {
|
||||
let pubkey = Pubkey::new(keypair.public.as_ref());
|
||||
print!("Recovered pubkey `{:?}`. Continue? (y/n): ", pubkey);
|
||||
let _ignored = stdout().flush();
|
||||
let mut input = String::new();
|
||||
stdin().read_line(&mut input).expect("Unexpected input");
|
||||
if input.to_lowercase().trim() != "y" {
|
||||
println!("Exiting");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(keypair)
|
||||
}
|
||||
|
||||
/// Checks CLI arguments to determine whether a keypair should be:
|
||||
/// - inputted securely via stdin,
|
||||
/// - read in from a file,
|
||||
|
@ -104,7 +128,7 @@ pub fn keypair_input(
|
|||
}
|
||||
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
keypair_from_seed_phrase(keypair_name, skip_validation)
|
||||
keypair_from_seed_phrase(keypair_name, skip_validation, true)
|
||||
.map(|keypair| KeypairWithSource::new(keypair, Source::SeedPhrase))
|
||||
} else if let Some(keypair_file) = matches.value_of(keypair_match_name) {
|
||||
read_keypair_file(keypair_file).map(|keypair| KeypairWithSource::new(keypair, Source::File))
|
||||
|
|
|
@ -52,7 +52,7 @@ fn get_keypair_from_matches(matches: &ArgMatches) -> Result<Keypair, Box<dyn err
|
|||
read_keypair(&mut stdin)
|
||||
} else if infile == ASK_KEYWORD {
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
keypair_from_seed_phrase("pubkey recovery", skip_validation)
|
||||
keypair_from_seed_phrase("pubkey recovery", skip_validation, false)
|
||||
} else {
|
||||
read_keypair_file(infile)
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ fn main() -> Result<(), Box<dyn error::Error>> {
|
|||
}
|
||||
|
||||
let skip_validation = matches.is_present(SKIP_SEED_PHRASE_VALIDATION_ARG.name);
|
||||
let keypair = keypair_from_seed_phrase("recover", skip_validation)?;
|
||||
let keypair = keypair_from_seed_phrase("recover", skip_validation, true)?;
|
||||
output_keypair(&keypair, &outfile, "recovered")?;
|
||||
}
|
||||
("grind", Some(matches)) => {
|
||||
|
|
Loading…
Reference in New Issue