Skip to content
This repository has been archived by the owner on Jul 27, 2022. It is now read-only.

Commit

Permalink
can dump all wallet at once
Browse files Browse the repository at this point in the history
  • Loading branch information
linfeng-crypto committed Feb 21, 2020
1 parent 3897dca commit d9c6437
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 31 deletions.
150 changes: 119 additions & 31 deletions client-cli/src/command/wallet_command.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use quest::{ask, success, text, yesno};
use quest::{ask, error, success, text};
use secstr::SecUtf8;
use structopt::StructOpt;

Expand All @@ -7,7 +7,9 @@ use client_core::types::WalletKind;
use client_core::{Mnemonic, WalletClient};

use crate::{ask_passphrase, ask_seckey};
use client_common::seckey::parse_hex_enckey;
use client_core::service::WalletInfo;
use serde_json::Value;
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
Expand Down Expand Up @@ -43,15 +45,23 @@ pub enum WalletCommand {
long = "name",
help = "Name of wallet"
)]
name: String,
name: Option<String>,
#[structopt(
name = "file",
name = "from",
short = "f",
long = "file",
long = "from_file",
parse(from_os_str),
help = "file to dump wallet"
help = r#"json file contains a list of {"name": wallet_name, "auth_token": auth_token}"#
)]
file: PathBuf,
from_file: Option<PathBuf>,
#[structopt(
name = "to",
short = "t",
long = "to_file",
parse(from_os_str),
help = "file to dump the wallet information"
)]
to_file: PathBuf,
},
#[structopt(name = "import", about = "Import a wallet from a file")]
Import {
Expand Down Expand Up @@ -119,7 +129,11 @@ impl WalletCommand {
WalletCommand::RestoreBasic { name } => Self::restore_basic_wallet(wallet_client, name),
WalletCommand::AuthToken { name } => Self::auth_token(wallet_client, name),
WalletCommand::Delete { name } => Self::delete(wallet_client, name),
WalletCommand::Export { name, file } => Self::export(wallet_client, name, file),
WalletCommand::Export {
name,
from_file,
to_file,
} => Self::export(wallet_client, name, from_file, to_file),
WalletCommand::Import { file } => Self::import(wallet_client, file),
}
}
Expand Down Expand Up @@ -157,20 +171,96 @@ impl WalletCommand {
Ok(())
}

fn export<T: WalletClient>(wallet_client: T, name: &str, file: &PathBuf) -> Result<()> {
let enckey = ask_seckey(None)?;
let wallet_info = wallet_client.export_wallet(name, &enckey)?;
let wallet_info_str = serde_json::to_string_pretty(&wallet_info).chain(|| {
fn export<T: WalletClient>(
wallet_client: T,
name: &Option<String>,
from_file: &Option<PathBuf>,
to_file: &PathBuf,
) -> Result<()> {
let mut wallet_info_list = vec![];
let mut error_wallets = vec![];
match (name, from_file) {
(Some(_name), Some(_from_file)) => {
return Err(Error::new(
ErrorKind::InvalidInput,
"only need name or from_file",
))
}
(None, None) => {
return Err(Error::new(
ErrorKind::InvalidInput,
"need name or from_file",
))
}
(Some(name), None) => {
let enckey = ask_seckey(None)?;
let wallet_info = wallet_client.export_wallet(name, &enckey)?;
wallet_info_list.push(wallet_info);
}
(None, Some(from_file)) => {
let mut file =
File::open(from_file).chain(|| (ErrorKind::IoError, "Unable to open file"))?;
let mut settings: String = String::new();
file.read_to_string(&mut settings)
.chain(|| (ErrorKind::IoError, "Unable to read from file"))?;
let wallet_settings: Value = serde_json::from_str(&settings)
.chain(|| (ErrorKind::InvalidInput, "Invalid wallet info"))?;
let wallet_settings = wallet_settings.as_array().chain(|| {
(
ErrorKind::InvalidInput,
"from_file should contains a list of setting",
)
})?;
for setting in wallet_settings {
let name = setting["name"]
.as_str()
.chain(|| (ErrorKind::InvalidInput, "expect name"))?;
let key = setting["auth_token"]
.as_str()
.chain(|| (ErrorKind::InvalidInput, "Expect auth_token"))?;
let enckey = parse_hex_enckey(&key).map_err(|_e| {
error(&format!("error auth_token of wallet {}", name));
});
if enckey.is_err() {
continue;
}
match wallet_client.export_wallet(name, &enckey.unwrap()) {
Ok(wallet_info) => {
wallet_info_list.push(wallet_info);
}
Err(e) => {
error(&format!("error to get wallet info: {:?}", e));
error_wallets.push(name.to_string());
}
}
}
}
}
if error_wallets.is_empty() {
success(&format!("Get all {} wallets info.", wallet_info_list.len()));
} else {
error(&format!(
"Get {} wallets info, failed wallet(s): {}, please fix and retry!",
wallet_info_list.len(),
error_wallets.join(",")
));
return Ok(());
}
let wallet_info_str = serde_json::to_string_pretty(&wallet_info_list).chain(|| {
(
ErrorKind::SerializationError,
"Inner serialize wallet info error",
)
})?;
let mut file =
File::create(file).chain(|| (ErrorKind::IoError, "Unable to create file"))?;
File::create(to_file).chain(|| (ErrorKind::IoError, "Unable to create file"))?;
file.write_all(wallet_info_str.as_bytes())
.chain(|| (ErrorKind::IoError, "Unable to write to file"))?;
let msg = format!("export wallet {} to file {:?} success", name, file);
let msg = format!(
"Export {} wallet to file {:?} success",
wallet_info_list.len(),
to_file
);
success(&msg);
Ok(())
}
Expand All @@ -180,25 +270,23 @@ impl WalletCommand {
let mut wallet_info_str = String::new();
file.read_to_string(&mut wallet_info_str)
.chain(|| (ErrorKind::IoError, "Unable to read from file"))?;
let wallet_info: WalletInfo = serde_json::from_str(&wallet_info_str)
.chain(|| (ErrorKind::InvalidInput, "Invalid wallet info"))?;
let mut name = wallet_info.name.clone();
ask(&format!("Use the wallet name {}? [Y|N]:", name));
match yesno(true).chain(|| (ErrorKind::IoError, "Unable to read yes/no"))? {
None => return Err(ErrorKind::InvalidInput.into()),
Some(yes) => {
if !yes {
ask("Input new wallet name:");
name = text().chain(|| (ErrorKind::IoError, "Unable to read name"))?;
}
}
let wallet_info_list: Vec<WalletInfo> = serde_json::from_str(&wallet_info_str)
.chain(|| (ErrorKind::InvalidInput, "Invalid wallet info list"))?;
for wallet_info in wallet_info_list {
let name = wallet_info.name.clone();
let passphrase_str = &wallet_info.passphrase;
let passphrase = if passphrase_str.is_empty() {
ask_passphrase(Some(&format!("Input passphrase for wallet {}", name)))?
} else {
passphrase_str.into()
};
let enckey = wallet_client.import_wallet(&name, &passphrase, wallet_info)?;
success(&format!(
"Authentication token of wallet {}: {}",
name,
&hex::encode(enckey.unsecure())
));
}
let passphrase = ask_passphrase(None)?;
let enckey = wallet_client.import_wallet(&name, &passphrase, wallet_info)?;
success(&format!(
"Authentication token: {}",
&hex::encode(enckey.unsecure())
));
Ok(())
}

Expand Down
2 changes: 2 additions & 0 deletions client-core/src/service/wallet_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ pub struct WalletInfo {
/// private key of the wallet
#[serde(deserialize_with = "deserde_from_str", serialize_with = "serde_to_str")]
pub private_key: PrivateKey,
/// passphrase used when import wallet
pub passphrase: String,
}

/// Wallet meta data
Expand Down
1 change: 1 addition & 0 deletions client-core/src/wallet/default_wallet_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ where
name: name.into(),
wallet,
private_key,
passphrase: String::default(),
};
Ok(wallet_info)
}
Expand Down

0 comments on commit d9c6437

Please sign in to comment.