Move HKP handing to a new module.

This commit is contained in:
Justus Winter 2019-03-12 12:18:28 +01:00
parent 8ba3f38270
commit 090f4b5f33
No known key found for this signature in database
GPG Key ID: 686F55B4AB2B3386
3 changed files with 358 additions and 340 deletions

333
src/web/hkp.rs Normal file
View File

@ -0,0 +1,333 @@
use std::fmt;
use rocket::Data;
use rocket::Outcome;
use rocket::http::{ContentType, Status};
use rocket::request::{self, Request, FromRequest};
use database::{Database, Query, Polymorphic};
use database::types::{Email, Fingerprint, KeyID};
use web::{
MyResponse,
State,
key_to_response,
upload,
};
#[derive(Debug)]
pub enum Hkp {
Fingerprint { fpr: Fingerprint, index: bool, machine_readable: bool },
KeyID { keyid: KeyID, index: bool, machine_readable: bool },
Email { email: Email, index: bool, machine_readable: bool },
Invalid{ query: String, },
}
impl fmt::Display for Hkp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Hkp::Fingerprint{ ref fpr,.. } => write!(f, "{}", fpr),
Hkp::KeyID{ ref keyid,.. } => write!(f, "{}", keyid),
Hkp::Email{ ref email,.. } => write!(f, "{}", email),
Hkp::Invalid{ ref query } => write!(f, "{}", query),
}
}
}
impl<'a, 'r> FromRequest<'a, 'r> for Hkp {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Hkp, ()> {
use std::str::FromStr;
use rocket::request::FormItems;
use std::collections::HashMap;
let query = request.uri().query().unwrap_or("");
let fields = FormItems::from(query)
.map(|item| {
let (k, v) = item.key_value();
let key = k.url_decode().unwrap_or_default();
let value = v.url_decode().unwrap_or_default();
(key, value)
})
.collect::<HashMap<_, _>>();
if fields.contains_key("search")
&& fields
.get("op")
.map(|x| x == "get" || x == "index")
.unwrap_or(false)
{
let index = fields.get("op").map(|x| x == "index").unwrap_or(false);
let machine_readable =
fields.get("options").map(|x| x.contains("mr"))
.unwrap_or(false);
let search = fields.get("search").cloned().unwrap_or_default();
let maybe_fpr = Fingerprint::from_str(&search);
let maybe_keyid = KeyID::from_str(&search);
if let Ok(fpr) = maybe_fpr {
Outcome::Success(Hkp::Fingerprint {
fpr: fpr,
index: index,
machine_readable: machine_readable,
})
} else if let Ok(keyid) = maybe_keyid {
Outcome::Success(Hkp::KeyID {
keyid: keyid,
index: index,
machine_readable: machine_readable,
})
} else {
match Email::from_str(&search) {
Ok(email) => {
Outcome::Success(Hkp::Email {
email: email,
index: index,
machine_readable: machine_readable,
})
}
Err(_) => {
Outcome::Success(Hkp::Invalid{
query: search
})
}
}
}
} else if fields.get("op").map(|x| x == "vindex"
|| x.starts_with("x-"))
.unwrap_or(false)
{
Outcome::Failure((Status::NotImplemented, ()))
} else {
Outcome::Failure((Status::BadRequest, ()))
}
}
}
#[post("/pks/add", data = "<data>")]
pub fn pks_add(db: rocket::State<Polymorphic>, cont_type: &ContentType, data: Data,
state: rocket::State<State>)
-> MyResponse {
match upload::handle_upload(db, cont_type, data, None, state) {
Ok(_) => MyResponse::plain("Ok".into()),
Err(err) => MyResponse::ise(err),
}
}
#[get("/pks/lookup")]
pub fn pks_lookup(state: rocket::State<State>,
db: rocket::State<Polymorphic>,
key: Hkp) -> MyResponse {
let query_string = key.to_string();
let (query, index, machine_readable) = match key {
Hkp::Fingerprint { fpr, index, machine_readable } =>
(Query::ByFingerprint(fpr), index, machine_readable),
Hkp::KeyID { keyid, index, machine_readable } =>
(Query::ByKeyID(keyid), index, machine_readable),
Hkp::Email { email, index, machine_readable } => {
(Query::ByEmail(email), index, machine_readable)
}
Hkp::Invalid { query: _ } => {
return MyResponse::not_found(None, None);
}
};
if index {
key_to_hkp_index(db, query)
} else {
key_to_response(state, db, query_string, query, machine_readable)
}
}
fn key_to_hkp_index<'a>(db: rocket::State<Polymorphic>, query: Query)
-> MyResponse {
use sequoia_openpgp::RevocationStatus;
let tpk = match db.lookup(&query) {
Ok(Some(tpk)) => tpk,
Ok(None) => return MyResponse::not_found(None, None),
Err(err) => { return MyResponse::ise(err); }
};
let mut out = String::default();
let p = tpk.primary();
let ctime = tpk
.primary_key_signature()
.and_then(|x| x.signature_creation_time())
.map(|x| format!("{}", x.to_timespec().sec))
.unwrap_or_default();
let extime = tpk
.primary_key_signature()
.and_then(|x| x.signature_expiration_time())
.map(|x| format!("{}", x))
.unwrap_or_default();
let is_exp = tpk
.primary_key_signature()
.and_then(|x| {
if x.signature_expired() { "e" } else { "" }.into()
})
.unwrap_or_default();
let is_rev =
if tpk.revoked(None) != RevocationStatus::NotAsFarAsWeKnow {
"r"
} else {
""
};
let algo: u8 = p.pk_algo().into();
out.push_str("info:1:1\r\n");
out.push_str(&format!(
"pub:{}:{}:{}:{}:{}:{}{}\r\n",
p.fingerprint().to_string().replace(" ", ""),
algo,
p.mpis().bits(),
ctime,
extime,
is_exp,
is_rev
));
for uid in tpk.userids() {
let u =
url::form_urlencoded::byte_serialize(uid.userid().userid())
.fold(String::default(), |acc, x| acc + x);
let ctime = uid
.binding_signature()
.and_then(|x| x.signature_creation_time())
.map(|x| format!("{}", x.to_timespec().sec))
.unwrap_or_default();
let extime = uid
.binding_signature()
.and_then(|x| x.signature_expiration_time())
.map(|x| format!("{}", x))
.unwrap_or_default();
let is_exp = uid
.binding_signature()
.and_then(|x| {
if x.signature_expired() { "e" } else { "" }.into()
})
.unwrap_or_default();
let is_rev = if uid.revoked(None)
!= RevocationStatus::NotAsFarAsWeKnow
{
"r"
} else {
""
};
out.push_str(&format!(
"uid:{}:{}:{}:{}{}\r\n",
u, ctime, extime, is_exp, is_rev
));
}
MyResponse::plain(out)
}
#[cfg(test)]
mod tests {
use rocket::http::Status;
use rocket::http::ContentType;
use sequoia_openpgp::tpk::TPKBuilder;
use sequoia_openpgp::serialize::Serialize;
use web::tests::*;
#[test]
fn hkp() {
let (tmpdir, client) = client().unwrap();
let filemail_into = tmpdir.path().join("filemail");
// eprintln!("LEAKING: {:?}", tmpdir);
// ::std::mem::forget(tmpdir);
// Generate a key and upload it.
let (tpk, _) = TPKBuilder::autocrypt(
None, Some("foo@invalid.example.com".into()))
.generate().unwrap();
// Prepare to /pks/add
let mut armored = Vec::new();
{
use sequoia_openpgp::armor::{Writer, Kind};
let mut w = Writer::new(&mut armored, Kind::PublicKey, &[])
.unwrap();
tpk.serialize(&mut w).unwrap();
}
let mut post_data = String::from("keytext=");
for enc in url::form_urlencoded::byte_serialize(&armored) {
post_data.push_str(enc);
}
// Add!
let mut response = client.post("/pks/add")
.body(post_data.as_bytes())
.header(ContentType::Form)
.dispatch();
assert_eq!(response.status(), Status::Ok);
let body = response.body_string().unwrap();
eprintln!("response: {}", body);
// Check that we do not get a confirmation mail.
let confirm_mail = pop_mail(filemail_into.as_path()).unwrap();
assert!(confirm_mail.is_none());
// We should not be able to look it up by email address.
check_null_responses_by_email(&client, "foo@invalid.example.com");
// And check that we can get it back via the machine readable
// interface.
check_mr_responses_by_fingerprint(&client, &tpk, 0);
// And check that we can see the human-readable result page.
check_hr_responses_by_fingerprint(&client, &tpk);
assert_consistency(client.rocket());
}
#[test]
fn hkp_add_two() {
let (tmpdir, client) = client().unwrap();
let filemail_into = tmpdir.path().join("filemail");
// Generate two keys and upload them.
let tpk_0 = TPKBuilder::autocrypt(
None, Some("foo@invalid.example.com".into()))
.generate().unwrap().0;
let tpk_1 = TPKBuilder::autocrypt(
None, Some("bar@invalid.example.com".into()))
.generate().unwrap().0;
// Prepare to /pks/add
let mut armored = Vec::new();
{
use sequoia_openpgp::armor::{Writer, Kind};
let mut w = Writer::new(&mut armored, Kind::PublicKey, &[])
.unwrap();
tpk_0.serialize(&mut w).unwrap();
tpk_1.serialize(&mut w).unwrap();
}
let mut post_data = String::from("keytext=");
for enc in url::form_urlencoded::byte_serialize(&armored) {
post_data.push_str(enc);
}
// Add!
let response = client.post("/pks/add")
.body(post_data.as_bytes())
.header(ContentType::Form)
.dispatch();
assert_eq!(response.status(), Status::Ok);
let confirm_mail = pop_mail(filemail_into.as_path()).unwrap();
assert!(confirm_mail.is_none());
check_mr_responses_by_fingerprint(&client, &tpk_0, 0);
check_mr_responses_by_fingerprint(&client, &tpk_1, 0);
check_hr_responses_by_fingerprint(&client, &tpk_0);
check_hr_responses_by_fingerprint(&client, &tpk_1);
assert_consistency(client.rocket());
}
}

View File

@ -10,7 +10,7 @@ use handlebars::Handlebars;
use std::path::PathBuf;
mod upload;
pub mod upload;
use mail;
use database::{Database, Polymorphic, Query};
@ -20,104 +20,7 @@ use Result;
use std::result;
use std::str::FromStr;
mod queries {
use std::fmt;
use rocket::request::{self, Request, FromRequest};
use rocket::http::Status;
use rocket::Outcome;
use database::types::{Email, Fingerprint, KeyID};
#[derive(Debug)]
pub enum Hkp {
Fingerprint { fpr: Fingerprint, index: bool, machine_readable: bool },
KeyID { keyid: KeyID, index: bool, machine_readable: bool },
Email { email: Email, index: bool, machine_readable: bool },
Invalid{ query: String, },
}
impl fmt::Display for Hkp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Hkp::Fingerprint{ ref fpr,.. } => write!(f, "{}", fpr),
Hkp::KeyID{ ref keyid,.. } => write!(f, "{}", keyid),
Hkp::Email{ ref email,.. } => write!(f, "{}", email),
Hkp::Invalid{ ref query } => write!(f, "{}", query),
}
}
}
impl<'a, 'r> FromRequest<'a, 'r> for Hkp {
type Error = ();
fn from_request(request: &'a Request<'r>) -> request::Outcome<Hkp, ()> {
use std::str::FromStr;
use rocket::request::FormItems;
use std::collections::HashMap;
let query = request.uri().query().unwrap_or("");
let fields = FormItems::from(query)
.map(|item| {
let (k, v) = item.key_value();
let key = k.url_decode().unwrap_or_default();
let value = v.url_decode().unwrap_or_default();
(key, value)
})
.collect::<HashMap<_, _>>();
if fields.contains_key("search")
&& fields
.get("op")
.map(|x| x == "get" || x == "index")
.unwrap_or(false)
{
let index = fields.get("op").map(|x| x == "index").unwrap_or(false);
let machine_readable =
fields.get("options").map(|x| x.contains("mr"))
.unwrap_or(false);
let search = fields.get("search").cloned().unwrap_or_default();
let maybe_fpr = Fingerprint::from_str(&search);
let maybe_keyid = KeyID::from_str(&search);
if let Ok(fpr) = maybe_fpr {
Outcome::Success(Hkp::Fingerprint {
fpr: fpr,
index: index,
machine_readable: machine_readable,
})
} else if let Ok(keyid) = maybe_keyid {
Outcome::Success(Hkp::KeyID {
keyid: keyid,
index: index,
machine_readable: machine_readable,
})
} else {
match Email::from_str(&search) {
Ok(email) => {
Outcome::Success(Hkp::Email {
email: email,
index: index,
machine_readable: machine_readable,
})
}
Err(_) => {
Outcome::Success(Hkp::Invalid{
query: search
})
}
}
}
} else if fields.get("op").map(|x| x == "vindex"
|| x.starts_with("x-"))
.unwrap_or(false)
{
Outcome::Failure((Status::NotImplemented, ()))
} else {
Outcome::Failure((Status::BadRequest, ()))
}
}
}
}
mod hkp;
use rocket::http::hyper::header::ContentDisposition;
@ -362,92 +265,6 @@ fn key_has_uids(state: &State, db: &Polymorphic, query: &Query)
Ok(false)
}
fn key_to_hkp_index<'a>(db: rocket::State<Polymorphic>, query: Query)
-> MyResponse {
use sequoia_openpgp::RevocationStatus;
let tpk = match db.lookup(&query) {
Ok(Some(tpk)) => tpk,
Ok(None) => return MyResponse::not_found(None, None),
Err(err) => { return MyResponse::ise(err); }
};
let mut out = String::default();
let p = tpk.primary();
let ctime = tpk
.primary_key_signature()
.and_then(|x| x.signature_creation_time())
.map(|x| format!("{}", x.to_timespec().sec))
.unwrap_or_default();
let extime = tpk
.primary_key_signature()
.and_then(|x| x.signature_expiration_time())
.map(|x| format!("{}", x))
.unwrap_or_default();
let is_exp = tpk
.primary_key_signature()
.and_then(|x| {
if x.signature_expired() { "e" } else { "" }.into()
})
.unwrap_or_default();
let is_rev =
if tpk.revoked(None) != RevocationStatus::NotAsFarAsWeKnow {
"r"
} else {
""
};
let algo: u8 = p.pk_algo().into();
out.push_str("info:1:1\r\n");
out.push_str(&format!(
"pub:{}:{}:{}:{}:{}:{}{}\r\n",
p.fingerprint().to_string().replace(" ", ""),
algo,
p.mpis().bits(),
ctime,
extime,
is_exp,
is_rev
));
for uid in tpk.userids() {
let u =
url::form_urlencoded::byte_serialize(uid.userid().userid())
.fold(String::default(), |acc, x| acc + x);
let ctime = uid
.binding_signature()
.and_then(|x| x.signature_creation_time())
.map(|x| format!("{}", x.to_timespec().sec))
.unwrap_or_default();
let extime = uid
.binding_signature()
.and_then(|x| x.signature_expiration_time())
.map(|x| format!("{}", x))
.unwrap_or_default();
let is_exp = uid
.binding_signature()
.and_then(|x| {
if x.signature_expired() { "e" } else { "" }.into()
})
.unwrap_or_default();
let is_rev = if uid.revoked(None)
!= RevocationStatus::NotAsFarAsWeKnow
{
"r"
} else {
""
};
out.push_str(&format!(
"uid:{}:{}:{}:{}{}\r\n",
u, ctime, extime, is_exp, is_rev
));
}
MyResponse::plain(out)
}
#[get("/vks/v1/by-fingerprint/<fpr>")]
fn by_fingerprint(state: rocket::State<State>,
db: rocket::State<Polymorphic>,
@ -585,31 +402,6 @@ fn files(file: PathBuf, state: rocket::State<State>) -> Option<NamedFile> {
NamedFile::open(state.public_dir.join("assets").join(file)).ok()
}
#[get("/pks/lookup")]
fn lookup(state: rocket::State<State>,
db: rocket::State<Polymorphic>,
key: queries::Hkp) -> MyResponse {
let query_string = key.to_string();
let (query, index, machine_readable) = match key {
queries::Hkp::Fingerprint { fpr, index, machine_readable } =>
(Query::ByFingerprint(fpr), index, machine_readable),
queries::Hkp::KeyID { keyid, index, machine_readable } =>
(Query::ByKeyID(keyid), index, machine_readable),
queries::Hkp::Email { email, index, machine_readable } => {
(Query::ByEmail(email), index, machine_readable)
}
queries::Hkp::Invalid { query: _ } => {
return MyResponse::not_found(None, None);
}
};
if index {
key_to_hkp_index(db, query)
} else {
key_to_response(state, db, query_string, query, machine_readable)
}
}
#[get("/")]
fn root() -> Template {
Template::render("index", templates::Index::new(None))
@ -640,14 +432,14 @@ fn rocket_factory(rocket: rocket::Rocket) -> Result<rocket::Rocket> {
by_email,
by_fingerprint,
by_keyid,
// HKP
lookup,
upload::pks_add,
upload::vks_publish,
upload::vks_publish_submit,
// verification & deletion
verify,
confirm,
// HKP
hkp::pks_lookup,
hkp::pks_add,
// about
about,
apidoc,
@ -699,7 +491,7 @@ fn rocket_factory(rocket: rocket::Rocket) -> Result<rocket::Rocket> {
}
#[cfg(test)]
mod tests {
pub mod tests {
use fs_extra;
use regex;
use std::fs;
@ -724,7 +516,7 @@ mod tests {
/// Note that you need to keep the returned TempDir alive for the
/// duration of your test. To debug the test, mem::forget it to
/// prevent cleanup.
fn configuration() -> Result<(TempDir, rocket::Config)> {
pub fn configuration() -> Result<(TempDir, rocket::Config)> {
use rocket::config::{Config, Environment};
let root = tempdir()?;
@ -754,7 +546,13 @@ mod tests {
Ok((root, config))
}
fn assert_consistency(rocket: &rocket::Rocket) {
pub fn client() -> Result<(TempDir, Client)> {
let (tmpdir, config) = configuration()?;
let rocket = rocket_factory(rocket::custom(config))?;
Ok((tmpdir, Client::new(rocket)?))
}
pub fn assert_consistency(rocket: &rocket::Rocket) {
let db = rocket.state::<Polymorphic>().unwrap();
if let Polymorphic::Filesystem(fs) = db {
fs.check_consistency().unwrap();
@ -904,13 +702,13 @@ mod tests {
}
/// Asserts that the given URI 404s.
fn check_null_response(client: &Client, uri: &str) {
pub fn check_null_response(client: &Client, uri: &str) {
let response = client.get(uri).dispatch();
assert_eq!(response.status(), Status::NotFound);
}
/// Asserts that lookups by the given address 404.
fn check_null_responses_by_email(client: &Client, addr: &str) {
pub fn check_null_responses_by_email(client: &Client, addr: &str) {
check_null_response(
&client, &format!("/vks/v1/by-email/{}", addr));
check_null_response(
@ -922,8 +720,8 @@ mod tests {
/// Asserts that the given URI returns a TPK matching the given
/// one, with the given number of userids.
fn check_mr_response(client: &Client, uri: &str, tpk: &TPK,
nr_uids: usize) {
pub fn check_mr_response(client: &Client, uri: &str, tpk: &TPK,
nr_uids: usize) {
let mut response = client.get(uri).dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(),
@ -941,8 +739,8 @@ mod tests {
/// Asserts that we can get the given TPK back using the various
/// by-fingerprint or by-keyid lookup mechanisms.
fn check_mr_responses_by_fingerprint(client: &Client, tpk: &TPK,
nr_uids: usize) {
pub fn check_mr_responses_by_fingerprint(client: &Client, tpk: &TPK,
nr_uids: usize) {
let fp = tpk.fingerprint().to_hex();
let keyid = tpk.fingerprint().to_keyid().to_hex();
@ -970,7 +768,7 @@ mod tests {
/// Asserts that the given URI returns human readable response
/// page.
fn check_hr_response(client: &Client, uri: &str, tpk: &TPK) {
pub fn check_hr_response(client: &Client, uri: &str, tpk: &TPK) {
let mut response = client.get(uri).dispatch();
assert_eq!(response.status(), Status::Ok);
assert_eq!(response.content_type(), Some(ContentType::HTML));
@ -981,7 +779,7 @@ mod tests {
/// Asserts that we can get the given TPK back using the various
/// by-fingerprint or by-keyid lookup mechanisms.
fn check_hr_responses_by_fingerprint(client: &Client, tpk: &TPK) {
pub fn check_hr_responses_by_fingerprint(client: &Client, tpk: &TPK) {
let fp = tpk.fingerprint().to_hex();
let keyid = tpk.fingerprint().to_keyid().to_hex();
@ -1018,110 +816,9 @@ mod tests {
assert_eq!(response.status(), Status::Ok);
}
#[test]
fn hkp() {
let (tmpdir, config) = configuration().unwrap();
let filemail_into = tmpdir.path().join("filemail");
// eprintln!("LEAKING: {:?}", tmpdir);
// ::std::mem::forget(tmpdir);
let rocket = rocket_factory(rocket::custom(config)).unwrap();
let client = Client::new(rocket).expect("valid rocket instance");
// Generate a key and upload it.
let (tpk, _) = TPKBuilder::autocrypt(
None, Some("foo@invalid.example.com".into()))
.generate().unwrap();
// Prepare to /pks/add
let mut armored = Vec::new();
{
use sequoia_openpgp::armor::{Writer, Kind};
let mut w = Writer::new(&mut armored, Kind::PublicKey, &[])
.unwrap();
tpk.serialize(&mut w).unwrap();
}
let mut post_data = String::from("keytext=");
for enc in url::form_urlencoded::byte_serialize(&armored) {
post_data.push_str(enc);
}
// Add!
let mut response = client.post("/pks/add")
.body(post_data.as_bytes())
.header(ContentType::Form)
.dispatch();
assert_eq!(response.status(), Status::Ok);
let body = response.body_string().unwrap();
eprintln!("response: {}", body);
// Check that we do not get a confirmation mail.
let confirm_mail = pop_mail(filemail_into.as_path()).unwrap();
assert!(confirm_mail.is_none());
// We should not be able to look it up by email address.
check_null_responses_by_email(&client, "foo@invalid.example.com");
// And check that we can get it back via the machine readable
// interface.
check_mr_responses_by_fingerprint(&client, &tpk, 0);
// And check that we can see the human-readable result page.
check_hr_responses_by_fingerprint(&client, &tpk);
assert_consistency(client.rocket());
}
#[test]
fn hkp_add_two() {
let (tmpdir, config) = configuration().unwrap();
let filemail_into = tmpdir.path().join("filemail");
let rocket = rocket_factory(rocket::custom(config)).unwrap();
let client = Client::new(rocket).expect("valid rocket instance");
// Generate two keys and upload them.
let tpk_0 = TPKBuilder::autocrypt(
None, Some("foo@invalid.example.com".into()))
.generate().unwrap().0;
let tpk_1 = TPKBuilder::autocrypt(
None, Some("bar@invalid.example.com".into()))
.generate().unwrap().0;
// Prepare to /pks/add
let mut armored = Vec::new();
{
use sequoia_openpgp::armor::{Writer, Kind};
let mut w = Writer::new(&mut armored, Kind::PublicKey, &[])
.unwrap();
tpk_0.serialize(&mut w).unwrap();
tpk_1.serialize(&mut w).unwrap();
}
let mut post_data = String::from("keytext=");
for enc in url::form_urlencoded::byte_serialize(&armored) {
post_data.push_str(enc);
}
// Add!
let response = client.post("/pks/add")
.body(post_data.as_bytes())
.header(ContentType::Form)
.dispatch();
assert_eq!(response.status(), Status::Ok);
let confirm_mail = pop_mail(filemail_into.as_path()).unwrap();
assert!(confirm_mail.is_none());
check_mr_responses_by_fingerprint(&client, &tpk_0, 0);
check_mr_responses_by_fingerprint(&client, &tpk_1, 0);
check_hr_responses_by_fingerprint(&client, &tpk_0);
check_hr_responses_by_fingerprint(&client, &tpk_1);
assert_consistency(client.rocket());
}
/// Returns and removes the first mail it finds from the given
/// directory.
fn pop_mail(dir: &Path) -> Result<Option<SimpleSendableEmail>> {
pub fn pop_mail(dir: &Path) -> Result<Option<SimpleSendableEmail>> {
for entry in fs::read_dir(dir)? {
let entry = entry?;
if entry.file_type()?.is_file() {

View File

@ -18,8 +18,6 @@ use web::State;
use std::io::Read;
use super::MyResponse;
const UPLOAD_LIMIT: u64 = 1024 * 1024; // 1 MiB.
mod template {
@ -87,24 +85,14 @@ pub fn vks_publish_submit(
db: rocket::State<Polymorphic>, cont_type: &ContentType, data: Data,
mail_service: rocket::State<mail::Service>, state: rocket::State<State>,
) -> Flash<Redirect> {
match do_upload_hkp(db, cont_type, data, Some(mail_service), state) {
match handle_upload(db, cont_type, data, Some(mail_service), state) {
Ok(ok) => ok,
Err(err) => Flash::error(Redirect::to("/vks/v1/publish?err"), err.to_string()),
}
}
#[post("/pks/add", data = "<data>")]
pub fn pks_add(db: rocket::State<Polymorphic>, cont_type: &ContentType, data: Data,
state: rocket::State<State>)
-> MyResponse {
match do_upload_hkp(db, cont_type, data, None, state) {
Ok(_) => MyResponse::plain("Ok".into()),
Err(err) => MyResponse::ise(err),
}
}
// signature requires the request to have a `Content-Type`
fn do_upload_hkp(
pub fn handle_upload(
db: rocket::State<Polymorphic>, cont_type: &ContentType, data: Data,
mail_service: Option<rocket::State<mail::Service>>, state: rocket::State<State>,
) -> Result<Flash<Redirect>> {