work in progress
This commit is contained in:
parent
482292551b
commit
734652d913
@ -425,17 +425,17 @@ enum KeyFileLoadError {
|
|||||||
pub struct KeyDirectory {
|
pub struct KeyDirectory {
|
||||||
/// Directory path for key management.
|
/// Directory path for key management.
|
||||||
path: String,
|
path: String,
|
||||||
cache: HashMap<Uuid, KeyFileContent>,
|
cache: RefCell<HashMap<Uuid, KeyFileContent>>,
|
||||||
cache_usage: VecDeque<Uuid>,
|
cache_usage: RefCell<VecDeque<Uuid>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyDirectory {
|
impl KeyDirectory {
|
||||||
/// Initializes new cache directory context with a given `path`
|
/// Initializes new cache directory context with a given `path`
|
||||||
pub fn new(path: &Path) -> KeyDirectory {
|
pub fn new(path: &Path) -> KeyDirectory {
|
||||||
KeyDirectory {
|
KeyDirectory {
|
||||||
cache: HashMap::new(),
|
cache: RefCell::new(HashMap::new()),
|
||||||
path: path.to_str().expect("Initialized key directory with empty path").to_owned(),
|
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();
|
let json_bytes = json_text.into_bytes();
|
||||||
try!(file.write(&json_bytes));
|
try!(file.write(&json_bytes));
|
||||||
}
|
}
|
||||||
|
let mut cache = self.cache.borrow_mut();
|
||||||
let id = key_file.id.clone();
|
let id = key_file.id.clone();
|
||||||
self.cache.insert(id.clone(), key_file);
|
cache.insert(id.clone(), key_file);
|
||||||
Ok(id.clone())
|
Ok(id.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns key given by id if corresponding file exists and no load error occured.
|
/// Returns key given by id if corresponding file exists and no load error occured.
|
||||||
/// Warns if any error occured during the key loading
|
/// 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<Ref<KeyFileContent>> {
|
||||||
let path = self.key_path(id);
|
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) {
|
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) => {
|
Err(error) => {
|
||||||
warn!(target: "sstore", "error loading key {:?}: {:?}", id, error);
|
warn!(target: "sstore", "error loading key {:?}: {:?}", id, error);
|
||||||
return None;
|
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
|
/// 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
|
/// Removes keys that never been requested during last `MAX_USAGE_TRACK` times
|
||||||
pub fn collect_garbage(&mut self) {
|
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;
|
let untracked_usages = max(total_usages as i64 - MAX_CACHE_USAGE_TRACK as i64, 0) as usize;
|
||||||
if untracked_usages > 0 {
|
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();
|
let mut removes = HashSet::new();
|
||||||
|
|
||||||
for key in self.cache.keys() {
|
for key in cache.keys() {
|
||||||
if !uniqs.contains(key) {
|
if !uniqs.contains(key) {
|
||||||
removes.insert(key.clone());
|
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.
|
/// Reports how many keys are currently cached.
|
||||||
pub fn cache_size(&self) -> usize {
|
pub fn cache_size(&self) -> usize {
|
||||||
self.cache.len()
|
self.cache.borrow().len()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn key_path(&self, id: &Uuid) -> PathBuf {
|
fn key_path(&self, id: &Uuid) -> PathBuf {
|
||||||
|
65
util/src/keys/encryptor.rs
Normal file
65
util/src/keys/encryptor.rs
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Generic Encryptor
|
||||||
|
|
||||||
|
use keys::directory::*;
|
||||||
|
use common::*;
|
||||||
|
|
||||||
|
pub trait EncryptedHashMap<Key: Hash + Eq> {
|
||||||
|
// Returns existing value for the key, if any
|
||||||
|
fn get<Value: Populatable + Default>(&self, key: &Key, password: &str) -> Option<Value>;
|
||||||
|
// Insert new encrypted key-value and returns previous if there was any
|
||||||
|
fn insert<Value: Populatable + Default>(&mut self, key: Key, value: Value, password: &str) -> Option<Value>;
|
||||||
|
// Removes key-value by key and returns the removed one, if any exists and password was provided
|
||||||
|
fn remove<Value: Populatable + Default> (&mut self, key: &Key, password: Option<&str>) -> Option<Value>;
|
||||||
|
// 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<H128> for SecretStore {
|
||||||
|
fn get<Value: Populatable + Default>(&self, key: &H128, password: &str) -> Option<Value> {
|
||||||
|
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<Value: Populatable + Default>(&mut self, key: H128, value: Value, password: &str) -> Option<Value>{
|
||||||
|
let previous = if let Some(key_file) = self.directory.get(&key) { self.get(&key, password) } else { None };
|
||||||
|
previous
|
||||||
|
}
|
||||||
|
|
||||||
|
fn remove<Value: Populatable + Default>(&mut self, key: &H128, password: Option<&str>) -> Option<Value> {
|
||||||
|
let previous = match (self.directory.get(&key), password) {
|
||||||
|
(Some(key_file), Some(pass)) => self.get(&key, pass),
|
||||||
|
(_, _) => None
|
||||||
|
};
|
||||||
|
previous
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -17,3 +17,5 @@
|
|||||||
//! Key management module
|
//! Key management module
|
||||||
|
|
||||||
pub mod directory;
|
pub mod directory;
|
||||||
|
|
||||||
|
mod encryptor;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#![feature(associated_consts)]
|
#![feature(associated_consts)]
|
||||||
#![feature(plugin)]
|
#![feature(plugin)]
|
||||||
#![feature(catch_panic)]
|
#![feature(catch_panic)]
|
||||||
|
#![feature(cell_extras)]
|
||||||
// Clippy settings
|
// Clippy settings
|
||||||
#![plugin(clippy)]
|
#![plugin(clippy)]
|
||||||
// TODO [todr] not really sure
|
// TODO [todr] not really sure
|
||||||
|
Loading…
Reference in New Issue
Block a user