diff --git a/src/bin/cmd/wallet_args.rs b/src/bin/cmd/wallet_args.rs index 3bd8d24f1..8afca3c25 100644 --- a/src/bin/cmd/wallet_args.rs +++ b/src/bin/cmd/wallet_args.rs @@ -74,6 +74,33 @@ fn prompt_password_confirm() -> String { first } +fn prompt_replace_seed() -> Result { + let interface = Arc::new(Interface::new("replace_seed")?); + interface.set_report_signal(Signal::Interrupt, true); + interface.set_prompt("Replace seed? (y/n)> ")?; + println!(); + println!("Existing wallet.seed file already exists. Continue?"); + println!("Continuing will back up your existing 'wallet.seed' file as 'wallet.seed.bak'"); + println!(); + loop { + let res = interface.read_line()?; + match res { + ReadResult::Eof => return Ok(false), + ReadResult::Signal(sig) => { + if sig == Signal::Interrupt { + interface.cancel_read_line()?; + return Err(ParseError::CancelledError); + } + } + ReadResult::Input(line) => match line.trim() { + "Y" | "y" => return Ok(true), + "N" | "n" => return Ok(false), + _ => println!("Please respond y or n"), + }, + } + } +} + fn prompt_recovery_phrase() -> Result { let interface = Arc::new(Interface::new("recover")?); let mut phrase = String::new(); @@ -219,6 +246,7 @@ pub fn parse_init_args( } pub fn parse_recover_args( + config: &WalletConfig, g_args: &command::GlobalArgs, args: &ArgMatches, ) -> Result { @@ -226,6 +254,16 @@ pub fn parse_recover_args( match args.is_present("display") { true => (prompt_password(&g_args.password), None), false => { + let cont = { + if command::wallet_seed_exists(config).is_err() { + prompt_replace_seed()? + } else { + true + } + }; + if !cont { + return Err(ParseError::CancelledError); + } let phrase = prompt_recovery_phrase()?; println!("Please provide a new password for the recovered wallet"); (prompt_password_confirm(), Some(phrase.to_owned())) @@ -482,7 +520,11 @@ pub fn wallet_command( command::init(&global_wallet_args, a) } ("recover", Some(args)) => { - let a = arg_parse!(parse_recover_args(&global_wallet_args, &args)); + let a = arg_parse!(parse_recover_args( + &wallet_config, + &global_wallet_args, + &args + )); command::recover(&wallet_config, a) } ("listen", Some(args)) => { diff --git a/wallet/src/command.rs b/wallet/src/command.rs index 25c65fb6d..22b533b88 100644 --- a/wallet/src/command.rs +++ b/wallet/src/command.rs @@ -72,6 +72,12 @@ pub struct RecoverArgs { pub passphrase: String, } +/// Check whether seed file exists +pub fn wallet_seed_exists(config: &WalletConfig) -> Result<(), Error> { + let res = WalletSeed::seed_file_exists(&config)?; + Ok(res) +} + pub fn recover(config: &WalletConfig, args: RecoverArgs) -> Result<(), Error> { if args.recovery_phrase.is_none() { let res = WalletSeed::from_file(config, &args.passphrase); diff --git a/wallet/src/types.rs b/wallet/src/types.rs index 7cb5a78c1..d0090ebba 100644 --- a/wallet/src/types.rs +++ b/wallet/src/types.rs @@ -152,6 +152,36 @@ impl WalletSeed { Ok(()) } + pub fn backup_seed(wallet_config: &WalletConfig) -> Result<(), Error> { + let seed_file_name = &format!( + "{}{}{}", + wallet_config.data_file_dir, MAIN_SEPARATOR, SEED_FILE, + ); + + let mut path = Path::new(seed_file_name).to_path_buf(); + path.pop(); + let mut backup_seed_file_name = format!( + "{}{}{}.bak", + wallet_config.data_file_dir, MAIN_SEPARATOR, SEED_FILE + ); + let mut i = 1; + while Path::new(&backup_seed_file_name).exists() { + backup_seed_file_name = format!( + "{}{}{}.bak.{}", + wallet_config.data_file_dir, MAIN_SEPARATOR, SEED_FILE, i + ); + i += 1; + } + path.push(backup_seed_file_name.clone()); + if let Err(_) = fs::rename(seed_file_name, backup_seed_file_name.as_str()) { + return Err(ErrorKind::GenericError( + "Can't rename wallet seed file".to_owned(), + ))?; + } + warn!("{} backed up as {}", seed_file_name, backup_seed_file_name); + Ok(()) + } + pub fn recover_from_phrase( wallet_config: &WalletConfig, word_list: &str, @@ -161,7 +191,9 @@ impl WalletSeed { "{}{}{}", wallet_config.data_file_dir, MAIN_SEPARATOR, SEED_FILE, ); - let _ = WalletSeed::seed_file_exists(wallet_config)?; + if WalletSeed::seed_file_exists(wallet_config).is_err() { + WalletSeed::backup_seed(wallet_config)?; + } let seed = WalletSeed::from_mnemonic(word_list)?; let enc_seed = EncryptedWalletSeed::from_seed(&seed, password)?; let enc_seed_json = serde_json::to_string_pretty(&enc_seed).context(ErrorKind::Format)?;