mirror of
https://github.com/Qortal/piratewallet-light-cli.git
synced 2025-01-30 18:42:15 +00:00
Improve recovery
This commit is contained in:
parent
f50b86ed1e
commit
664e9512bb
@ -27,6 +27,10 @@ macro_rules! configure_clapapp {
|
||||
.long("recover")
|
||||
.help("Attempt to recover the seed from the wallet")
|
||||
.takes_value(false))
|
||||
.arg(Arg::with_name("password")
|
||||
.long("password")
|
||||
.help("When recovering seed, specify a password for the encrypted wallet")
|
||||
.takes_value(true))
|
||||
.arg(Arg::with_name("seed")
|
||||
.short("s")
|
||||
.long("seed")
|
||||
@ -234,7 +238,7 @@ pub fn command_loop(lightclient: Arc<LightClient>) -> (Sender<(String, Vec<Strin
|
||||
(command_tx, resp_rx)
|
||||
}
|
||||
|
||||
pub fn attempt_recover_seed() {
|
||||
pub fn attempt_recover_seed(password: Option<String>) {
|
||||
// Create a Light Client Config in an attempt to recover the file.
|
||||
let config = LightClientConfig {
|
||||
server: "0.0.0.0:0".parse().unwrap(),
|
||||
@ -246,7 +250,7 @@ pub fn attempt_recover_seed() {
|
||||
data_dir: None,
|
||||
};
|
||||
|
||||
match LightClient::attempt_recover_seed(&config) {
|
||||
match LightClient::attempt_recover_seed(&config, password) {
|
||||
Ok(seed) => println!("Recovered seed: '{}'", seed),
|
||||
Err(e) => eprintln!("Failed to recover seed. Error: {}", e)
|
||||
};
|
||||
|
@ -13,9 +13,10 @@ pub fn main() {
|
||||
let fresh_app = App::new("Zecwallet CLI");
|
||||
let configured_app = configure_clapapp!(fresh_app);
|
||||
let matches = configured_app.get_matches();
|
||||
|
||||
if matches.is_present("recover") {
|
||||
// Create a Light Client Config in an attempt to recover the file.
|
||||
attempt_recover_seed();
|
||||
attempt_recover_seed(matches.value_of("password").map(|s| s.to_string()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -55,8 +56,9 @@ pub fn main() {
|
||||
let (command_tx, resp_rx) = match startup(server, dangerous, seed, birthday, !nosync, command.is_none()) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("Error during startup: {}", e);
|
||||
error!("Error during startup: {}", e);
|
||||
let emsg = format!("Error during startup:{}\nIf you repeatedly run into this issue, you might have to restore your wallet from your seed phrase.", e);
|
||||
eprintln!("{}", emsg);
|
||||
error!("{}", emsg);
|
||||
if cfg!(target_os = "unix" ) {
|
||||
match e.raw_os_error() {
|
||||
Some(13) => report_permission_error(),
|
||||
|
@ -418,7 +418,7 @@ impl LightClient {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn attempt_recover_seed(config: &LightClientConfig) -> Result<String, String> {
|
||||
pub fn attempt_recover_seed(config: &LightClientConfig, password: Option<String>) -> Result<String, String> {
|
||||
use std::io::prelude::*;
|
||||
use byteorder::{LittleEndian, ReadBytesExt};
|
||||
use libflate::gzip::Decoder;
|
||||
@ -442,8 +442,8 @@ impl LightClient {
|
||||
false
|
||||
};
|
||||
|
||||
if encrypted {
|
||||
return Err("The wallet is encrypted!".to_string());
|
||||
if encrypted && password.is_none() {
|
||||
return Err("The wallet is encrypted and a password was not specified. Please specify the password with '--password'!".to_string());
|
||||
}
|
||||
|
||||
let mut enc_seed = [0u8; 48];
|
||||
@ -451,19 +451,35 @@ impl LightClient {
|
||||
reader.read_exact(&mut enc_seed).unwrap();
|
||||
}
|
||||
|
||||
let _nonce = if version >= 4 {
|
||||
let nonce = if version >= 4 {
|
||||
Vector::read(&mut reader, |r| r.read_u8()).unwrap()
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
// Seed
|
||||
let mut seed_bytes = [0u8; 32];
|
||||
reader.read_exact(&mut seed_bytes).unwrap();
|
||||
let phrase = if encrypted {
|
||||
use sodiumoxide::crypto::secretbox;
|
||||
use crate::lightwallet::double_sha256;
|
||||
|
||||
let phrase = Mnemonic::from_entropy(&seed_bytes, Language::English,).unwrap().phrase().to_string();
|
||||
// Get the doublesha256 of the password, which is the right length
|
||||
let key = secretbox::Key::from_slice(&double_sha256(password.unwrap().as_bytes())).unwrap();
|
||||
let nonce = secretbox::Nonce::from_slice(&nonce).unwrap();
|
||||
|
||||
Ok(phrase)
|
||||
let seed = match secretbox::open(&enc_seed, &nonce, &key) {
|
||||
Ok(s) => s,
|
||||
Err(_) => return Err("Decryption failed. Is your password correct?".to_string())
|
||||
};
|
||||
|
||||
Mnemonic::from_entropy(&seed, Language::English)
|
||||
} else {
|
||||
// Seed
|
||||
let mut seed_bytes = [0u8; 32];
|
||||
reader.read_exact(&mut seed_bytes).unwrap();
|
||||
|
||||
Mnemonic::from_entropy(&seed_bytes, Language::English)
|
||||
}.map_err(|e| format!("Failed to read seed. {:?}", e));
|
||||
|
||||
phrase.map(|m| m.phrase().to_string())
|
||||
}
|
||||
|
||||
|
||||
@ -1268,13 +1284,14 @@ pub mod tests {
|
||||
let seed = lc.do_seed_phrase().unwrap()["seed"].as_str().unwrap().to_string();
|
||||
lc.do_save().unwrap();
|
||||
|
||||
assert_eq!(seed, LightClient::attempt_recover_seed(&config).unwrap());
|
||||
assert_eq!(seed, LightClient::attempt_recover_seed(&config, None).unwrap());
|
||||
|
||||
// Now encrypt and save the file
|
||||
lc.wallet.write().unwrap().encrypt("password".to_string()).unwrap();
|
||||
let pwd = "password".to_string();
|
||||
lc.wallet.write().unwrap().encrypt(pwd.clone()).unwrap();
|
||||
lc.do_save().unwrap();
|
||||
|
||||
assert!(LightClient::attempt_recover_seed(&config).is_err());
|
||||
assert_eq!(seed, LightClient::attempt_recover_seed(&config, Some(pwd)).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,12 +239,15 @@ impl LightWallet {
|
||||
return Err(io::Error::new(ErrorKind::InvalidData, e));
|
||||
}
|
||||
|
||||
println!("Reading wallet version {}", version);
|
||||
info!("Reading wallet version {}", version);
|
||||
|
||||
// After version 5, we're writing the rest of the file as a compressed stream (gzip)
|
||||
let mut reader: Box<dyn Read> = if version <= 4 {
|
||||
info!("Reading direct");
|
||||
Box::new(inp)
|
||||
} else {
|
||||
info!("Reading libflat");
|
||||
Box::new(Decoder::new(inp).unwrap())
|
||||
};
|
||||
|
||||
@ -253,25 +256,25 @@ impl LightWallet {
|
||||
} else {
|
||||
false
|
||||
};
|
||||
info!("Wallet Encryption {:?}", encrypted);
|
||||
|
||||
let mut enc_seed = [0u8; 48];
|
||||
if version >= 4 {
|
||||
reader.read_exact(&mut enc_seed)?;
|
||||
}
|
||||
|
||||
|
||||
let nonce = if version >= 4 {
|
||||
Vector::read(&mut reader, |r| r.read_u8())?
|
||||
} else {
|
||||
vec![]
|
||||
};
|
||||
|
||||
|
||||
// Seed
|
||||
let mut seed_bytes = [0u8; 32];
|
||||
reader.read_exact(&mut seed_bytes)?;
|
||||
|
||||
// Read the spending keys
|
||||
let extsks = Vector::read(&mut reader, |r| ExtendedSpendingKey::read(r))?;
|
||||
println!("reading version {}", version);
|
||||
|
||||
let extfvks = if version >= 4 {
|
||||
// Read the viewing keys
|
||||
@ -281,7 +284,7 @@ impl LightWallet {
|
||||
extsks.iter().map(|sk| ExtendedFullViewingKey::from(sk))
|
||||
.collect::<Vec<ExtendedFullViewingKey>>()
|
||||
};
|
||||
|
||||
|
||||
// Calculate the addresses
|
||||
let addresses = extfvks.iter().map( |fvk| fvk.default_address().unwrap().1 )
|
||||
.collect::<Vec<PaymentAddress<Bls12>>>();
|
||||
@ -291,7 +294,7 @@ impl LightWallet {
|
||||
r.read_exact(&mut tpk_bytes)?;
|
||||
secp256k1::SecretKey::from_slice(&tpk_bytes).map_err(|e| io::Error::new(ErrorKind::InvalidData, e))
|
||||
})?;
|
||||
|
||||
|
||||
let taddresses = if version >= 4 {
|
||||
// Read the addresses
|
||||
Vector::read(&mut reader, |r| utils::read_string(r))?
|
||||
@ -299,9 +302,9 @@ impl LightWallet {
|
||||
// Calculate the addresses
|
||||
tkeys.iter().map(|sk| LightWallet::address_from_prefix_sk(&config.base58_pubkey_address(), sk)).collect()
|
||||
};
|
||||
|
||||
|
||||
let blocks = Vector::read(&mut reader, |r| BlockData::read(r))?;
|
||||
|
||||
|
||||
let txs_tuples = Vector::read(&mut reader, |r| {
|
||||
let mut txid_bytes = [0u8; 32];
|
||||
r.read_exact(&mut txid_bytes)?;
|
||||
@ -363,7 +366,7 @@ impl LightWallet {
|
||||
writer.write_all(&self.seed)?;
|
||||
|
||||
// Flush after writing the seed, so in case of a disaster, we can still recover the seed.
|
||||
//writer.flush()?;
|
||||
writer.flush()?;
|
||||
|
||||
// Write all the spending keys
|
||||
Vector::write(&mut writer, &self.extsks.read().unwrap(),
|
||||
|
Loading…
Reference in New Issue
Block a user