diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index c5e17100f..23e82d010 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -425,17 +425,17 @@ enum KeyFileLoadError { pub struct KeyDirectory { /// Directory path for key management. path: String, - cache: HashMap, - cache_usage: VecDeque, + cache: RefCell>, + cache_usage: RefCell>, } impl KeyDirectory { /// Initializes new cache directory context with a given `path` pub fn new(path: &Path) -> KeyDirectory { KeyDirectory { - cache: HashMap::new(), + cache: RefCell::new(HashMap::new()), path: path.to_str().expect("Initialized key directory with empty path").to_owned(), - cache_usage: VecDeque::new(), + cache_usage: RefCell::new(VecDeque::new()), } } @@ -448,25 +448,34 @@ impl KeyDirectory { let json_bytes = json_text.into_bytes(); try!(file.write(&json_bytes)); } + let mut cache = self.cache.borrow_mut(); let id = key_file.id.clone(); - self.cache.insert(id.clone(), key_file); + cache.insert(id.clone(), key_file); Ok(id.clone()) } /// Returns key given by id if corresponding file exists and no load error occured. /// Warns if any error occured during the key loading - pub fn get(&mut self, id: &Uuid) -> Option<&KeyFileContent> { + pub fn get(&self, id: &Uuid) -> Option> { let path = self.key_path(id); - self.cache_usage.push_back(id.clone()); - Some(self.cache.entry(id.to_owned()).or_insert( + { + let mut usage = self.cache_usage.borrow_mut(); + usage.push_back(id.clone()); + } + + if !self.cache.borrow().contains_key(id) { match KeyDirectory::load_key(&path) { - Ok(loaded_key) => loaded_key, + Ok(loaded_key) => { + self.cache.borrow_mut().insert(id.to_owned(), loaded_key); + } Err(error) => { warn!(target: "sstore", "error loading key {:?}: {:?}", id, error); return None; } } - )) + } + + Some(Ref::map(self.cache.borrow(), |c| c.get(id).expect("should be they key, we have just inserted or checked it"))) } /// Returns current path to the directory with keys @@ -476,29 +485,32 @@ impl KeyDirectory { /// Removes keys that never been requested during last `MAX_USAGE_TRACK` times pub fn collect_garbage(&mut self) { - let total_usages = self.cache_usage.len(); + let mut cache_usage = self.cache_usage.borrow_mut(); + + let total_usages = cache_usage.len(); let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize; if untracked_usages > 0 { - self.cache_usage.drain(..untracked_usages); + cache_usage.drain(..untracked_usages); } - if self.cache.len() <= MAX_CACHE_USAGE_TRACK { return; } + let mut cache = self.cache.borrow_mut(); + if cache.len() <= MAX_CACHE_USAGE_TRACK { return; } - let uniqs: HashSet<&Uuid> = self.cache_usage.iter().collect(); + let uniqs: HashSet<&Uuid> = cache_usage.iter().collect(); let mut removes = HashSet::new(); - for key in self.cache.keys() { + for key in cache.keys() { if !uniqs.contains(key) { removes.insert(key.clone()); } } - for removed_key in removes { self.cache.remove(&removed_key); } + for removed_key in removes { cache.remove(&removed_key); } } /// Reports how many keys are currently cached. pub fn cache_size(&self) -> usize { - self.cache.len() + self.cache.borrow().len() } fn key_path(&self, id: &Uuid) -> PathBuf { diff --git a/util/src/keys/encryptor.rs b/util/src/keys/encryptor.rs new file mode 100644 index 000000000..cbc926dc6 --- /dev/null +++ b/util/src/keys/encryptor.rs @@ -0,0 +1,65 @@ +// 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 . + +//! Generic Encryptor + +use keys::directory::*; +use common::*; + +pub trait EncryptedHashMap { + // Returns existing value for the key, if any + fn get(&self, key: &Key, password: &str) -> Option; + // Insert new encrypted key-value and returns previous if there was any + fn insert(&mut self, key: Key, value: Value, password: &str) -> Option; + // Removes key-value by key and returns the removed one, if any exists and password was provided + fn remove (&mut self, key: &Key, password: Option<&str>) -> Option; + // Deletes key-value by key and returns if the key-value existed + fn delete(&mut self, key: &Key) -> bool { + self.remove::<()>(key, None).is_some() + } +} + +pub struct SecretStore { + directory: KeyDirectory +} + +impl EncryptedHashMap for SecretStore { + fn get(&self, key: &H128, password: &str) -> Option { + match self.directory.get(key) { + Some(key_file) => { + let mut instance = Value::default(); + instance.populate_raw(&key_file.crypto.cipher_text); + Some(instance) + }, + None => None + } + + } + + fn insert(&mut self, key: H128, value: Value, password: &str) -> Option{ + let previous = if let Some(key_file) = self.directory.get(&key) { self.get(&key, password) } else { None }; + previous + } + + fn remove(&mut self, key: &H128, password: Option<&str>) -> Option { + let previous = match (self.directory.get(&key), password) { + (Some(key_file), Some(pass)) => self.get(&key, pass), + (_, _) => None + }; + previous + } + +} diff --git a/util/src/keys/mod.rs b/util/src/keys/mod.rs index d7ffdb0dd..f886d362c 100644 --- a/util/src/keys/mod.rs +++ b/util/src/keys/mod.rs @@ -17,3 +17,5 @@ //! Key management module pub mod directory; + +mod encryptor; diff --git a/util/src/lib.rs b/util/src/lib.rs index d4f972800..151afb60a 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -20,6 +20,7 @@ #![feature(associated_consts)] #![feature(plugin)] #![feature(catch_panic)] +#![feature(cell_extras)] // Clippy settings #![plugin(clippy)] // TODO [todr] not really sure