keys import (#1240)

* pattern importing

* tests for import

* cli options for account import

* [options] for import also

* removed globbing

* removed glob crate refs
This commit is contained in:
Nikolay Volf 2016-06-08 17:17:37 +04:00 committed by Gav Wood
parent be435cde99
commit b4b883b341
6 changed files with 122 additions and 5 deletions

View File

@ -23,7 +23,8 @@ Parity. Ethereum Client.
Usage: Usage:
parity daemon <pid-file> [options] parity daemon <pid-file> [options]
parity account (new | list) [options] parity account (new | list ) [options]
parity account import <path>... [options]
parity import [ <file> ] [options] parity import [ <file> ] [options]
parity export [ <file> ] [options] parity export [ <file> ] [options]
parity signer new-token [options] parity signer new-token [options]
@ -212,6 +213,7 @@ pub struct Args {
pub cmd_new_token: bool, pub cmd_new_token: bool,
pub arg_pid_file: String, pub arg_pid_file: String,
pub arg_file: Option<String>, pub arg_file: Option<String>,
pub arg_path: Vec<String>,
pub flag_chain: String, pub flag_chain: String,
pub flag_db_path: String, pub flag_db_path: String,
pub flag_identity: String, pub flag_identity: String,

View File

@ -482,6 +482,11 @@ fn execute_account_cli(conf: Configuration) {
for &(addr, _) in &secret_store.accounts().unwrap() { for &(addr, _) in &secret_store.accounts().unwrap() {
println!("{:?}", addr); println!("{:?}", addr);
} }
return;
}
if conf.args.cmd_import {
let imported = util::keys::import_keys_paths(&mut secret_store, &conf.args.arg_path).unwrap();
println!("Imported {} keys", imported);
} }
} }

21
util/res/pat/p1.json Normal file
View File

@ -0,0 +1,21 @@
{
"address": "3f49624084b67849c7b4e805c5988c21a430f9d9",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "9f27e3dd4fc73e7103ed61e5493662189a3eb52223ae49e3d1deacc04c889eae",
"cipherparams": {
"iv": "457494bf05f2618c397dc74dbb5181c0"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "db14edb18c41ee7f5ec4397df89c3a2ae4d0af60884c52bb54ce490574f8df33"
},
"mac": "572d24532438d31fdf513c744a3ff26c933ffda5744ee42bc71661cbe3f2112e"
},
"id": "62a0ad73-556d-496a-8e1c-0783d30d3ace",
"version": 3
}

21
util/res/pat/p2.json Normal file
View File

@ -0,0 +1,21 @@
{
"address": "5ba4dcf897e97c2bdf8315b9ef26c13c085988cf",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "d4a08ec930163778273920f6ad1d49b71836337be6fd9863993ac700a612fddd",
"cipherparams": {
"iv": "89ce5ec129fc27cd5bcbeb8c92bdad50"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "612ab108dc37e69ee8af37a7b24bf7f2234086d7bbf945bacdeccce331f7f84a"
},
"mac": "4152caa7444e06784223d735cea80cd2690b4c587ad8db3d5529442227b25695"
},
"id": "35086353-fb12-4029-b56b-033cd61ce35b",
"version": 3
}

View File

@ -80,9 +80,10 @@ pub fn import_geth_key(secret_store: &mut SecretStore, geth_keyfile_path: &Path)
} }
/// Imports all geth keys in the directory /// Imports all geth keys in the directory
pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<(), ImportError> { pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory: &Path) -> Result<usize, ImportError> {
use std::path::PathBuf; use std::path::PathBuf;
let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory)); let geth_files = try!(enumerate_geth_keys(geth_keyfiles_directory));
let mut total = 0;
for &(ref address, ref file_path) in &geth_files { for &(ref address, ref file_path) in &geth_files {
let mut path = PathBuf::new(); let mut path = PathBuf::new();
path.push(geth_keyfiles_directory); path.push(geth_keyfiles_directory);
@ -90,18 +91,45 @@ pub fn import_geth_keys(secret_store: &mut SecretStore, geth_keyfiles_directory:
if let Err(e) = import_geth_key(secret_store, Path::new(&path)) { if let Err(e) = import_geth_key(secret_store, Path::new(&path)) {
warn!("Skipped geth address {}, error importing: {:?}", address, e) warn!("Skipped geth address {}, error importing: {:?}", address, e)
} }
else { total = total + 1}
} }
Ok(()) Ok(total)
} }
/// Gets the default geth keystore directory. /// Gets the default geth keystore directory.
///
/// Based on https://github.com/ethereum/go-ethereum/blob/e553215/common/path.go#L75
pub fn keystore_dir(is_testnet: bool) -> PathBuf { pub fn keystore_dir(is_testnet: bool) -> PathBuf {
path::ethereum::with_default(if is_testnet {"testnet/keystore"} else {"keystore"}) path::ethereum::with_default(if is_testnet {"testnet/keystore"} else {"keystore"})
} }
/// Imports key(s) from provided file/directory
pub fn import_keys_path(secret_store: &mut SecretStore, path: &str) -> Result<usize, ImportError> {
// check if it is just one file or directory
if let Ok(meta) = fs::metadata(path) {
if meta.is_file() {
try!(import_geth_key(secret_store, Path::new(path)));
return Ok(1);
}
else if meta.is_dir() {
return Ok(try!(fs::read_dir(path)).fold(
0,
|total, p|
total +
match p {
Ok(dir_entry) => import_keys_path(secret_store, dir_entry.path().to_str().unwrap()).unwrap_or_else(|_| 0),
Err(e) => { warn!("Error importing dir entry: {:?}", e); 0 },
}
))
}
}
Ok(0)
}
/// Imports all keys from list of provided files/directories
pub fn import_keys_paths(secret_store: &mut SecretStore, path: &[String]) -> Result<usize, ImportError> {
Ok(path.iter().fold(0, |total, ref p| total + import_keys_path(secret_store, &p).unwrap_or_else(|_| 0)))
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -115,10 +143,21 @@ mod tests {
} }
} }
fn pat_path() -> &'static str {
match ::std::fs::metadata("res") {
Ok(_) => "res/pat",
Err(_) => "util/res/pat"
}
}
fn test_path_param(param_val: &'static str) -> String { fn test_path_param(param_val: &'static str) -> String {
test_path().to_owned() + param_val test_path().to_owned() + param_val
} }
fn pat_path_param(param_val: &'static str) -> String {
pat_path().to_owned() + param_val
}
#[test] #[test]
fn can_enumerate() { fn can_enumerate() {
let keys = enumerate_geth_keys(Path::new(test_path())).unwrap(); let keys = enumerate_geth_keys(Path::new(test_path())).unwrap();
@ -191,4 +230,32 @@ mod tests {
assert!(val.is_ok()); assert!(val.is_ok());
assert_eq!(32, val.unwrap().len()); assert_eq!(32, val.unwrap().len());
} }
#[test]
fn can_import_by_filename() {
let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path());
let amount = import_keys_path(&mut secret_store, &pat_path_param("/p1.json")).unwrap();
assert_eq!(1, amount);
}
#[test]
fn can_import_by_dir() {
let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path());
let amount = import_keys_path(&mut secret_store, pat_path()).unwrap();
assert_eq!(2, amount);
}
#[test]
fn can_import_mulitple() {
let temp = ::devtools::RandomTempPath::create_dir();
let mut secret_store = SecretStore::new_in(temp.as_path());
let amount = import_keys_paths(&mut secret_store, &[pat_path_param("/p1.json"), pat_path_param("/p2.json")]).unwrap();
assert_eq!(2, amount);
}
} }

View File

@ -23,3 +23,4 @@ mod test_account_provider;
pub use self::store::AccountProvider; pub use self::store::AccountProvider;
pub use self::test_account_provider::{TestAccount, TestAccountProvider}; pub use self::test_account_provider::{TestAccount, TestAccountProvider};
pub use self::geth_import::import_keys_paths;