Read password from user in move command

This commit is contained in:
Paul Hauner
2022-12-14 11:55:12 +11:00
parent 6bef2beba4
commit 0abb6a3d60
3 changed files with 47 additions and 5 deletions

View File

@@ -15,6 +15,7 @@ use tree_hash::TreeHash;
use types::*; use types::*;
pub const IGNORE_DUPLICATES_FLAG: &str = "ignore-duplicates"; pub const IGNORE_DUPLICATES_FLAG: &str = "ignore-duplicates";
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
/// When the `ethereum/staking-deposit-cli` tool generates deposit data JSON, it adds a /// When the `ethereum/staking-deposit-cli` tool generates deposit data JSON, it adds a
/// `deposit_cli_version` to protect the web-based "Launchpad" tool against a breaking change that /// `deposit_cli_version` to protect the web-based "Launchpad" tool against a breaking change that

View File

@@ -19,7 +19,6 @@ pub const OUTPUT_PATH_FLAG: &str = "output-path";
pub const DEPOSIT_GWEI_FLAG: &str = "deposit-gwei"; pub const DEPOSIT_GWEI_FLAG: &str = "deposit-gwei";
pub const DISABLE_DEPOSITS_FLAG: &str = "disable-deposits"; pub const DISABLE_DEPOSITS_FLAG: &str = "disable-deposits";
pub const COUNT_FLAG: &str = "count"; pub const COUNT_FLAG: &str = "count";
pub const STDIN_INPUTS_FLAG: &str = "stdin-inputs";
pub const FIRST_INDEX_FLAG: &str = "first-index"; pub const FIRST_INDEX_FLAG: &str = "first-index";
pub const MNEMONIC_FLAG: &str = "mnemonic-path"; pub const MNEMONIC_FLAG: &str = "mnemonic-path";
pub const SPECIFY_VOTING_KEYSTORE_PASSWORD_FLAG: &str = "specify-voting-keystore-password"; pub const SPECIFY_VOTING_KEYSTORE_PASSWORD_FLAG: &str = "specify-voting-keystore-password";

View File

@@ -1,5 +1,6 @@
use super::common::*; use super::common::*;
use crate::DumpConfig; use crate::DumpConfig;
use account_utils::read_password_from_user;
use clap::{App, Arg, ArgMatches}; use clap::{App, Arg, ArgMatches};
use eth2::{ use eth2::{
lighthouse_vc::{ lighthouse_vc::{
@@ -167,6 +168,7 @@ pub struct MoveConfig {
pub builder_proposals: Option<bool>, pub builder_proposals: Option<bool>,
pub fee_recipient: Option<Address>, pub fee_recipient: Option<Address>,
pub gas_limit: Option<u64>, pub gas_limit: Option<u64>,
pub stdin_inputs: bool,
} }
impl MoveConfig { impl MoveConfig {
@@ -180,6 +182,7 @@ impl MoveConfig {
builder_proposals: clap_utils::parse_optional(matches, BUILDER_PROPOSALS_FLAG)?, builder_proposals: clap_utils::parse_optional(matches, BUILDER_PROPOSALS_FLAG)?,
fee_recipient: clap_utils::parse_optional(matches, FEE_RECIPIENT_FLAG)?, fee_recipient: clap_utils::parse_optional(matches, FEE_RECIPIENT_FLAG)?,
gas_limit: clap_utils::parse_optional(matches, GAS_LIMIT_FLAG)?, gas_limit: clap_utils::parse_optional(matches, GAS_LIMIT_FLAG)?,
stdin_inputs: cfg!(windows) || matches.is_present(STDIN_INPUTS_FLAG),
}) })
} }
} }
@@ -206,6 +209,7 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> {
builder_proposals, builder_proposals,
fee_recipient, fee_recipient,
gas_limit, gas_limit,
stdin_inputs,
} = config; } = config;
// Moving validators between the same VC is unlikely to be useful and probably indicates a user // Moving validators between the same VC is unlikely to be useful and probably indicates a user
@@ -346,10 +350,48 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> {
validating_keystore_password, validating_keystore_password,
} => match (validating_keystore, validating_keystore_password) { } => match (validating_keystore, validating_keystore_password) {
(Some(keystore), Some(password)) => (keystore, password), (Some(keystore), Some(password)) => (keystore, password),
(keystore_opt, password_opt) => { (Some(keystore), None) => {
eprintln!(
"Validator {:?} requires a password, please provide it to continue with \
moving validators. If the provided password is incorrect the user will \
be asked to provide another password. \
Failing to provide the correct password now will \
result in the keystore being deleted from the src VC \
without being transfered to the dest VC. \
The dest VC will store this password on its filesystem and it will not be \
required next time the dest VC starts. \
It is strongly recommend to provide a password now rather than exiting.",
pubkey_to_move
);
// Read the password from the user, retrying if the password is incorrect.
loop {
match read_password_from_user(stdin_inputs) {
Ok(password) => {
if let Err(e) = keystore.decrypt_keypair(password.as_ref()) {
eprintln!("Failed to decrypt keystore: {:?}", e);
} else {
break (keystore, password);
}
}
Err(e) => {
eprintln!(
"Retrying after error: {:?}. If this error persists the user will need to \
manually recover their keystore for validator {:?} from the mnemonic."
,
e, pubkey_to_move
);
}
}
// Add a sleep here to prevent spamming the console.
sleep(Duration::from_secs(1)).await;
}
}
(None, password_opt) => {
eprintln!( eprintln!(
"Validator {:?} was not moved since the validator client did \ "Validator {:?} was not moved since the validator client did \
not return both a keystore and password. It is likely that the \ not return a keystore. It is likely that the \
validator has been deleted from the source validator client \ validator has been deleted from the source validator client \
without being moved to the destination validator client. \ without being moved to the destination validator client. \
This validator will most likely need to be manually recovered \ This validator will most likely need to be manually recovered \
@@ -357,8 +399,7 @@ async fn run<'a>(config: MoveConfig) -> Result<(), String> {
pubkey_to_move pubkey_to_move
); );
return Err(format!( return Err(format!(
"VC returned deleted but keystore {}, password {}", "VC returned deleted but keystore not present (password {})",
keystore_opt.is_some(),
password_opt.is_some() password_opt.is_some()
)); ));
} }
@@ -643,6 +684,7 @@ mod test {
builder_proposals: None, builder_proposals: None,
fee_recipient: None, fee_recipient: None,
gas_limit: None, gas_limit: None,
stdin_inputs: false,
}; };
let result = run(move_config).await; let result = run(move_config).await;