Name and meta in accounts (#1695)
* Introduce persistent name() and meta() in SecretStore. * Quick stash. * Fix build. * Add ethcore_set methods. * Bug fixes for default values. * Move to personal to ensure set API exposed. * Add UUID to accounts info. * Add tests.
This commit is contained in:
@@ -35,6 +35,8 @@ pub struct SafeAccount {
|
||||
pub version: Version,
|
||||
pub address: Address,
|
||||
pub crypto: Crypto,
|
||||
pub name: String,
|
||||
pub meta: String,
|
||||
}
|
||||
|
||||
impl From<json::Crypto> for Crypto {
|
||||
@@ -66,6 +68,8 @@ impl From<json::KeyFile> for SafeAccount {
|
||||
version: From::from(json.version),
|
||||
address: From::from(json.address), //json.address.into(),
|
||||
crypto: From::from(json.crypto),
|
||||
name: json.name.unwrap_or(String::new()),
|
||||
meta: json.meta.unwrap_or("{}".to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,6 +81,8 @@ impl Into<json::KeyFile> for SafeAccount {
|
||||
version: self.version.into(),
|
||||
address: self.address.into(), //From::from(self.address),
|
||||
crypto: self.crypto.into(),
|
||||
name: Some(self.name.into()),
|
||||
meta: Some(self.meta.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,12 +144,15 @@ impl Crypto {
|
||||
}
|
||||
|
||||
impl SafeAccount {
|
||||
pub fn create(keypair: &KeyPair, id: [u8; 16], password: &str, iterations: u32) -> Self {
|
||||
// DEPRECATED. use `create_with_name` instead
|
||||
pub fn create(keypair: &KeyPair, id: [u8; 16], password: &str, iterations: u32, name: String, meta: String) -> Self {
|
||||
SafeAccount {
|
||||
id: id,
|
||||
version: Version::V3,
|
||||
crypto: Crypto::create(keypair.secret(), password, iterations),
|
||||
address: keypair.address(),
|
||||
name: name,
|
||||
meta: meta,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -159,6 +168,8 @@ impl SafeAccount {
|
||||
version: self.version.clone(),
|
||||
crypto: Crypto::create(&secret, new_password, iterations),
|
||||
address: self.address.clone(),
|
||||
name: self.name.clone(),
|
||||
meta: self.meta.clone(),
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
@@ -194,7 +205,7 @@ mod tests {
|
||||
let keypair = Random.generate().unwrap();
|
||||
let password = "hello world";
|
||||
let message = Message::default();
|
||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240);
|
||||
let account = SafeAccount::create(&keypair, [0u8; 16], password, 10240, "Test".to_owned(), "{}".to_owned());
|
||||
let signature = account.sign(password, &message).unwrap();
|
||||
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
|
||||
}
|
||||
@@ -206,7 +217,7 @@ mod tests {
|
||||
let sec_password = "this is sparta";
|
||||
let i = 10240;
|
||||
let message = Message::default();
|
||||
let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i);
|
||||
let account = SafeAccount::create(&keypair, [0u8; 16], first_password, i, "Test".to_owned(), "{}".to_owned());
|
||||
let new_account = account.change_password(first_password, sec_password, i).unwrap();
|
||||
assert!(account.sign(first_password, &message).is_ok());
|
||||
assert!(account.sign(sec_password, &message).is_err());
|
||||
|
||||
@@ -23,6 +23,7 @@ use ethkey::{Signature, Address, Message, Secret};
|
||||
use dir::KeyDirectory;
|
||||
use account::SafeAccount;
|
||||
use {Error, SecretStore};
|
||||
use json::UUID;
|
||||
|
||||
pub struct EthStore {
|
||||
dir: Box<KeyDirectory>,
|
||||
@@ -61,7 +62,7 @@ impl SecretStore for EthStore {
|
||||
fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error> {
|
||||
let keypair = try!(KeyPair::from_secret(secret).map_err(|_| Error::CreationFailed));
|
||||
let id: [u8; 16] = Random::random();
|
||||
let account = SafeAccount::create(&keypair, id, password, self.iterations);
|
||||
let account = SafeAccount::create(&keypair, id, password, self.iterations, UUID::from(id).into(), "{}".to_owned());
|
||||
let address = account.address.clone();
|
||||
try!(self.save(account));
|
||||
Ok(address)
|
||||
@@ -105,4 +106,46 @@ impl SecretStore for EthStore {
|
||||
let account = try!(cache.get(account).ok_or(Error::InvalidAccount));
|
||||
account.sign(password, message)
|
||||
}
|
||||
|
||||
fn uuid(&self, addr: &Address) -> Result<UUID, Error> {
|
||||
let cache = self.cache.read().unwrap();
|
||||
let account = try!(cache.get(addr).ok_or(Error::InvalidAccount));
|
||||
Ok(account.id.into())
|
||||
}
|
||||
|
||||
fn name(&self, addr: &Address) -> Result<String, Error> {
|
||||
let cache = self.cache.read().unwrap();
|
||||
let account = try!(cache.get(addr).ok_or(Error::InvalidAccount));
|
||||
Ok(account.name.clone())
|
||||
}
|
||||
|
||||
fn meta(&self, addr: &Address) -> Result<String, Error> {
|
||||
let cache = self.cache.read().unwrap();
|
||||
let account = try!(cache.get(addr).ok_or(Error::InvalidAccount));
|
||||
Ok(account.meta.clone())
|
||||
}
|
||||
|
||||
fn set_name(&self, addr: &Address, name: String) -> Result<(), Error> {
|
||||
let account = {
|
||||
let cache = self.cache.read().unwrap();
|
||||
let mut account = try!(cache.get(addr).ok_or(Error::InvalidAccount)).clone();
|
||||
account.name = name;
|
||||
account
|
||||
};
|
||||
|
||||
// save to file
|
||||
self.save(account)
|
||||
}
|
||||
|
||||
fn set_meta(&self, addr: &Address, meta: String) -> Result<(), Error> {
|
||||
let account = {
|
||||
let cache = self.cache.read().unwrap();
|
||||
let mut account = try!(cache.get(addr).ok_or(Error::InvalidAccount)).clone();
|
||||
account.meta = meta;
|
||||
account
|
||||
};
|
||||
|
||||
// save to file
|
||||
self.save(account)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@ pub struct KeyFile {
|
||||
pub version: Version,
|
||||
pub crypto: Crypto,
|
||||
pub address: H160,
|
||||
pub name: Option<String>,
|
||||
pub meta: Option<String>,
|
||||
}
|
||||
|
||||
enum KeyFileField {
|
||||
@@ -33,6 +35,8 @@ enum KeyFileField {
|
||||
Version,
|
||||
Crypto,
|
||||
Address,
|
||||
Name,
|
||||
Meta,
|
||||
}
|
||||
|
||||
impl Deserialize for KeyFileField {
|
||||
@@ -57,6 +61,8 @@ impl Visitor for KeyFileFieldVisitor {
|
||||
"crypto" => Ok(KeyFileField::Crypto),
|
||||
"Crypto" => Ok(KeyFileField::Crypto),
|
||||
"address" => Ok(KeyFileField::Address),
|
||||
"name" => Ok(KeyFileField::Name),
|
||||
"meta" => Ok(KeyFileField::Meta),
|
||||
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
|
||||
}
|
||||
}
|
||||
@@ -83,6 +89,8 @@ impl Visitor for KeyFileVisitor {
|
||||
let mut version = None;
|
||||
let mut crypto = None;
|
||||
let mut address = None;
|
||||
let mut name = None;
|
||||
let mut meta = None;
|
||||
|
||||
loop {
|
||||
match try!(visitor.visit_key()) {
|
||||
@@ -90,6 +98,8 @@ impl Visitor for KeyFileVisitor {
|
||||
Some(KeyFileField::Version) => { version = Some(try!(visitor.visit_value())); }
|
||||
Some(KeyFileField::Crypto) => { crypto = Some(try!(visitor.visit_value())); }
|
||||
Some(KeyFileField::Address) => { address = Some(try!(visitor.visit_value())); }
|
||||
Some(KeyFileField::Name) => { name = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
|
||||
Some(KeyFileField::Meta) => { meta = visitor.visit_value().ok(); } // ignore anyhing that is not a string to be permissive.
|
||||
None => { break; }
|
||||
}
|
||||
}
|
||||
@@ -121,6 +131,8 @@ impl Visitor for KeyFileVisitor {
|
||||
version: version,
|
||||
crypto: crypto,
|
||||
address: address,
|
||||
name: name,
|
||||
meta: meta,
|
||||
};
|
||||
|
||||
Ok(result)
|
||||
@@ -165,7 +177,9 @@ mod tests {
|
||||
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
|
||||
},
|
||||
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
|
||||
"version": 3
|
||||
"version": 3,
|
||||
"name": "Test",
|
||||
"meta": "{}"
|
||||
}"#;
|
||||
|
||||
let expected = KeyFile {
|
||||
@@ -186,6 +200,8 @@ mod tests {
|
||||
}),
|
||||
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
|
||||
},
|
||||
name: Some("Test".to_owned()),
|
||||
meta: Some("{}".to_owned()),
|
||||
};
|
||||
|
||||
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
|
||||
@@ -235,6 +251,8 @@ mod tests {
|
||||
}),
|
||||
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
|
||||
},
|
||||
name: None,
|
||||
meta: None,
|
||||
};
|
||||
|
||||
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
|
||||
@@ -261,9 +279,12 @@ mod tests {
|
||||
}),
|
||||
mac: H256::from_str("46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f").unwrap(),
|
||||
},
|
||||
name: Some("Test".to_owned()),
|
||||
meta: None,
|
||||
};
|
||||
|
||||
let serialized = serde_json::to_string(&file).unwrap();
|
||||
println!("{}", serialized);
|
||||
let deserialized = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
assert_eq!(file, deserialized);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
use ethkey::{Address, Message, Signature, Secret};
|
||||
use Error;
|
||||
use json::UUID;
|
||||
|
||||
pub trait SecretStore: Send + Sync {
|
||||
fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error>;
|
||||
@@ -27,5 +28,15 @@ pub trait SecretStore: Send + Sync {
|
||||
fn remove_account(&self, account: &Address, password: &str) -> Result<(), Error>;
|
||||
|
||||
fn sign(&self, account: &Address, password: &str, message: &Message) -> Result<Signature, Error>;
|
||||
|
||||
fn uuid(&self, account: &Address) -> Result<UUID, Error>;
|
||||
|
||||
fn name(&self, account: &Address) -> Result<String, Error>;
|
||||
|
||||
fn meta(&self, account: &Address) -> Result<String, Error>;
|
||||
|
||||
fn set_name(&self, address: &Address, name: String) -> Result<(), Error>;
|
||||
|
||||
fn set_meta(&self, address: &Address, meta: String) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user