From c1a88f88404ff6affdc97313b67085034e01bcb3 Mon Sep 17 00:00:00 2001 From: Nora Widdecke Date: Thu, 17 Feb 2022 16:48:55 +0100 Subject: [PATCH] web: handle wkd requests --- database/src/fs.rs | 15 ++++++++++++ database/src/lib.rs | 1 + src/web/mod.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++ src/web/wkd.rs | 26 +++++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 src/web/wkd.rs diff --git a/database/src/fs.rs b/database/src/fs.rs index c7f3a33..d45bf23 100644 --- a/database/src/fs.rs +++ b/database/src/fs.rs @@ -182,6 +182,15 @@ impl Filesystem { ].iter().collect() } + /// Returns the WKD path to the given url-encoded domain and wkd-encoded local part. + fn link_wkd_by_domain_and_hash(&self, domain: &str, hash: &str) -> PathBuf { + [ + &self.links_dir_wkd_by_email, + Path::new(&domain), + &path_split(hash) + ].iter().collect() + } + #[allow(clippy::nonminimal_bool)] fn read_from_path(&self, path: &Path, allow_internal: bool) -> Option { use std::fs; @@ -575,6 +584,12 @@ impl Database for Filesystem { self.read_from_path_bytes(&path, false) } + // XXX: slow + fn by_domain_and_hash_wkd(&self, domain: &str, hash: &str) -> Option> { + let path = self.link_wkd_by_domain_and_hash(domain, hash); + self.read_from_path_bytes(&path, false) + } + // XXX: slow fn by_kid(&self, kid: &KeyID) -> Option { let path = self.link_by_keyid(kid); diff --git a/database/src/lib.rs b/database/src/lib.rs index a1ca706..bca1514 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -149,6 +149,7 @@ pub trait Database: Sync + Send { fn by_kid(&self, kid: &KeyID) -> Option; fn by_email(&self, email: &Email) -> Option; fn by_email_wkd(&self, email: &Email) -> Option>; + fn by_domain_and_hash_wkd(&self, domain: &str, hash: &str) -> Option>; fn check_link_fpr(&self, fpr: &Fingerprint, target: &Fingerprint) -> Result>; diff --git a/src/web/mod.rs b/src/web/mod.rs index 78c7d2e..0c0e984 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -37,6 +37,7 @@ mod vks; mod vks_web; mod vks_api; mod debug_web; +mod wkd; use crate::web::maintenance::MaintenanceMode; @@ -68,6 +69,8 @@ pub enum MyResponse { Xml(HagridTemplate), #[response(status = 200, content_type = "application/pgp-keys")] Key(String, Header<'static>), + #[response(status = 200, content_type = "application/octet-stream")] + WkdKey(Vec, Header<'static>), #[response(status = 500, content_type = "html")] ServerError(Template), #[response(status = 404, content_type = "html")] @@ -120,6 +123,20 @@ impl MyResponse { MyResponse::Key(armored_key, content_disposition) } + pub fn wkd(binary_key: Vec, wkd_hash: &str) -> Self { + let content_disposition = Header::new( + rocket::http::hyper::header::CONTENT_DISPOSITION.as_str(), + ContentDisposition { + disposition: DispositionType::Attachment, + parameters: vec![ + DispositionParam::Filename( + Charset::Us_Ascii, None, + (wkd_hash.to_string() + ".pgp").into_bytes()), + ], + }.to_string()); + MyResponse::WkdKey(binary_key, content_disposition) + } + pub fn ise(e: anyhow::Error) -> Self { eprintln!("Internal error: {:?}", e); let ctx = templates::FiveHundred { @@ -383,6 +400,9 @@ fn rocket_factory(mut rocket: rocket::Rocket) -> Result>(), + tpk_.keys().map(|skb| skb.key().fingerprint()) + .collect::>()); + assert_eq!(tpk_.userids().count(), nr_uids); + } + + fn check_verify_link(client: &Client, token: &str, address: &str, lang: &'static str) { let encoded = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("token", token) diff --git a/src/web/wkd.rs b/src/web/wkd.rs new file mode 100644 index 0000000..f195b46 --- /dev/null +++ b/src/web/wkd.rs @@ -0,0 +1,26 @@ +use crate::database::{Database, KeyDatabase}; +use crate::web::MyResponse; + +// WKD queries +#[get("/.well-known/openpgpkey//hu/")] +pub fn wkd_query( + db: &rocket::State, + domain: String, + wkd_hash: String, +) -> MyResponse { + match db.by_domain_and_hash_wkd(&domain, &wkd_hash) { + Some(key) => MyResponse::wkd(key, &wkd_hash), + None => MyResponse::not_found_plain( + "No key found for this email address.", + ), + } +} + +// Policy requests. +// 200 response with an empty body. +#[get("/.well-known/openpgpkey/<_domain>/policy")] +pub fn wkd_policy( + _domain: String, +) -> MyResponse { + MyResponse::plain("".to_string()) +}