Key files include timestamp in name. (#1700)

* Key files include timestamp in name.

Introduce timestamp into new key files; keep filename around, so
that we don't accidentally duplicate keys.

* Remove unnecessary clone

* Fix test code.

* Remove log module from ethstore
This commit is contained in:
Gav Wood 2016-07-25 10:45:45 +02:00 committed by GitHub
parent f048839a4b
commit 435ba186f8
11 changed files with 55 additions and 26 deletions

1
Cargo.lock generated
View File

@ -471,6 +471,7 @@ dependencies = [
"serde_codegen 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -114,8 +114,8 @@ impl KeyDirectory for NullDir {
Ok(vec![]) Ok(vec![])
} }
fn insert(&self, _account: SafeAccount) -> Result<(), SSError> { fn insert(&self, account: SafeAccount) -> Result<SafeAccount, SSError> {
Ok(()) Ok(account)
} }
fn remove(&self, _address: &SSAddress) -> Result<(), SSError> { fn remove(&self, _address: &SSAddress) -> Result<(), SSError> {

View File

@ -15,6 +15,7 @@ rustc-serialize = "0.3"
rust-crypto = "0.2.36" rust-crypto = "0.2.36"
tiny-keccak = "1.0" tiny-keccak = "1.0"
docopt = { version = "0.6", optional = true } docopt = { version = "0.6", optional = true }
time = "0.1.34"
[build-dependencies] [build-dependencies]
serde_codegen = { version = "0.7", optional = true } serde_codegen = { version = "0.7", optional = true }

View File

@ -15,6 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::path::{PathBuf};
use ethkey::{KeyPair, sign, Address, Secret, Signature, Message}; use ethkey::{KeyPair, sign, Address, Secret, Signature, Message};
use {json, Error, crypto}; use {json, Error, crypto};
use crypto::Keccak256; use crypto::Keccak256;
@ -35,6 +36,7 @@ pub struct SafeAccount {
pub version: Version, pub version: Version,
pub address: Address, pub address: Address,
pub crypto: Crypto, pub crypto: Crypto,
pub path: Option<PathBuf>,
pub name: String, pub name: String,
pub meta: String, pub meta: String,
} }
@ -42,9 +44,9 @@ pub struct SafeAccount {
impl From<json::Crypto> for Crypto { impl From<json::Crypto> for Crypto {
fn from(json: json::Crypto) -> Self { fn from(json: json::Crypto) -> Self {
Crypto { Crypto {
cipher: From::from(json.cipher), cipher: json.cipher.into(),
ciphertext: json.ciphertext.into(), ciphertext: json.ciphertext.into(),
kdf: From::from(json.kdf), kdf: json.kdf.into(),
mac: json.mac.into(), mac: json.mac.into(),
} }
} }
@ -54,9 +56,9 @@ impl Into<json::Crypto> for Crypto {
fn into(self) -> json::Crypto { fn into(self) -> json::Crypto {
json::Crypto { json::Crypto {
cipher: self.cipher.into(), cipher: self.cipher.into(),
ciphertext: From::from(self.ciphertext), ciphertext: self.ciphertext.into(),
kdf: self.kdf.into(), kdf: self.kdf.into(),
mac: From::from(self.mac), mac: self.mac.into(),
} }
} }
} }
@ -65,9 +67,10 @@ impl From<json::KeyFile> for SafeAccount {
fn from(json: json::KeyFile) -> Self { fn from(json: json::KeyFile) -> Self {
SafeAccount { SafeAccount {
id: json.id.into(), id: json.id.into(),
version: From::from(json.version), version: json.version.into(),
address: From::from(json.address), //json.address.into(), address: json.address.into(),
crypto: From::from(json.crypto), crypto: json.crypto.into(),
path: None,
name: json.name.unwrap_or(String::new()), name: json.name.unwrap_or(String::new()),
meta: json.meta.unwrap_or("{}".to_owned()), meta: json.meta.unwrap_or("{}".to_owned()),
} }
@ -151,11 +154,24 @@ impl SafeAccount {
version: Version::V3, version: Version::V3,
crypto: Crypto::create(keypair.secret(), password, iterations), crypto: Crypto::create(keypair.secret(), password, iterations),
address: keypair.address(), address: keypair.address(),
path: None,
name: name, name: name,
meta: meta, 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<Signature, Error> { pub fn sign(&self, password: &str, message: &Message) -> Result<Signature, Error> {
let secret = try!(self.crypto.secret(password)); let secret = try!(self.crypto.secret(password));
sign(&secret, message).map_err(From::from) sign(&secret, message).map_err(From::from)
@ -168,6 +184,7 @@ impl SafeAccount {
version: self.version.clone(), version: self.version.clone(),
crypto: Crypto::create(&secret, new_password, iterations), crypto: Crypto::create(&secret, new_password, iterations),
address: self.address.clone(), address: self.address.clone(),
path: self.path.clone(),
name: self.name.clone(), name: self.name.clone(),
meta: self.meta.clone(), meta: self.meta.clone(),
}; };

View File

@ -17,6 +17,7 @@
use std::{fs, ffi, io}; use std::{fs, ffi, io};
use std::path::{PathBuf, Path}; use std::path::{PathBuf, Path};
use std::collections::HashMap; use std::collections::HashMap;
use time;
use ethkey::Address; use ethkey::Address;
use {libc, json, SafeAccount, Error}; use {libc, json, SafeAccount, Error};
use super::KeyDirectory; use super::KeyDirectory;
@ -73,7 +74,7 @@ impl DiskDirectory {
let accounts = files.into_iter() let accounts = files.into_iter()
.map(json::KeyFile::load) .map(json::KeyFile::load)
.zip(paths.into_iter()) .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(); .collect();
Ok(accounts) Ok(accounts)
@ -89,24 +90,32 @@ impl KeyDirectory for DiskDirectory {
Ok(accounts) Ok(accounts)
} }
fn insert(&self, account: SafeAccount) -> Result<(), Error> { fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
// transform account into key file // transform account into key file
let keyfile: json::KeyFile = account.into(); let keyfile: json::KeyFile = account.clone().into();
// build file path // build file path
let mut account = account;
account.path = account.path.or_else(|| {
let mut keyfile_path = self.path.clone(); let mut keyfile_path = self.path.clone();
keyfile_path.push(format!("{}", keyfile.id)); 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 // save the file
let mut file = try!(fs::File::create(&keyfile_path)); 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)))); try!(keyfile.write(&mut file).map_err(|e| Error::Custom(format!("{:?}", e))));
if let Err(_) = restrict_permissions_to_owner(&keyfile_path) { if let Err(_) = restrict_permissions_to_owner(path) {
fs::remove_file(&keyfile_path).expect("Expected to remove recently created file"); fs::remove_file(path).expect("Expected to remove recently created file");
return Err(Error::Io(io::Error::last_os_error())); return Err(Error::Io(io::Error::last_os_error()));
} }
}
Ok(()) Ok(account)
} }
fn remove(&self, address: &Address) -> Result<(), Error> { fn remove(&self, address: &Address) -> Result<(), Error> {

View File

@ -85,7 +85,7 @@ impl KeyDirectory for GethDirectory {
self.dir.load() self.dir.load()
} }
fn insert(&self, account: SafeAccount) -> Result<(), Error> { fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
self.dir.insert(account) self.dir.insert(account)
} }

View File

@ -28,7 +28,7 @@ pub enum DirectoryType {
pub trait KeyDirectory: Send + Sync { pub trait KeyDirectory: Send + Sync {
fn load(&self) -> Result<Vec<SafeAccount>, Error>; fn load(&self) -> Result<Vec<SafeAccount>, Error>;
fn insert(&self, account: SafeAccount) -> Result<(), Error>; fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error>;
fn remove(&self, address: &Address) -> Result<(), Error>; fn remove(&self, address: &Address) -> Result<(), Error>;
} }

View File

@ -64,7 +64,7 @@ impl KeyDirectory for ParityDirectory {
self.dir.load() self.dir.load()
} }
fn insert(&self, account: SafeAccount) -> Result<(), Error> { fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
self.dir.insert(account) self.dir.insert(account)
} }

View File

@ -49,7 +49,7 @@ impl EthStore {
fn save(&self, account: SafeAccount) -> Result<(), Error> { fn save(&self, account: SafeAccount) -> Result<(), Error> {
// save to file // save to file
try!(self.dir.insert(account.clone())); let account = try!(self.dir.insert(account.clone()));
// update cache // update cache
let mut cache = self.cache.write().unwrap(); let mut cache = self.cache.write().unwrap();

View File

@ -19,6 +19,7 @@
extern crate libc; extern crate libc;
extern crate rand; extern crate rand;
extern crate time;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;
extern crate rustc_serialize; extern crate rustc_serialize;

View File

@ -64,7 +64,7 @@ impl KeyDirectory for TransientDir {
self.dir.load() self.dir.load()
} }
fn insert(&self, account: SafeAccount) -> Result<(), Error> { fn insert(&self, account: SafeAccount) -> Result<SafeAccount, Error> {
self.dir.insert(account) self.dir.insert(account)
} }