From 851ea659b64c1f4b28fd191612ea94d29a2dc5ba Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 27 Apr 2019 00:21:30 +0200 Subject: [PATCH] drop polymorphic database abstraction --- database/src/lib.rs | 6 +- database/src/memory.rs | 198 ----------------------------------------- database/src/poly.rs | 115 ------------------------ src/delete.rs | 6 +- src/import.rs | 6 +- src/web/hkp.rs | 8 +- src/web/manage.rs | 10 +-- src/web/mod.rs | 32 +++---- src/web/upload.rs | 14 +-- 9 files changed, 36 insertions(+), 359 deletions(-) delete mode 100644 database/src/memory.rs delete mode 100644 database/src/poly.rs diff --git a/database/src/lib.rs b/database/src/lib.rs index fb78ae7..dee2d49 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -45,11 +45,7 @@ pub mod sync; use sync::MutexGuard; mod fs; -pub use self::fs::Filesystem; -mod memory; -pub use self::memory::Memory; -mod poly; -pub use self::poly::Polymorphic; +pub use self::fs::Filesystem as KeyDatabase; mod stateful_tokens; pub use stateful_tokens::StatefulTokens; diff --git a/database/src/memory.rs b/database/src/memory.rs deleted file mode 100644 index abb91d9..0000000 --- a/database/src/memory.rs +++ /dev/null @@ -1,198 +0,0 @@ -use parking_lot::Mutex; -use std::collections::HashMap; - -use {Database, Query}; -use types::{Email, Fingerprint, KeyID}; -use sync::MutexGuard; -use Result; - -#[derive(Debug)] -pub struct Memory { - update_lock: Mutex<()>, - - fpr: Mutex>, - - fpr_links: Mutex>, - email: Mutex>, - kid: Mutex>, -} - -impl Default for Memory { - fn default() -> Self { - Memory { - update_lock: Mutex::new(()), - fpr: Mutex::new(HashMap::default()), - fpr_links: Mutex::new(HashMap::default()), - kid: Mutex::new(HashMap::default()), - email: Mutex::new(HashMap::default()), - } - } -} - -impl Database for Memory { - fn lock(&self) -> MutexGuard<()> { - self.update_lock.lock().into() - } - - fn update( - &self, fpr: &Fingerprint, new: Option, - ) -> Result<()> { - let mut fprs = self.fpr.lock(); - - if let Some(new) = new { - fprs.insert(fpr.clone(), new); - } else { - fprs.remove(fpr); - } - - Ok(()) - } - - fn lookup_primary_fingerprint(&self, term: &Query) -> Option { - use self::Query::*; - match term { - ByFingerprint(ref fp) => - if self.fpr.lock().contains_key(fp) { - Some(fp.clone()) - } else { - self.fpr_links.lock().get(fp).map(|fp| fp.clone()) - }, - ByKeyID(ref keyid) => - self.kid.lock().get(keyid).map(|fp| fp.clone()), - ByEmail(ref email) => - self.email.lock().get(email).map(|fp| fp.clone()), - } - } - - fn link_fpr(&self, from: &Fingerprint, fpr: &Fingerprint) -> Result<()> { - self.fpr_links.lock().insert(from.clone(), fpr.clone()); - Ok(()) - } - - fn unlink_fpr(&self, from: &Fingerprint, _: &Fingerprint) -> Result<()> { - self.fpr_links.lock().remove(from); - Ok(()) - } - - fn link_email(&self, email: &Email, fpr: &Fingerprint) -> Result<()> { - self.email.lock().insert(email.clone(), fpr.clone()); - Ok(()) - } - - fn unlink_email(&self, email: &Email, _: &Fingerprint) -> Result<()> { - self.email.lock().remove(email); - Ok(()) - } - - fn link_kid(&self, kid: &KeyID, fpr: &Fingerprint) -> Result<()> { - self.kid.lock().insert(kid.clone(), fpr.clone()); - Ok(()) - } - - fn unlink_kid(&self, kid: &KeyID, _: &Fingerprint) -> Result<()> { - self.kid.lock().remove(kid); - Ok(()) - } - - fn by_fpr(&self, fpr: &Fingerprint) -> Option { - let fprs = self.fpr.lock(); - let links = self.fpr_links.lock(); - - fprs.get(fpr).map(|x| x.clone()).or_else(|| { - links.get(fpr).and_then(|fpr| fprs.get(fpr).map(|x| x.clone())) - }) - } - - fn by_email(&self, email: &Email) -> Option { - let fprs = self.fpr.lock(); - let by_email = self.email.lock(); - - by_email.get(email).and_then(|fpr| fprs.get(fpr).map(|x| x.clone())) - } - - fn by_kid(&self, kid: &KeyID) -> Option { - let fprs = self.fpr.lock(); - let by_kid = self.kid.lock(); - - by_kid.get(kid).and_then(|fpr| fprs.get(fpr).map(|x| x.clone())) - } -} - -impl Memory { - pub fn new_token() -> String { - use rand::distributions::Alphanumeric; - use rand::{thread_rng, Rng}; - - let mut rng = thread_rng(); - // samples from [a-zA-Z0-9] - // 43 chars ~ 256 bit - rng.sample_iter(&Alphanumeric).take(43).collect() - } -} - -#[cfg(test)] -mod tests { - use super::*; - use test; - use openpgp::tpk::TPKBuilder; - - #[test] - fn new() { - let db = Memory::default(); - let k1 = TPKBuilder::default().add_userid("a@invalid.example.org") - .generate().unwrap().0; - let k2 = TPKBuilder::default().add_userid("b@invalid.example.org") - .generate().unwrap().0; - let k3 = TPKBuilder::default().add_userid("c@invalid.example.org") - .generate().unwrap().0; - - assert!(db.merge_or_publish(&k1).unwrap().len() > 0); - assert!(db.merge_or_publish(&k2).unwrap().len() > 0); - assert!(!db.merge_or_publish(&k2).unwrap().len() > 0); - assert!(db.merge_or_publish(&k3).unwrap().len() > 0); - assert!(!db.merge_or_publish(&k3).unwrap().len() > 0); - assert!(!db.merge_or_publish(&k3).unwrap().len() > 0); - } - - #[test] - fn uid_verification() { - let mut db = Memory::default(); - - test::test_uid_verification(&mut db); - } - - #[test] - fn subkey_lookup() { - let mut db = Memory::default(); - - test::test_subkey_lookup(&mut db); - } - - #[test] - fn kid_lookup() { - let mut db = Memory::default(); - - test::test_kid_lookup(&mut db); - } - - #[test] - fn uid_revocation() { - let mut db = Memory::default(); - - test::test_uid_revocation(&mut db); - } - - #[test] - fn test_same_email_1() { - let mut db = Memory::default(); - - test::test_same_email_1(&mut db); - } - - #[test] - fn test_same_email_2() { - let mut db = Memory::default(); - - test::test_same_email_2(&mut db); - } -} diff --git a/database/src/poly.rs b/database/src/poly.rs deleted file mode 100644 index 1ab20ff..0000000 --- a/database/src/poly.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::path::PathBuf; - -use {Database, Filesystem, Memory, Query}; -use Result; -use types::{Email, Fingerprint, KeyID}; -use sync::MutexGuard; - -pub enum Polymorphic { - Memory(Memory), - Filesystem(Filesystem), -} - -impl Database for Polymorphic { - fn lock(&self) -> MutexGuard<()> { - match self { - &Polymorphic::Memory(ref db) => db.lock(), - &Polymorphic::Filesystem(ref db) => db.lock(), - } - } - - fn update( - &self, fpr: &Fingerprint, new: Option, - ) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => { - db.update(fpr, new) - } - &Polymorphic::Filesystem(ref db) => { - db.update(fpr, new) - } - } - } - - fn lookup_primary_fingerprint(&self, term: &Query) -> Option { - match self { - &Polymorphic::Memory(ref db) => - db.lookup_primary_fingerprint(term), - &Polymorphic::Filesystem(ref db) => - db.lookup_primary_fingerprint(term), - } - } - - /// Gets the path to the underlying file, if any. - fn lookup_path(&self, term: &Query) -> Option { - match self { - &Polymorphic::Memory(ref db) => - db.lookup_path(term), - &Polymorphic::Filesystem(ref db) => - db.lookup_path(term), - } - } - - fn link_fpr(&self, from: &Fingerprint, fpr: &Fingerprint) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => db.link_fpr(from, fpr), - &Polymorphic::Filesystem(ref db) => db.link_fpr(from, fpr), - } - } - - fn unlink_fpr(&self, from: &Fingerprint, fpr: &Fingerprint) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => db.unlink_fpr(from, fpr), - &Polymorphic::Filesystem(ref db) => db.unlink_fpr(from, fpr), - } - } - - fn link_kid(&self, kid: &KeyID, fpr: &Fingerprint) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => db.link_kid(kid, fpr), - &Polymorphic::Filesystem(ref db) => db.link_kid(kid, fpr), - } - } - - fn unlink_kid(&self, kid: &KeyID, fpr: &Fingerprint) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => db.unlink_kid(kid, fpr), - &Polymorphic::Filesystem(ref db) => db.unlink_kid(kid, fpr), - } - } - - fn link_email(&self, email: &Email, fpr: &Fingerprint) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => db.link_email(email, fpr), - &Polymorphic::Filesystem(ref db) => db.link_email(email, fpr), - } - } - - fn unlink_email(&self, email: &Email, fpr: &Fingerprint) -> Result<()> { - match self { - &Polymorphic::Memory(ref db) => db.unlink_email(email, fpr), - &Polymorphic::Filesystem(ref db) => db.unlink_email(email, fpr), - } - } - - fn by_fpr(&self, fpr: &Fingerprint) -> Option { - match self { - &Polymorphic::Memory(ref db) => db.by_fpr(fpr), - &Polymorphic::Filesystem(ref db) => db.by_fpr(fpr), - } - } - - fn by_email(&self, email: &Email) -> Option { - match self { - &Polymorphic::Memory(ref db) => db.by_email(email), - &Polymorphic::Filesystem(ref db) => db.by_email(email), - } - } - - fn by_kid(&self, kid: &KeyID) -> Option { - match self { - &Polymorphic::Memory(ref db) => db.by_kid(kid), - &Polymorphic::Filesystem(ref db) => db.by_kid(kid), - } - } -} diff --git a/src/delete.rs b/src/delete.rs index 198c97a..924fef2 100644 --- a/src/delete.rs +++ b/src/delete.rs @@ -11,7 +11,7 @@ extern crate structopt; use structopt::StructOpt; extern crate hagrid_database as database; -use database::{Query, Database, Filesystem}; +use database::{Query, Database, KeyDatabase}; #[derive(Debug, StructOpt)] #[structopt( @@ -51,11 +51,11 @@ fn main() { fn real_main() -> Result<()> { let opt = Opt::from_args(); - let db = Filesystem::new_from_base(opt.base.canonicalize()?)?; + let db = KeyDatabase::new_from_base(opt.base.canonicalize()?)?; delete(&db, &opt.query.parse()?, opt.all_bindings, opt.all) } -fn delete(db: &Filesystem, query: &Query, all_bindings: bool, mut all: bool) +fn delete(db: &KeyDatabase, query: &Query, all_bindings: bool, mut all: bool) -> Result<()> { match query { Query::ByFingerprint(_) | Query::ByKeyID(_) => { diff --git a/src/import.rs b/src/import.rs index ad9a6cc..4eaea08 100644 --- a/src/import.rs +++ b/src/import.rs @@ -25,7 +25,7 @@ use openpgp::Packet; use openpgp::parse::{PacketParser, PacketParserResult, Parse}; extern crate hagrid_database as database; -use database::{Database, Filesystem}; +use database::{Database, KeyDatabase}; fn main() { let args: Vec = env::args().collect(); @@ -56,7 +56,7 @@ fn main() { } fn do_import(base: PathBuf, keyrings: Vec) -> Result<()> { - let db = Filesystem::new_from_base(base)?; + let db = KeyDatabase::new_from_base(base)?; // For each input file, create a parser. for input in keyrings.iter() { @@ -110,7 +110,7 @@ mod import_tests { fn import() { let root = tempdir().unwrap(); - let db = Filesystem::new_from_base(root.path().to_path_buf()).unwrap(); + let db = KeyDatabase::new_from_base(root.path().to_path_buf()).unwrap(); // Generate a key and import it. let (tpk, _) = openpgp::tpk::TPKBuilder::autocrypt( diff --git a/src/web/hkp.rs b/src/web/hkp.rs index ba53cdf..57e40e3 100644 --- a/src/web/hkp.rs +++ b/src/web/hkp.rs @@ -6,7 +6,7 @@ use rocket::http::{ContentType, Status}; use rocket::request::{self, Request, FromRequest}; use rocket::http::uri::Uri; -use database::{Database, Query, Polymorphic}; +use database::{Database, Query, KeyDatabase}; use database::types::{Email, Fingerprint, KeyID}; use web::{ @@ -109,7 +109,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Hkp { #[post("/pks/add", data = "")] pub fn pks_add( - db: rocket::State, + db: rocket::State, cont_type: &ContentType, data: Data, ) -> MyResponse { @@ -121,7 +121,7 @@ pub fn pks_add( #[get("/pks/lookup")] pub fn pks_lookup(state: rocket::State, - db: rocket::State, + db: rocket::State, key: Hkp) -> MyResponse { let query_string = key.to_string(); let (query, index, machine_readable) = match key { @@ -144,7 +144,7 @@ pub fn pks_lookup(state: rocket::State, } } -fn key_to_hkp_index<'a>(db: rocket::State, query: Query) +fn key_to_hkp_index<'a>(db: rocket::State, query: Query) -> MyResponse { use sequoia_openpgp::RevocationStatus; diff --git a/src/web/manage.rs b/src/web/manage.rs index 930fcdc..603afc5 100644 --- a/src/web/manage.rs +++ b/src/web/manage.rs @@ -5,7 +5,7 @@ use rocket::request::Form; use failure::Fallible as Result; use web::{HagridState, MyResponse, templates::General}; -use database::{Database, Polymorphic, types::Email}; +use database::{Database, KeyDatabase, types::Email}; use mail; use tokens; @@ -54,7 +54,7 @@ pub fn vks_manage() -> Result { #[get("/manage/")] pub fn vks_manage_key( state: rocket::State, - db: State, + db: State, token: String, token_service: rocket::State, ) -> MyResponse { @@ -100,7 +100,7 @@ pub fn vks_manage_key( #[post("/manage", data="")] pub fn vks_manage_post( - db: State, + db: State, request: Form, token_service: rocket::State, mail_service: Option>, @@ -148,7 +148,7 @@ pub fn vks_manage_post( #[post("/manage/unpublish", data="")] pub fn vks_manage_unpublish( state: rocket::State, - db: rocket::State, + db: rocket::State, token_service: rocket::State, request: Form, ) -> MyResponse { @@ -160,7 +160,7 @@ pub fn vks_manage_unpublish( pub fn vks_manage_unpublish_or_fail( state: rocket::State, - db: rocket::State, + db: rocket::State, token_service: rocket::State, request: Form, ) -> Result { diff --git a/src/web/mod.rs b/src/web/mod.rs index 2d21f17..63269eb 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -13,7 +13,7 @@ pub mod upload; use mail; use tokens; -use database::{Database, Polymorphic, Query, StatefulTokens}; +use database::{Database, KeyDatabase, Query, StatefulTokens}; use database::types::{Email, Fingerprint, KeyID}; use Result; @@ -179,7 +179,7 @@ pub struct HagridState { } fn key_to_response<'a>(state: rocket::State, - db: rocket::State, + db: rocket::State, query_string: String, query: Query, machine_readable: bool) @@ -225,7 +225,7 @@ fn key_to_response<'a>(state: rocket::State, MyResponse::ok("found", context) } -fn key_has_uids(state: &HagridState, db: &Polymorphic, query: &Query) +fn key_has_uids(state: &HagridState, db: &KeyDatabase, query: &Query) -> Result { use sequoia_openpgp::Packet; use sequoia_openpgp::parse::{Parse, PacketParser, PacketParserResult}; @@ -250,7 +250,7 @@ pub fn get_link_by_fingerprint(fpr: &Fingerprint) -> String { #[get("/vks/v1/by-fingerprint/")] fn vks_v1_by_fingerprint(state: rocket::State, - db: rocket::State, + db: rocket::State, fpr: String) -> MyResponse { let query = match Fingerprint::from_str(&fpr) { Ok(fpr) => Query::ByFingerprint(fpr), @@ -262,7 +262,7 @@ fn vks_v1_by_fingerprint(state: rocket::State, #[get("/vks/v1/by-email/")] fn vks_v1_by_email(state: rocket::State, - db: rocket::State, + db: rocket::State, email: String) -> MyResponse { let query = match Email::from_str(&email) { Ok(email) => Query::ByEmail(email), @@ -274,7 +274,7 @@ fn vks_v1_by_email(state: rocket::State, #[get("/vks/v1/by-keyid/")] fn vks_v1_by_keyid(state: rocket::State, - db: rocket::State, + db: rocket::State, kid: String) -> MyResponse { let query = match KeyID::from_str(&kid) { Ok(keyid) => Query::ByKeyID(keyid), @@ -286,7 +286,7 @@ fn vks_v1_by_keyid(state: rocket::State, #[get("/publish/")] fn publish_verify( - db: rocket::State, + db: rocket::State, token_service: rocket::State, token: String, ) -> MyResponse { @@ -297,7 +297,7 @@ fn publish_verify( } fn publish_verify_or_fail( - db: rocket::State, + db: rocket::State, token_service: rocket::State, token: String, ) -> Result { @@ -391,14 +391,12 @@ fn rocket_factory(rocket: rocket::Rocket) -> Result { ) } -fn configure_db_service(config: &Config) -> Result { - use database::{Filesystem, Polymorphic}; - +fn configure_db_service(config: &Config) -> Result { let keys_dir: PathBuf = config.get_str("keys_dir")?.into(); let tmp_dir: PathBuf = config.get_str("tmp_dir")?.into(); - let fs_db = Filesystem::new(keys_dir, tmp_dir)?; - Ok(Polymorphic::Filesystem(fs_db)) + let fs_db = KeyDatabase::new(keys_dir, tmp_dir)?; + Ok(fs_db) } fn configure_hagrid_state(config: &Config) -> Result { @@ -521,12 +519,8 @@ pub mod tests { } pub fn assert_consistency(rocket: &rocket::Rocket) { - let db = rocket.state::().unwrap(); - if let Polymorphic::Filesystem(fs) = db { - fs.check_consistency().unwrap(); - } else { - unreachable!(); - } + let db = rocket.state::().unwrap(); + db.check_consistency().unwrap(); } #[test] diff --git a/src/web/upload.rs b/src/web/upload.rs index b582d32..79af6ed 100644 --- a/src/web/upload.rs +++ b/src/web/upload.rs @@ -8,7 +8,7 @@ use multipart::server::Multipart; use rocket::http::ContentType; use rocket::Data; -use database::{Database, Polymorphic, StatefulTokens}; +use database::{Database, KeyDatabase, StatefulTokens}; use mail; use web::MyResponse; @@ -45,7 +45,7 @@ pub fn publish(guide: bool) -> MyResponse { #[post("/vks/v1/publish", data = "")] pub fn vks_v1_publish_post( - db: rocket::State, + db: rocket::State, mail_service: rocket::State, token_service: rocket::State, cont_type: &ContentType, @@ -57,7 +57,7 @@ pub fn vks_v1_publish_post( } } pub fn handle_upload_without_verify( - db: rocket::State, + db: rocket::State, cont_type: &ContentType, data: Data, ) -> Result { @@ -66,7 +66,7 @@ pub fn handle_upload_without_verify( // signature requires the request to have a `Content-Type` pub fn handle_upload( - db: rocket::State, cont_type: &ContentType, data: Data, + db: rocket::State, cont_type: &ContentType, data: Data, services: Option<(rocket::State, rocket::State)>, ) -> Result { if cont_type.is_form_data() { @@ -119,7 +119,7 @@ pub fn handle_upload( } fn process_upload( - boundary: &str, data: Data, db: &Polymorphic, + boundary: &str, data: Data, db: &KeyDatabase, services: Option<(rocket::State, rocket::State)>, ) -> Result { // saves all fields, any field longer than 10kB goes to a temporary directory @@ -137,7 +137,7 @@ fn process_upload( } fn process_multipart( - entries: Entries, db: &Polymorphic, + entries: Entries, db: &KeyDatabase, services: Option<(rocket::State, rocket::State)>, ) -> Result { match entries.fields.get("keytext") { @@ -156,7 +156,7 @@ fn process_multipart( fn process_key( reader: R, - db: &Polymorphic, + db: &KeyDatabase, services: Option<(rocket::State, rocket::State)>, ) -> Result where