From 756101753bca95800ce2dfe6dcbfeedc4148b80d Mon Sep 17 00:00:00 2001 From: Katharina Fey Date: Thu, 12 Jul 2018 20:25:35 +0200 Subject: Adding a new keystore to lockchain-core::crypto, composing a userstore from two metadomains now (users, registry) to allow for a better user registry pipeline. Tweaking examples to make all this work and generally cleaning up code --- lockchain-core/src/crypto/keystore.rs | 59 ++++++++++++++++++++ lockchain-core/src/crypto/mod.rs | 4 +- lockchain-core/src/traits.rs | 2 +- lockchain-core/src/users/mod.rs | 102 ++++++++++++++++++++++++++-------- lockchain-files/examples/create.rs | 18 +++--- lockchain-files/src/lib.rs | 2 +- 6 files changed, 154 insertions(+), 33 deletions(-) create mode 100644 lockchain-core/src/crypto/keystore.rs diff --git a/lockchain-core/src/crypto/keystore.rs b/lockchain-core/src/crypto/keystore.rs new file mode 100644 index 0000000..0f19e30 --- /dev/null +++ b/lockchain-core/src/crypto/keystore.rs @@ -0,0 +1,59 @@ +//! A utility keystore module for the lockchain ecosystem + +use traits::{AutoEncoder, Base64AutoEncoder}; +use {crypto::Key, meta::MetaDomain}; + +use std::collections::HashMap; + +#[derive(Serialize, Deserialize)] +pub struct KeyStore { + keys: HashMap, +} + +impl KeyStore { + pub fn add_key(&mut self, user: &str, key: Key) { + self.keys.insert(user.into(), key); + } + + pub fn revoke_key(&mut self, user: &str) { + self.keys.remove(user); + } +} + +impl AutoEncoder for KeyStore {} + +impl From for KeyStore { + fn from(d: MetaDomain) -> Self { + Self { + keys: d + .all() + .iter() + .map(|(k, v)| { + ( + k.clone(), + match v { + ::Payload::Text(s) => Key::decode(&String::from_base64(s)).unwrap(), + _ => unreachable!(), + }, + ) + }) + .collect(), + } + } +} + +impl From for MetaDomain { + fn from(ks: KeyStore) -> Self { + MetaDomain::new("keystore").fill( + ks.keys + .iter() + .map(|(name, key)| { + ( + name.clone(), + ::Payload::Text(key.encode().unwrap().to_base64()), + ) + }) + .collect(), + ) + } +} diff --git a/lockchain-core/src/crypto/mod.rs b/lockchain-core/src/crypto/mod.rs index 6fa17bb..671cff0 100644 --- a/lockchain-core/src/crypto/mod.rs +++ b/lockchain-core/src/crypto/mod.rs @@ -13,10 +13,12 @@ mod keys { impl AutoEncoder for KeyType {} } -pub mod passwords; +// pub mod passwords; pub mod encoding; +pub mod keystore; pub mod hashing; pub mod random; pub use self::data::PackedData; +pub use self::keystore::KeyStore; pub use self::keys::{Key, KeyType}; diff --git a/lockchain-core/src/traits.rs b/lockchain-core/src/traits.rs index 088ee84..6498ac3 100644 --- a/lockchain-core/src/traits.rs +++ b/lockchain-core/src/traits.rs @@ -141,7 +141,7 @@ where /// returned with a single pull request fn meta_add_domain(&mut self, domain: &str) -> Option<()>; /// Returns all records from a meta domain - fn meta_pull_domain(&mut self, domain: &str) -> Option<&MetaDomain>; + fn meta_pull_domain(&self, domain: &str) -> Option<&MetaDomain>; /// Entirely replace a meta domain in the store fn meta_push_domain(&mut self, domain: MetaDomain) -> Option<()>; /// Set the value of a field inside a domain. Field names **must not** collide diff --git a/lockchain-core/src/users/mod.rs b/lockchain-core/src/users/mod.rs index 0077427..03cbcb4 100644 --- a/lockchain-core/src/users/mod.rs +++ b/lockchain-core/src/users/mod.rs @@ -29,22 +29,24 @@ use { /// Specifies access to a resource #[derive(Hash, Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum Access { - /// Allows specific access to an entire API - Api, /// Allows access to vault metadata & index files - Vault(String), + Vault(Role), /// Allows access to a record resource inside a vault - Record(String, String), + Record(Role, String), } +impl AutoEncoder for Access {} + /// Specifies the capabilities of a user -#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] +#[derive(Hash, Serialize, Deserialize, Clone, PartialEq, Eq)] pub enum Role { Reader, Editor, Admin, } +impl AutoEncoder for Role {} + /// A generic user representation /// /// A user has an identify check built in that can verify a passphrase @@ -102,21 +104,38 @@ impl User { impl AutoEncoder for User {} -/// A utility structure that manages users and can be derived +/// A utility structure that manages users and can be derived /// from/into a metadata object. By default this process uses /// base64 encoding. -/// +/// /// The workflow for this is to create a new `UserStore`, add -/// users and then use `meta_push_domain` and give it the +/// users and then use `meta_push_domain` and give it the /// `UserStore::into()` which is then encoded automatically. /// The reverse action works the same way #[derive(Serialize, Deserialize)] pub struct UserStore { /// A map between username – user item users: HashMap, + registry: HashMap>, } impl UserStore { + /// Generate a sign-up token for a new user which needs to be + /// provided in order for them to create an account. + pub fn get_token(&mut self, access: Vec) -> String { + let token = ::crypto::encoding::base64_encode(&::crypto::random::bytes(128)); + self.registry.insert( + token.clone(), + if access.is_empty() { + vec![Access::Vault(Role::Reader)] + } else { + access + }, + ); + + token + } + pub fn get_user(&self, name: &str) -> Option<&User> { self.users.get(name) } @@ -135,6 +154,7 @@ impl Default for UserStore { fn default() -> Self { Self { users: HashMap::new(), + registry: HashMap::new(), } } } @@ -145,10 +165,10 @@ impl AutoEncoder for UserStore {} /// that *are* userstores into a UserStore easily /// /// Will most likely `panic!` if called on a non UserStore -impl From for UserStore { - fn from(md: MetaDomain) -> Self { +impl From<(MetaDomain, MetaDomain)> for UserStore { + fn from((users, registry): (MetaDomain, MetaDomain)) -> Self { Self { - users: md + users: users .all() .iter() .map(|(k, v)| { @@ -161,22 +181,60 @@ impl From for UserStore { ) }) .collect(), - } - } -} - -impl From for MetaDomain { - fn from(us: UserStore) -> Self { - MetaDomain::new("userstore").fill( - us.users + registry: registry + .all() .iter() - .map(|(name, user)| { + .map(|(k, v)| { ( - name.clone(), - ::Payload::Text(user.encode().unwrap().to_base64()), + k.clone(), + match v { + ::Payload::List(regs) => regs + .iter() + .map(|reg| { + Access::decode(&String::from_base64(match reg { + ::Payload::Text(s) => s, + _ => unreachable!(), + })).unwrap() + }) + .collect(), + _ => unreachable!(), + }, ) }) .collect(), + } + } +} + +impl From for (MetaDomain, MetaDomain) { + fn from(us: UserStore) -> Self { + ( + MetaDomain::new("userstore").fill( + us.users + .iter() + .map(|(name, user)| { + ( + name.clone(), + ::Payload::Text(user.encode().unwrap().to_base64()), + ) + }) + .collect(), + ), + MetaDomain::new("registry").fill( + us.registry + .iter() + .map(|(name, reg)| { + ( + name.clone(), + ::Payload::List( + reg.iter() + .map(|reg| ::Payload::Text(reg.encode().unwrap().to_base64())) + .collect(), + ), + ) + }) + .collect(), + ), ) } } diff --git a/lockchain-files/examples/create.rs b/lockchain-files/examples/create.rs index db2b8e9..4b19180 100644 --- a/lockchain-files/examples/create.rs +++ b/lockchain-files/examples/create.rs @@ -13,20 +13,22 @@ fn main() { let name = env::args().nth(2).unwrap(); let mut vault: DataVault = DataVault::new(&name, &path); - let mut store = match vault.meta_pull_domain("userstore") { - Some(m) => m.clone().into(), + let mut store = match ( + vault.meta_pull_domain("userstore"), + vault.meta_pull_domain("registry"), + ) { + (Some(users), Some(registry)) => (users.clone(), registry.clone()).into(), _ => UserStore::default(), }; /* Some users of our vault have the same password :S */ store.add(User::register("alice", "password")); - store.add(User::register("bob", "password")); - store.add(User::register("carol", "password")); - store.add(User::register("darius", "password")); - store.add(User::register("elena", "password")); - store.add(User::register("farah", "password")); + let token = store.get_token(vec!()); - vault.meta_push_domain(store.into()); + let (users, registry) = store.into(); + + vault.meta_push_domain(users); + vault.meta_push_domain(registry); vault.sync(); } else { eprintln!("Usage: create [FLAGS] (there are no flags)") diff --git a/lockchain-files/src/lib.rs b/lockchain-files/src/lib.rs index cdbfecb..24f212e 100644 --- a/lockchain-files/src/lib.rs +++ b/lockchain-files/src/lib.rs @@ -123,7 +123,7 @@ impl Vault for DataVault { } } - fn meta_pull_domain(&mut self, domain: &str) -> Option<&MetaDomain> { + fn meta_pull_domain(&self, domain: &str) -> Option<&MetaDomain> { self.metadata.get(domain) } -- cgit v1.2.3