web: handle wkd requests
This commit is contained in:
parent
8eb3984560
commit
70711191f1
|
@ -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()
|
||||
}
|
||||
|
||||
fn read_from_path(&self, path: &Path, allow_internal: bool) -> Option<String> {
|
||||
use std::fs;
|
||||
|
||||
|
@ -579,6 +588,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<Vec<u8>> {
|
||||
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<String> {
|
||||
let path = self.link_by_keyid(kid);
|
||||
|
|
|
@ -153,6 +153,7 @@ pub trait Database: Sync + Send {
|
|||
fn by_kid(&self, kid: &KeyID) -> Option<String>;
|
||||
fn by_email(&self, email: &Email) -> Option<String>;
|
||||
fn by_email_wkd(&self, email: &Email) -> Option<Vec<u8>>;
|
||||
fn by_domain_and_hash_wkd(&self, domain: &str, hash: &str) -> Option<Vec<u8>>;
|
||||
|
||||
fn check_link_fpr(&self, fpr: &Fingerprint, target: &Fingerprint) -> Result<Option<Fingerprint>>;
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ mod vks;
|
|||
mod vks_web;
|
||||
mod vks_api;
|
||||
mod debug_web;
|
||||
mod wkd;
|
||||
|
||||
use crate::web::maintenance::MaintenanceMode;
|
||||
|
||||
|
@ -69,6 +70,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<u8>, Header<'static>),
|
||||
#[response(status = 500, content_type = "html")]
|
||||
ServerError(Template),
|
||||
#[response(status = 404, content_type = "html")]
|
||||
|
@ -121,6 +124,20 @@ impl MyResponse {
|
|||
MyResponse::Key(armored_key, content_disposition)
|
||||
}
|
||||
|
||||
pub fn wkd(binary_key: Vec<u8>, 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 {
|
||||
|
@ -384,6 +401,9 @@ fn rocket_factory(mut rocket: rocket::Rocket<rocket::Build>) -> Result<rocket::R
|
|||
hkp::pks_add_form,
|
||||
hkp::pks_add_form_data,
|
||||
hkp::pks_internal_index,
|
||||
// WKD
|
||||
wkd::wkd_policy,
|
||||
wkd::wkd_query,
|
||||
// Manage
|
||||
manage::vks_manage,
|
||||
manage::vks_manage_key,
|
||||
|
@ -941,6 +961,12 @@ pub mod tests {
|
|||
Status::BadRequest, "not supported");
|
||||
|
||||
}
|
||||
#[test]
|
||||
fn wkd_policy() {
|
||||
let (_tmpdir, client) = client().unwrap();
|
||||
check_response(&client, "/.well-known/openpgpkey/example.org/policy",
|
||||
Status::Ok, "");
|
||||
}
|
||||
|
||||
/// Asserts that the given URI 404s.
|
||||
pub fn check_null_response(client: &Client, uri: &str) {
|
||||
|
@ -957,6 +983,11 @@ pub mod tests {
|
|||
check_null_response(
|
||||
&client, &format!("/pks/lookup?op=get&options=mr&search={}",
|
||||
addr));
|
||||
|
||||
let (wkd_hash, domain) = crate::database::wkd::encode_wkd(addr).unwrap();
|
||||
check_null_response(
|
||||
&client,
|
||||
&format!("/.well-known/openpgpkey/{}/hu/{}", domain, wkd_hash));
|
||||
}
|
||||
|
||||
/// Asserts that lookups by the given email are successful.
|
||||
|
@ -982,6 +1013,12 @@ pub mod tests {
|
|||
&client,
|
||||
&format!("/search?q={}", addr),
|
||||
&tpk, nr_uids);
|
||||
|
||||
let (wkd_hash, domain) = crate::database::wkd::encode_wkd(addr).unwrap();
|
||||
check_wkd_response(
|
||||
&client,
|
||||
&format!("/.well-known/openpgpkey/{}/hu/{}", domain, wkd_hash),
|
||||
&tpk, nr_uids);
|
||||
}
|
||||
|
||||
/// Asserts that the given URI returns a Cert matching the given
|
||||
|
@ -1137,6 +1174,25 @@ pub mod tests {
|
|||
&tpk, nr_uids);
|
||||
}
|
||||
|
||||
/// Asserts that the given URI returns correct WKD response with a Cert
|
||||
/// matching the given one, with the given number of userids.
|
||||
pub fn check_wkd_response(client: &Client, uri: &str, tpk: &Cert,
|
||||
nr_uids: usize) {
|
||||
let response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(),
|
||||
Some(ContentType::new("application", "octet-stream")));
|
||||
let body = response.into_bytes().unwrap();
|
||||
let tpk_ = Cert::from_bytes(&body).unwrap();
|
||||
assert_eq!(tpk.fingerprint(), tpk_.fingerprint());
|
||||
assert_eq!(tpk.keys().map(|skb| skb.key().fingerprint())
|
||||
.collect::<Vec<_>>(),
|
||||
tpk_.keys().map(|skb| skb.key().fingerprint())
|
||||
.collect::<Vec<_>>());
|
||||
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)
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
use crate::database::{Database, KeyDatabase};
|
||||
use crate::web::MyResponse;
|
||||
|
||||
// WKD queries
|
||||
#[get("/.well-known/openpgpkey/<domain>/hu/<wkd_hash>")]
|
||||
pub fn wkd_query(
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
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())
|
||||
}
|
Loading…
Reference in New Issue