2016-06-20 10:06:49 +02:00
|
|
|
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
|
|
|
// This file is part of Parity.
|
|
|
|
|
|
|
|
// Parity is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
|
|
|
// Parity is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2016-06-20 00:10:34 +02:00
|
|
|
use std::collections::BTreeMap;
|
2016-07-31 10:44:17 +02:00
|
|
|
use std::mem;
|
2016-06-20 00:10:34 +02:00
|
|
|
use ethkey::KeyPair;
|
|
|
|
use crypto::KEY_ITERATIONS;
|
|
|
|
use random::Random;
|
2016-10-15 14:44:08 +02:00
|
|
|
use ethkey::{Signature, Address, Message, Secret, Public};
|
2016-06-20 00:10:34 +02:00
|
|
|
use dir::KeyDirectory;
|
|
|
|
use account::SafeAccount;
|
2016-11-30 15:08:38 +01:00
|
|
|
use {Error, SimpleSecretStore, SecretStore};
|
2016-08-10 17:57:40 +02:00
|
|
|
use json;
|
2016-07-24 17:38:21 +02:00
|
|
|
use json::UUID;
|
2016-10-25 22:34:52 +02:00
|
|
|
use parking_lot::RwLock;
|
2016-08-10 17:57:40 +02:00
|
|
|
use presale::PresaleWallet;
|
2016-08-11 18:31:28 +02:00
|
|
|
use import;
|
2016-06-20 00:10:34 +02:00
|
|
|
|
|
|
|
pub struct EthStore {
|
2016-11-30 15:08:38 +01:00
|
|
|
store: EthMultiStore,
|
2016-06-20 00:10:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl EthStore {
|
|
|
|
pub fn open(directory: Box<KeyDirectory>) -> Result<Self, Error> {
|
|
|
|
Self::open_with_iterations(directory, KEY_ITERATIONS as u32)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn open_with_iterations(directory: Box<KeyDirectory>, iterations: u32) -> Result<Self, Error> {
|
2016-11-30 15:08:38 +01:00
|
|
|
Ok(EthStore {
|
|
|
|
store: try!(EthMultiStore::open_with_iterations(directory, iterations)),
|
|
|
|
})
|
2016-06-20 00:10:34 +02:00
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn get(&self, address: &Address) -> Result<SafeAccount, Error> {
|
|
|
|
let mut accounts = try!(self.store.get(address)).into_iter();
|
|
|
|
accounts.next().ok_or(Error::InvalidAccount)
|
|
|
|
}
|
|
|
|
}
|
2016-06-20 00:10:34 +02:00
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
impl SimpleSecretStore for EthStore {
|
|
|
|
fn insert_account(&self, secret: Secret, password: &str) -> Result<Address, Error> {
|
|
|
|
self.store.insert_account(secret, password)
|
2016-06-20 00:10:34 +02:00
|
|
|
}
|
2016-07-31 10:44:17 +02:00
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn accounts(&self) -> Result<Vec<Address>, Error> {
|
|
|
|
self.store.accounts()
|
2016-07-31 10:44:17 +02:00
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn change_password(&self, address: &Address, old_password: &str, new_password: &str) -> Result<(), Error> {
|
|
|
|
self.store.change_password(address, old_password, new_password)
|
2016-07-31 10:44:17 +02:00
|
|
|
}
|
2016-06-20 00:10:34 +02:00
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn remove_account(&self, address: &Address, password: &str) -> Result<(), Error> {
|
|
|
|
self.store.remove_account(address, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sign(&self, address: &Address, password: &str, message: &Message) -> Result<Signature, Error> {
|
|
|
|
let account = try!(self.get(address));
|
|
|
|
account.sign(password, message)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn decrypt(&self, account: &Address, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
|
|
|
let account = try!(self.get(account));
|
|
|
|
account.decrypt(password, shared_mac, message)
|
2016-06-20 00:10:34 +02:00
|
|
|
}
|
2016-11-30 15:08:38 +01:00
|
|
|
}
|
2016-06-20 00:10:34 +02:00
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
impl SecretStore for EthStore {
|
2016-08-10 17:57:40 +02:00
|
|
|
fn import_presale(&self, json: &[u8], password: &str) -> Result<Address, Error> {
|
|
|
|
let json_wallet = try!(json::PresaleWallet::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned())));
|
|
|
|
let wallet = PresaleWallet::from(json_wallet);
|
|
|
|
let keypair = try!(wallet.decrypt(password).map_err(|_| Error::InvalidPassword));
|
|
|
|
self.insert_account(keypair.secret().clone(), password)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn import_wallet(&self, json: &[u8], password: &str) -> Result<Address, Error> {
|
|
|
|
let json_keyfile = try!(json::KeyFile::load(json).map_err(|_| Error::InvalidKeyFile("Invalid JSON format".to_owned())));
|
|
|
|
let mut safe_account = SafeAccount::from_file(json_keyfile, None);
|
|
|
|
let secret = try!(safe_account.crypto.secret(password).map_err(|_| Error::InvalidPassword));
|
|
|
|
safe_account.address = try!(KeyPair::from_secret(secret)).address();
|
|
|
|
let address = safe_account.address.clone();
|
2016-11-30 15:08:38 +01:00
|
|
|
try!(self.store.save(safe_account));
|
2016-08-10 17:57:40 +02:00
|
|
|
Ok(address)
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn test_password(&self, address: &Address, password: &str) -> Result<bool, Error> {
|
2016-07-31 10:44:17 +02:00
|
|
|
let account = try!(self.get(address));
|
2016-11-30 15:08:38 +01:00
|
|
|
Ok(account.check_password(password))
|
2016-06-20 00:10:34 +02:00
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn copy_account(&self, new_store: &SimpleSecretStore, address: &Address, password: &str, new_password: &str) -> Result<(), Error> {
|
2016-11-30 13:47:14 +01:00
|
|
|
let account = try!(self.get(address));
|
2016-11-30 15:08:38 +01:00
|
|
|
let secret = try!(account.crypto.secret(password));
|
|
|
|
try!(new_store.insert_account(secret, new_password));
|
|
|
|
Ok(())
|
2016-09-22 14:48:22 +02:00
|
|
|
}
|
|
|
|
|
2016-10-15 14:44:08 +02:00
|
|
|
fn public(&self, account: &Address, password: &str) -> Result<Public, Error> {
|
|
|
|
let account = try!(self.get(account));
|
|
|
|
account.public(password)
|
|
|
|
}
|
|
|
|
|
2016-07-31 10:44:17 +02:00
|
|
|
fn uuid(&self, address: &Address) -> Result<UUID, Error> {
|
|
|
|
let account = try!(self.get(address));
|
2016-07-24 17:38:21 +02:00
|
|
|
Ok(account.id.into())
|
|
|
|
}
|
|
|
|
|
2016-07-31 10:44:17 +02:00
|
|
|
fn name(&self, address: &Address) -> Result<String, Error> {
|
|
|
|
let account = try!(self.get(address));
|
2016-07-24 17:38:21 +02:00
|
|
|
Ok(account.name.clone())
|
|
|
|
}
|
|
|
|
|
2016-07-31 10:44:17 +02:00
|
|
|
fn meta(&self, address: &Address) -> Result<String, Error> {
|
|
|
|
let account = try!(self.get(address));
|
2016-07-24 17:38:21 +02:00
|
|
|
Ok(account.meta.clone())
|
|
|
|
}
|
|
|
|
|
2016-07-31 10:44:17 +02:00
|
|
|
fn set_name(&self, address: &Address, name: String) -> Result<(), Error> {
|
|
|
|
let mut account = try!(self.get(address));
|
|
|
|
account.name = name;
|
|
|
|
|
2016-07-24 17:38:21 +02:00
|
|
|
// save to file
|
2016-11-30 15:08:38 +01:00
|
|
|
self.store.save(account)
|
2016-07-24 17:38:21 +02:00
|
|
|
}
|
|
|
|
|
2016-07-31 10:44:17 +02:00
|
|
|
fn set_meta(&self, address: &Address, meta: String) -> Result<(), Error> {
|
|
|
|
let mut account = try!(self.get(address));
|
|
|
|
account.meta = meta;
|
|
|
|
|
2016-07-24 17:38:21 +02:00
|
|
|
// save to file
|
2016-11-30 15:08:38 +01:00
|
|
|
self.store.save(account)
|
2016-07-24 17:38:21 +02:00
|
|
|
}
|
2016-08-11 18:31:28 +02:00
|
|
|
|
|
|
|
fn local_path(&self) -> String {
|
2016-11-30 15:08:38 +01:00
|
|
|
self.store.dir.path().map(|p| p.to_string_lossy().into_owned()).unwrap_or_else(|| String::new())
|
2016-08-11 18:31:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn list_geth_accounts(&self, testnet: bool) -> Vec<Address> {
|
|
|
|
import::read_geth_accounts(testnet)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn import_geth_accounts(&self, desired: Vec<Address>, testnet: bool) -> Result<Vec<Address>, Error> {
|
2016-11-30 15:08:38 +01:00
|
|
|
import::import_geth_accounts(&*self.store.dir, desired.into_iter().collect(), testnet)
|
2016-08-11 18:31:28 +02:00
|
|
|
}
|
2016-06-20 00:10:34 +02:00
|
|
|
}
|
2016-11-30 13:47:14 +01:00
|
|
|
|
|
|
|
/// Similar to `EthStore` but may store many accounts (with different passwords) for the same `Address`
|
|
|
|
pub struct EthMultiStore {
|
|
|
|
dir: Box<KeyDirectory>,
|
|
|
|
iterations: u32,
|
|
|
|
cache: RwLock<BTreeMap<Address, Vec<SafeAccount>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EthMultiStore {
|
|
|
|
|
|
|
|
pub fn open(directory: Box<KeyDirectory>) -> Result<Self, Error> {
|
|
|
|
Self::open_with_iterations(directory, KEY_ITERATIONS as u32)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn open_with_iterations(directory: Box<KeyDirectory>, iterations: u32) -> Result<Self, Error> {
|
2016-11-30 15:08:38 +01:00
|
|
|
let store = EthMultiStore {
|
2016-11-30 13:47:14 +01:00
|
|
|
dir: directory,
|
|
|
|
iterations: iterations,
|
|
|
|
cache: Default::default(),
|
|
|
|
};
|
|
|
|
try!(store.reload_accounts());
|
|
|
|
Ok(store)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reload_accounts(&self) -> Result<(), Error> {
|
|
|
|
let mut cache = self.cache.write();
|
|
|
|
let accounts = try!(self.dir.load());
|
|
|
|
|
|
|
|
let mut new_accounts = BTreeMap::new();
|
|
|
|
for account in accounts {
|
|
|
|
let mut entry = new_accounts.entry(account.address.clone()).or_insert_with(Vec::new);
|
|
|
|
entry.push(account);
|
|
|
|
}
|
|
|
|
mem::replace(&mut *cache, new_accounts);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get(&self, address: &Address) -> Result<Vec<SafeAccount>, Error> {
|
|
|
|
{
|
|
|
|
let cache = self.cache.read();
|
|
|
|
if let Some(accounts) = cache.get(address) {
|
|
|
|
if !accounts.is_empty() {
|
|
|
|
return Ok(accounts.clone())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try!(self.reload_accounts());
|
|
|
|
let cache = self.cache.read();
|
|
|
|
let accounts = try!(cache.get(address).cloned().ok_or(Error::InvalidAccount));
|
|
|
|
if accounts.is_empty() {
|
|
|
|
Err(Error::InvalidAccount)
|
|
|
|
} else {
|
|
|
|
Ok(accounts)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn save(&self, account: SafeAccount) -> Result<(), Error> {
|
2016-11-30 13:47:14 +01:00
|
|
|
//save to file
|
|
|
|
let account = try!(self.dir.insert(account));
|
|
|
|
|
|
|
|
// update cache
|
|
|
|
let mut cache = self.cache.write();
|
|
|
|
let mut accounts = cache.entry(account.address.clone()).or_insert_with(Vec::new);
|
2016-11-30 16:21:57 +01:00
|
|
|
// TODO [ToDr] That is crappy way of overcoming set_name, set_meta, etc.
|
|
|
|
// Avoid cloning instead!
|
|
|
|
accounts.retain(|acc| acc.filename != account.filename);
|
2016-11-30 13:47:14 +01:00
|
|
|
accounts.push(account);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl SimpleSecretStore for EthMultiStore {
|
|
|
|
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, "".to_owned(), "{}".to_owned());
|
|
|
|
let address = account.address.clone();
|
|
|
|
try!(self.save(account));
|
|
|
|
Ok(address)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accounts(&self) -> Result<Vec<Address>, Error> {
|
|
|
|
try!(self.reload_accounts());
|
|
|
|
Ok(self.cache.read().keys().cloned().collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn remove_account(&self, address: &Address, password: &str) -> Result<(), Error> {
|
2016-11-30 13:47:14 +01:00
|
|
|
let accounts = try!(self.get(address));
|
|
|
|
|
|
|
|
for account in accounts {
|
|
|
|
// Skip if password is invalid
|
|
|
|
if !account.check_password(password) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove from dir
|
|
|
|
try!(self.dir.remove(&account));
|
|
|
|
|
|
|
|
// Remove from cache
|
|
|
|
let mut cache = self.cache.write();
|
|
|
|
let is_empty = {
|
|
|
|
let mut accounts = cache.get_mut(address).expect("Entry exists, because it was returned by `get`; qed");
|
|
|
|
if let Some(position) = accounts.iter().position(|acc| acc == &account) {
|
|
|
|
accounts.remove(position);
|
|
|
|
}
|
|
|
|
accounts.is_empty()
|
|
|
|
};
|
|
|
|
|
|
|
|
if is_empty {
|
|
|
|
cache.remove(address);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
Err(Error::InvalidPassword)
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn change_password(&self, address: &Address, old_password: &str, new_password: &str) -> Result<(), Error> {
|
2016-11-30 13:47:14 +01:00
|
|
|
let accounts = try!(self.get(address));
|
|
|
|
for account in accounts {
|
|
|
|
// First remove
|
|
|
|
try!(self.remove_account(&address, old_password));
|
|
|
|
// Then insert back with new password
|
|
|
|
let new_account = try!(account.change_password(old_password, new_password, self.iterations));
|
2016-11-30 15:08:38 +01:00
|
|
|
try!(self.save(new_account));
|
2016-11-30 13:47:14 +01:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn sign(&self, address: &Address, password: &str, message: &Message) -> Result<Signature, Error> {
|
2016-11-30 13:47:14 +01:00
|
|
|
let accounts = try!(self.get(address));
|
|
|
|
for account in accounts {
|
|
|
|
if account.check_password(password) {
|
|
|
|
return account.sign(password, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Err(Error::InvalidPassword)
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
fn decrypt(&self, account: &Address, password: &str, shared_mac: &[u8], message: &[u8]) -> Result<Vec<u8>, Error> {
|
2016-11-30 13:47:14 +01:00
|
|
|
let accounts = try!(self.get(account));
|
|
|
|
for account in accounts {
|
|
|
|
if account.check_password(password) {
|
|
|
|
return account.decrypt(password, shared_mac, message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(Error::InvalidPassword)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-30 15:08:38 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2016-11-30 16:41:37 +01:00
|
|
|
#[test]
|
2016-11-30 15:08:38 +01:00
|
|
|
fn should_have_some_tests() {
|
|
|
|
assert_eq!(true, false)
|
|
|
|
}
|
|
|
|
}
|