diff --git a/Cargo.lock b/Cargo.lock index 974a50f96..63dabcd43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -471,6 +471,7 @@ dependencies = [ "serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ethcore/src/account_provider.rs b/ethcore/src/account_provider.rs index 62bfa3d0d..1738fb82a 100644 --- a/ethcore/src/account_provider.rs +++ b/ethcore/src/account_provider.rs @@ -114,8 +114,8 @@ impl KeyDirectory for NullDir { Ok(vec![]) } - fn insert(&self, _account: SafeAccount) -> Result<(), SSError> { - Ok(()) + fn insert(&self, account: SafeAccount) -> Result { + Ok(account) } fn remove(&self, _address: &SSAddress) -> Result<(), SSError> { diff --git a/ethstore/Cargo.toml b/ethstore/Cargo.toml index cfb5b9fbc..24dd41e14 100644 --- a/ethstore/Cargo.toml +++ b/ethstore/Cargo.toml @@ -15,6 +15,7 @@ rustc-serialize = "0.3" rust-crypto = "0.2.36" tiny-keccak = "1.0" docopt = { version = "0.6", optional = true } +time = "0.1.34" [build-dependencies] serde_codegen = { version = "0.7", optional = true } diff --git a/ethstore/src/account/safe_account.rs b/ethstore/src/account/safe_account.rs index 5e680c260..059f988d0 100644 --- a/ethstore/src/account/safe_account.rs +++ b/ethstore/src/account/safe_account.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . use std::ops::{Deref, DerefMut}; +use std::path::{PathBuf}; use ethkey::{KeyPair, sign, Address, Secret, Signature, Message}; use {json, Error, crypto}; use crypto::Keccak256; @@ -35,6 +36,7 @@ pub struct SafeAccount { pub version: Version, pub address: Address, pub crypto: Crypto, + pub path: Option, pub name: String, pub meta: String, } @@ -42,9 +44,9 @@ pub struct SafeAccount { impl From for Crypto { fn from(json: json::Crypto) -> Self { Crypto { - cipher: From::from(json.cipher), + cipher: json.cipher.into(), ciphertext: json.ciphertext.into(), - kdf: From::from(json.kdf), + kdf: json.kdf.into(), mac: json.mac.into(), } } @@ -54,9 +56,9 @@ impl Into for Crypto { fn into(self) -> json::Crypto { json::Crypto { cipher: self.cipher.into(), - ciphertext: From::from(self.ciphertext), + ciphertext: self.ciphertext.into(), kdf: self.kdf.into(), - mac: From::from(self.mac), + mac: self.mac.into(), } } } @@ -65,9 +67,10 @@ impl From for SafeAccount { fn from(json: json::KeyFile) -> Self { SafeAccount { id: json.id.into(), - version: From::from(json.version), - address: From::from(json.address), //json.address.into(), - crypto: From::from(json.crypto), + version: json.version.into(), + address: json.address.into(), + crypto: json.crypto.into(), + path: None, name: json.name.unwrap_or(String::new()), meta: json.meta.unwrap_or("{}".to_owned()), } @@ -151,11 +154,24 @@ impl SafeAccount { version: Version::V3, crypto: Crypto::create(keypair.secret(), password, iterations), address: keypair.address(), + path: None, name: name, meta: meta, } } + pub fn from_file(json: json::KeyFile, path: PathBuf) -> Self { + SafeAccount { + id: json.id.into(), + version: json.version.into(), + address: json.address.into(), + crypto: json.crypto.into(), + path: Some(path), + name: json.name.unwrap_or(String::new()), + meta: json.meta.unwrap_or("{}".to_owned()), + } + } + pub fn sign(&self, password: &str, message: &Message) -> Result { let secret = try!(self.crypto.secret(password)); sign(&secret, message).map_err(From::from) @@ -168,6 +184,7 @@ impl SafeAccount { version: self.version.clone(), crypto: Crypto::create(&secret, new_password, iterations), address: self.address.clone(), + path: self.path.clone(), name: self.name.clone(), meta: self.meta.clone(), }; diff --git a/ethstore/src/dir/disk.rs b/ethstore/src/dir/disk.rs index f63577361..b94fe5214 100644 --- a/ethstore/src/dir/disk.rs +++ b/ethstore/src/dir/disk.rs @@ -17,6 +17,7 @@ use std::{fs, ffi, io}; use std::path::{PathBuf, Path}; use std::collections::HashMap; +use time; use ethkey::Address; use {libc, json, SafeAccount, Error}; use super::KeyDirectory; @@ -73,7 +74,7 @@ impl DiskDirectory { let accounts = files.into_iter() .map(json::KeyFile::load) .zip(paths.into_iter()) - .filter_map(|(file, path)| file.ok().map(|file| (path, SafeAccount::from(file)))) + .filter_map(|(file, path)| file.ok().map(|file| (path.clone(), SafeAccount::from_file(file, path)))) .collect(); Ok(accounts) @@ -89,24 +90,32 @@ impl KeyDirectory for DiskDirectory { Ok(accounts) } - fn insert(&self, account: SafeAccount) -> Result<(), Error> { + fn insert(&self, account: SafeAccount) -> Result { // transform account into key file - let keyfile: json::KeyFile = account.into(); + let keyfile: json::KeyFile = account.clone().into(); // build file path - let mut keyfile_path = self.path.clone(); - keyfile_path.push(format!("{}", keyfile.id)); + let mut account = account; + account.path = account.path.or_else(|| { + let mut keyfile_path = self.path.clone(); + let timestamp = time::strftime("%Y-%m-%d_%H:%M:%S_%Z", &time::now()).unwrap_or("???".to_owned()); + keyfile_path.push(format!("{}-{}.json", keyfile.id, timestamp)); + Some(keyfile_path) + }); - // save the file - let mut file = try!(fs::File::create(&keyfile_path)); - try!(keyfile.write(&mut file).map_err(|e| Error::Custom(format!("{:?}", e)))); + { + // save the file + let path = account.path.as_ref().expect("build-file-path ensures is not None; qed"); + let mut file = try!(fs::File::create(path)); + try!(keyfile.write(&mut file).map_err(|e| Error::Custom(format!("{:?}", e)))); - if let Err(_) = restrict_permissions_to_owner(&keyfile_path) { - fs::remove_file(&keyfile_path).expect("Expected to remove recently created file"); - return Err(Error::Io(io::Error::last_os_error())); + if let Err(_) = restrict_permissions_to_owner(path) { + fs::remove_file(path).expect("Expected to remove recently created file"); + return Err(Error::Io(io::Error::last_os_error())); + } } - Ok(()) + Ok(account) } fn remove(&self, address: &Address) -> Result<(), Error> { diff --git a/ethstore/src/dir/geth.rs b/ethstore/src/dir/geth.rs index 29c9f2dc3..f63ebbea2 100644 --- a/ethstore/src/dir/geth.rs +++ b/ethstore/src/dir/geth.rs @@ -85,7 +85,7 @@ impl KeyDirectory for GethDirectory { self.dir.load() } - fn insert(&self, account: SafeAccount) -> Result<(), Error> { + fn insert(&self, account: SafeAccount) -> Result { self.dir.insert(account) } diff --git a/ethstore/src/dir/mod.rs b/ethstore/src/dir/mod.rs index 68280f596..6f2b59194 100644 --- a/ethstore/src/dir/mod.rs +++ b/ethstore/src/dir/mod.rs @@ -28,7 +28,7 @@ pub enum DirectoryType { pub trait KeyDirectory: Send + Sync { fn load(&self) -> Result, Error>; - fn insert(&self, account: SafeAccount) -> Result<(), Error>; + fn insert(&self, account: SafeAccount) -> Result; fn remove(&self, address: &Address) -> Result<(), Error>; } diff --git a/ethstore/src/dir/parity.rs b/ethstore/src/dir/parity.rs index c1b812fe0..7aa50c80b 100644 --- a/ethstore/src/dir/parity.rs +++ b/ethstore/src/dir/parity.rs @@ -64,7 +64,7 @@ impl KeyDirectory for ParityDirectory { self.dir.load() } - fn insert(&self, account: SafeAccount) -> Result<(), Error> { + fn insert(&self, account: SafeAccount) -> Result { self.dir.insert(account) } diff --git a/ethstore/src/ethstore.rs b/ethstore/src/ethstore.rs index 8db00298e..a63a9d274 100644 --- a/ethstore/src/ethstore.rs +++ b/ethstore/src/ethstore.rs @@ -49,7 +49,7 @@ impl EthStore { fn save(&self, account: SafeAccount) -> Result<(), Error> { // save to file - try!(self.dir.insert(account.clone())); + let account = try!(self.dir.insert(account.clone())); // update cache let mut cache = self.cache.write().unwrap(); diff --git a/ethstore/src/lib.rs b/ethstore/src/lib.rs index 96d860db4..010052f18 100644 --- a/ethstore/src/lib.rs +++ b/ethstore/src/lib.rs @@ -19,6 +19,7 @@ extern crate libc; extern crate rand; +extern crate time; extern crate serde; extern crate serde_json; extern crate rustc_serialize; diff --git a/ethstore/tests/util/transient_dir.rs b/ethstore/tests/util/transient_dir.rs index f4998e124..23523e48c 100644 --- a/ethstore/tests/util/transient_dir.rs +++ b/ethstore/tests/util/transient_dir.rs @@ -64,7 +64,7 @@ impl KeyDirectory for TransientDir { self.dir.load() } - fn insert(&self, account: SafeAccount) -> Result<(), Error> { + fn insert(&self, account: SafeAccount) -> Result { self.dir.insert(account) }