web: first iteration, update to rocket v0.5-rc1
This commit is contained in:
parent
3f156ec8c2
commit
a2bc5f014c
|
@ -1,10 +1,12 @@
|
|||
use lazy_static::lazy_static;
|
||||
use rocket_prometheus::prometheus;
|
||||
// use rocket_prometheus::prometheus;
|
||||
|
||||
use crate::anonymize_utils;
|
||||
|
||||
use crate::database::types::Email;
|
||||
|
||||
// TODO this module is a stub at the moment for rocket 0.5 migration. reintroduce later on?
|
||||
|
||||
lazy_static! {
|
||||
static ref KEY_UPLOAD: LabelCounter =
|
||||
LabelCounter::new("hagrid_key_upload", "Uploaded keys", &["result"]);
|
||||
|
@ -18,6 +20,7 @@ lazy_static! {
|
|||
LabelCounter::new("hagrid_key_address_unpublished", "Unpublished email addresses", &["domain"]);
|
||||
}
|
||||
|
||||
/*
|
||||
pub fn register_counters(registry: &prometheus::Registry) {
|
||||
KEY_UPLOAD.register(registry);
|
||||
|
||||
|
@ -26,6 +29,7 @@ pub fn register_counters(registry: &prometheus::Registry) {
|
|||
KEY_ADDRESS_PUBLISHED.register(registry);
|
||||
KEY_ADDRESS_UNPUBLISHED.register(registry);
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn inc_key_upload(upload_result: &str) {
|
||||
KEY_UPLOAD.inc(&[upload_result]);
|
||||
|
@ -47,21 +51,24 @@ pub fn inc_address_unpublished(email: &Email) {
|
|||
}
|
||||
|
||||
struct LabelCounter {
|
||||
prometheus_counter: prometheus::IntCounterVec,
|
||||
// prometheus_counter: prometheus::IntCounterVec,
|
||||
}
|
||||
|
||||
impl LabelCounter {
|
||||
fn new(name: &str, help: &str, labels: &[&str]) -> Self {
|
||||
let opts = prometheus::Opts::new(name, help);
|
||||
let prometheus_counter = prometheus::IntCounterVec::new(opts, labels).unwrap();
|
||||
Self { prometheus_counter }
|
||||
// let opts = prometheus::Opts::new(name, help);
|
||||
// let prometheus_counter = prometheus::IntCounterVec::new(opts, labels).unwrap();
|
||||
// Self { prometheus_counter }
|
||||
Self { }
|
||||
}
|
||||
|
||||
/*
|
||||
fn register(&self, registry: &prometheus::Registry) {
|
||||
registry.register(Box::new(self.prometheus_counter.clone())).unwrap();
|
||||
}
|
||||
*/
|
||||
|
||||
fn inc(&self, values: &[&str]) {
|
||||
self.prometheus_counter.with_label_values(values).inc();
|
||||
// self.prometheus_counter.with_label_values(values).inc();
|
||||
}
|
||||
}
|
||||
|
|
18
src/main.rs
18
src/main.rs
|
@ -1,4 +1,3 @@
|
|||
#![feature(proc_macro_hygiene, plugin, decl_macro)]
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -10,8 +9,6 @@ extern crate serde_derive;
|
|||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
#[macro_use]
|
||||
extern crate rocket_contrib;
|
||||
|
||||
#[cfg(test)]
|
||||
extern crate regex;
|
||||
|
@ -39,16 +36,7 @@ mod gettext_strings;
|
|||
mod web;
|
||||
mod template_helpers;
|
||||
|
||||
fn main() {
|
||||
if let Err(e) = web::serve() {
|
||||
eprint!("{}", e);
|
||||
let mut cause = e.source();
|
||||
while let Some(c) = cause {
|
||||
eprint!(":\n {}", c);
|
||||
cause = c.source();
|
||||
}
|
||||
eprintln!();
|
||||
|
||||
::std::process::exit(2);
|
||||
}
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
web::serve().expect("Rocket config must succeed")
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::database::{Database, KeyDatabase, Query};
|
|||
|
||||
#[get("/debug?<q>")]
|
||||
pub fn debug_info(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
q: String,
|
||||
) -> MyResponse {
|
||||
|
|
|
@ -4,11 +4,12 @@ use std::time::SystemTime;
|
|||
use std::collections::HashMap;
|
||||
|
||||
use rocket::Data;
|
||||
use rocket::Outcome;
|
||||
use rocket::form::{Form, ValueField};
|
||||
use rocket::outcome::Outcome;
|
||||
use rocket::http::{ContentType, Status};
|
||||
use rocket::request::{self, Request, FromRequest};
|
||||
use rocket::http::uri::Uri;
|
||||
use rocket_i18n::I18n;
|
||||
use url::percent_encoding::{DEFAULT_ENCODE_SET, utf8_percent_encode};
|
||||
|
||||
use crate::database::{Database, Query, KeyDatabase};
|
||||
use crate::database::types::{Email, Fingerprint, KeyID};
|
||||
|
@ -45,21 +46,17 @@ impl fmt::Display for Hkp {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'r> FromRequest<'a, 'r> for Hkp {
|
||||
#[async_trait]
|
||||
impl<'r> FromRequest<'r> for Hkp {
|
||||
type Error = ();
|
||||
|
||||
fn from_request(request: &'a Request<'r>) -> request::Outcome<Hkp, ()> {
|
||||
async fn from_request(request: &'r Request<'_>) -> request::Outcome<Hkp, ()> {
|
||||
use std::str::FromStr;
|
||||
use rocket::request::FormItems;
|
||||
|
||||
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)
|
||||
let query = request.uri().query().map(|q| q.as_str()).unwrap_or_default();
|
||||
let fields = Form::values(query)
|
||||
.map(|ValueField { name, value }| {
|
||||
(name.to_string(), value.to_string())
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
|
@ -78,30 +75,30 @@ impl<'a, 'r> FromRequest<'a, 'r> for Hkp {
|
|||
(search.starts_with("0x") && search.len() < 16 || search.len() == 8);
|
||||
if looks_like_short_key_id {
|
||||
Outcome::Success(Hkp::ShortKeyID {
|
||||
query: search,
|
||||
index: index,
|
||||
query: search.to_string(),
|
||||
index,
|
||||
})
|
||||
} else if let Ok(fpr) = maybe_fpr {
|
||||
Outcome::Success(Hkp::Fingerprint {
|
||||
fpr: fpr,
|
||||
index: index,
|
||||
fpr,
|
||||
index,
|
||||
})
|
||||
} else if let Ok(keyid) = maybe_keyid {
|
||||
Outcome::Success(Hkp::KeyID {
|
||||
keyid: keyid,
|
||||
index: index,
|
||||
keyid,
|
||||
index,
|
||||
})
|
||||
} else {
|
||||
match Email::from_str(&search) {
|
||||
Ok(email) => {
|
||||
Outcome::Success(Hkp::Email {
|
||||
email: email,
|
||||
index: index,
|
||||
email,
|
||||
index,
|
||||
})
|
||||
}
|
||||
Err(_) => {
|
||||
Outcome::Success(Hkp::Invalid{
|
||||
query: search
|
||||
query: search.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -119,9 +116,9 @@ impl<'a, 'r> FromRequest<'a, 'r> for Hkp {
|
|||
|
||||
#[post("/pks/add", format = "multipart/form-data", data = "<data>")]
|
||||
pub fn pks_add_form_data(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
cont_type: &ContentType,
|
||||
data: Data,
|
||||
|
@ -133,16 +130,16 @@ pub fn pks_add_form_data(
|
|||
}
|
||||
|
||||
#[post("/pks/add", format = "application/x-www-form-urlencoded", data = "<data>")]
|
||||
pub fn pks_add_form(
|
||||
pub async fn pks_add_form(
|
||||
request_origin: RequestOrigin,
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
i18n: I18n,
|
||||
data: Data,
|
||||
data: Data<'_>,
|
||||
) -> MyResponse {
|
||||
match vks_web::process_post_form(&db, &tokens_stateless, &rate_limiter, &i18n, data) {
|
||||
match vks_web::process_post_form(&db, &tokens_stateless, &rate_limiter, &i18n, data).await {
|
||||
Ok(UploadResponse::Ok { is_new_key, key_fpr, primary_uid, token, status, .. }) => {
|
||||
let msg = pks_add_ok(&request_origin, &mail_service, &rate_limiter, token, status, is_new_key, key_fpr, primary_uid);
|
||||
MyResponse::plain(msg)
|
||||
|
@ -198,7 +195,7 @@ fn send_welcome_mail(
|
|||
|
||||
#[get("/pks/lookup")]
|
||||
pub fn pks_lookup(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
key: Hkp
|
||||
) -> MyResponse {
|
||||
|
@ -227,7 +224,7 @@ pub fn pks_lookup(
|
|||
|
||||
#[get("/pks/internal/index/<query_string>")]
|
||||
pub fn pks_internal_index(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
query_string: String,
|
||||
) -> MyResponse {
|
||||
|
@ -238,7 +235,7 @@ pub fn pks_internal_index(
|
|||
}
|
||||
|
||||
fn key_to_hkp_index(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
query: Query,
|
||||
) -> MyResponse {
|
||||
|
@ -278,7 +275,7 @@ fn key_to_hkp_index(
|
|||
|
||||
for uid in tpk.userids() {
|
||||
let uidstr = uid.userid().to_string();
|
||||
let u = Uri::percent_encode(&uidstr);
|
||||
let u = utf8_percent_encode(&uidstr, DEFAULT_ENCODE_SET).to_string();
|
||||
let ctime = uid
|
||||
.binding_signature(policy, None)
|
||||
.ok()
|
||||
|
@ -344,7 +341,7 @@ mod tests {
|
|||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
eprintln!("response: {}", body);
|
||||
|
||||
// Check that we get a welcome mail
|
||||
|
@ -357,7 +354,7 @@ mod tests {
|
|||
.header(ContentType::Form)
|
||||
.dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
eprintln!("response: {}", body);
|
||||
|
||||
// No second email right after the welcome one!
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use rocket::{Request, Data};
|
||||
use rocket::fairing::{Fairing, Info, Kind};
|
||||
use rocket::http::Method;
|
||||
use rocket_contrib::templates::Template;
|
||||
use rocket_dyn_templates::Template;
|
||||
use rocket_i18n::I18n;
|
||||
use serde_json::json;
|
||||
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
@ -23,6 +24,7 @@ mod templates {
|
|||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Fairing for MaintenanceMode {
|
||||
fn info(&self) -> Info {
|
||||
Info {
|
||||
|
@ -31,21 +33,21 @@ impl Fairing for MaintenanceMode {
|
|||
}
|
||||
}
|
||||
|
||||
fn on_request(&self, request: &mut Request, _: &Data) {
|
||||
async fn on_request(&self, request: &mut Request<'_>, _: &mut Data<'_>) {
|
||||
let message = match self.get_maintenance_message() {
|
||||
Some(message) => message,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let path = request.uri().path();
|
||||
let path = request.uri().path().as_str();
|
||||
if self.is_request_json(path) {
|
||||
request.set_uri(uri!(maintenance_error_json: message));
|
||||
request.set_uri(uri!(maintenance_error_json(message)));
|
||||
request.set_method(Method::Get);
|
||||
} else if self.is_request_plain(path, request.method()) {
|
||||
request.set_uri(uri!(maintenance_error_plain: message));
|
||||
request.set_uri(uri!(maintenance_error_plain(message)));
|
||||
request.set_method(Method::Get);
|
||||
} else if self.is_request_web(path) {
|
||||
request.set_uri(uri!(maintenance_error_web: message));
|
||||
request.set_uri(uri!(maintenance_error_web(message)));
|
||||
request.set_method(Method::Get);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use rocket;
|
||||
use rocket::State;
|
||||
use rocket::request::Form;
|
||||
use rocket::form::Form;
|
||||
use rocket_i18n::I18n;
|
||||
|
||||
use crate::Result;
|
||||
|
@ -65,10 +64,10 @@ pub fn vks_manage() -> Result<MyResponse> {
|
|||
#[get("/manage/<token>")]
|
||||
pub fn vks_manage_key(
|
||||
request_origin: RequestOrigin,
|
||||
db: State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
token: String,
|
||||
token_service: rocket::State<tokens::Service>,
|
||||
token_service: &rocket::State<tokens::Service>,
|
||||
) -> MyResponse {
|
||||
use crate::database::types::Fingerprint;
|
||||
use std::convert::TryFrom;
|
||||
|
@ -88,7 +87,7 @@ pub fn vks_manage_key(
|
|||
published: true,
|
||||
}
|
||||
).collect();
|
||||
let key_link = uri!(vks_web::search: fp.to_string()).to_string();
|
||||
let key_link = uri!(vks_web::search(q = fp.to_string())).to_string();
|
||||
let context = templates::ManageKey {
|
||||
key_fpr: fp.to_string(),
|
||||
key_link,
|
||||
|
@ -100,7 +99,10 @@ pub fn vks_manage_key(
|
|||
},
|
||||
Ok(None) => MyResponse::not_found(
|
||||
Some("manage/manage"),
|
||||
Some(i18n!(i18n.catalog, "This link is invalid or expired"))),
|
||||
Some(i18n!(i18n.catalog, "This link is invalid or expired")),
|
||||
i18n,
|
||||
request_origin,
|
||||
),
|
||||
Err(e) => MyResponse::ise(e),
|
||||
}
|
||||
} else {
|
||||
|
@ -112,13 +114,13 @@ pub fn vks_manage_key(
|
|||
|
||||
#[post("/manage", data="<request>")]
|
||||
pub fn vks_manage_post(
|
||||
db: State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
request_origin: RequestOrigin,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
request: Form<forms::ManageRequest>,
|
||||
token_service: rocket::State<tokens::Service>,
|
||||
token_service: &rocket::State<tokens::Service>,
|
||||
) -> MyResponse {
|
||||
use std::convert::TryInto;
|
||||
|
||||
|
@ -155,7 +157,7 @@ pub fn vks_manage_post(
|
|||
let fpr: Fingerprint = tpk.fingerprint().try_into().unwrap();
|
||||
let fpr_text = fpr.to_string();
|
||||
let token = token_service.create(&StatelessVerifyToken { fpr });
|
||||
let link_path = uri!(vks_manage_key: token).to_string();
|
||||
let link_path = uri!(vks_manage_key(token)).to_string();
|
||||
|
||||
let base_uri = request_origin.get_base_uri();
|
||||
if let Err(e) = mail_service.send_manage_token(&i18n, base_uri, fpr_text, &email, &link_path) {
|
||||
|
@ -171,9 +173,9 @@ pub fn vks_manage_post(
|
|||
#[post("/manage/unpublish", data="<request>")]
|
||||
pub fn vks_manage_unpublish(
|
||||
request_origin: RequestOrigin,
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
token_service: rocket::State<tokens::Service>,
|
||||
token_service: &rocket::State<tokens::Service>,
|
||||
request: Form<forms::ManageDelete>,
|
||||
) -> MyResponse {
|
||||
match vks_manage_unpublish_or_fail(request_origin, db, token_service, i18n, request) {
|
||||
|
@ -184,8 +186,8 @@ pub fn vks_manage_unpublish(
|
|||
|
||||
pub fn vks_manage_unpublish_or_fail(
|
||||
request_origin: RequestOrigin,
|
||||
db: rocket::State<KeyDatabase>,
|
||||
token_service: rocket::State<tokens::Service>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
token_service: &rocket::State<tokens::Service>,
|
||||
i18n: I18n,
|
||||
request: Form<forms::ManageDelete>,
|
||||
) -> Result<MyResponse> {
|
||||
|
|
265
src/web/mod.rs
265
src/web/mod.rs
|
@ -1,15 +1,14 @@
|
|||
use rocket;
|
||||
use rocket::http::Status;
|
||||
use rocket::figment::Figment;
|
||||
use rocket::fs::NamedFile;
|
||||
use rocket::http::{Header, Status};
|
||||
use rocket::request;
|
||||
use rocket::outcome::Outcome;
|
||||
use rocket::response::{NamedFile, Responder, Response};
|
||||
use rocket::config::Config;
|
||||
use rocket_contrib::templates::{Template, Engines};
|
||||
use rocket_contrib::json::JsonValue;
|
||||
use rocket::response::{Responder, Response};
|
||||
use rocket::response::status::Custom;
|
||||
use rocket_dyn_templates::{Engines, Template};
|
||||
use rocket_i18n::I18n;
|
||||
|
||||
use rocket_prometheus::PrometheusMetrics;
|
||||
use hyperx::header::{ContentDisposition, DispositionType, DispositionParam, Charset};
|
||||
|
||||
use gettext_macros::{compile_i18n, include_i18n};
|
||||
|
||||
|
@ -19,7 +18,6 @@ use std::path::PathBuf;
|
|||
|
||||
use crate::mail;
|
||||
use crate::tokens;
|
||||
use crate::counters;
|
||||
use crate::i18n_helpers::describe_query_error;
|
||||
use crate::template_helpers::TemplateOverrides;
|
||||
use crate::i18n::I18NHelper;
|
||||
|
@ -41,17 +39,14 @@ mod debug_web;
|
|||
|
||||
use crate::web::maintenance::MaintenanceMode;
|
||||
|
||||
use rocket::http::hyper::header::ContentDisposition;
|
||||
pub struct HagridTemplate(&'static str, serde_json::Value, I18n, RequestOrigin);
|
||||
|
||||
pub struct HagridTemplate(&'static str, serde_json::Value);
|
||||
impl<'r> Responder<'r, 'static> for HagridTemplate {
|
||||
fn respond_to(self, req: &'r rocket::Request) -> std::result::Result<Response<'static>, Status> {
|
||||
let HagridTemplate(tmpl, ctx, i18n, origin) = self;
|
||||
|
||||
impl Responder<'static> for HagridTemplate {
|
||||
fn respond_to(self, req: &rocket::Request) -> std::result::Result<Response<'static>, Status> {
|
||||
let HagridTemplate(tmpl, ctx) = self;
|
||||
let i18n: I18n = req.guard().expect("Error parsing language");
|
||||
let template_overrides: rocket::State<TemplateOverrides> = req.guard().expect("TemplateOverrides must be in managed state");
|
||||
let template_overrides: &TemplateOverrides = req.rocket().state().expect("TemplateOverrides must be in managed state");
|
||||
let template_override = template_overrides.get_template_override(i18n.lang, tmpl);
|
||||
let origin: RequestOrigin = req.guard().expect("Error determining request origin");
|
||||
let layout_context = templates::HagridLayout::new(ctx, i18n, origin);
|
||||
|
||||
if let Some(template_override) = template_override {
|
||||
|
@ -71,7 +66,7 @@ pub enum MyResponse {
|
|||
#[response(status = 200, content_type = "xml")]
|
||||
Xml(HagridTemplate),
|
||||
#[response(status = 200, content_type = "application/pgp-keys")]
|
||||
Key(String, ContentDisposition),
|
||||
Key(String, Header<'static>),
|
||||
#[response(status = 500, content_type = "html")]
|
||||
ServerError(Template),
|
||||
#[response(status = 404, content_type = "html")]
|
||||
|
@ -85,25 +80,25 @@ pub enum MyResponse {
|
|||
#[response(status = 503, content_type = "html")]
|
||||
Maintenance(Template),
|
||||
#[response(status = 503, content_type = "json")]
|
||||
MaintenanceJson(JsonValue),
|
||||
MaintenanceJson(serde_json::Value),
|
||||
#[response(status = 503, content_type = "plain")]
|
||||
MaintenancePlain(String),
|
||||
}
|
||||
|
||||
impl MyResponse {
|
||||
pub fn ok(tmpl: &'static str, ctx: impl Serialize) -> Self {
|
||||
pub fn ok(tmpl: &'static str, ctx: impl Serialize, i18n: I18n, origin: RequestOrigin) -> Self {
|
||||
let context_json = serde_json::to_value(ctx).unwrap();
|
||||
MyResponse::Success(HagridTemplate(tmpl, context_json))
|
||||
MyResponse::Success(HagridTemplate(tmpl, context_json, i18n, origin))
|
||||
}
|
||||
|
||||
pub fn ok_bare(tmpl: &'static str) -> Self {
|
||||
pub fn ok_bare(tmpl: &'static str, i18n: I18n, origin: RequestOrigin) -> Self {
|
||||
let context_json = serde_json::to_value(templates::Bare { dummy: () }).unwrap();
|
||||
MyResponse::Success(HagridTemplate(tmpl, context_json))
|
||||
MyResponse::Success(HagridTemplate(tmpl, context_json, i18n, origin))
|
||||
}
|
||||
|
||||
pub fn xml(tmpl: &'static str) -> Self {
|
||||
pub fn xml(tmpl: &'static str, i18n: I18n, origin: RequestOrigin) -> Self {
|
||||
let context_json = serde_json::to_value(templates::Bare { dummy: () }).unwrap();
|
||||
MyResponse::Xml(HagridTemplate(tmpl, context_json))
|
||||
MyResponse::Xml(HagridTemplate(tmpl, context_json, i18n, origin))
|
||||
}
|
||||
|
||||
pub fn plain(s: String) -> Self {
|
||||
|
@ -111,17 +106,15 @@ impl MyResponse {
|
|||
}
|
||||
|
||||
pub fn key(armored_key: String, fp: &Fingerprint) -> Self {
|
||||
use rocket::http::hyper::header::{DispositionType, DispositionParam, Charset};
|
||||
MyResponse::Key(
|
||||
armored_key,
|
||||
ContentDisposition {
|
||||
let content_disposition = Header::new(CONTENT_DISPOSITION.as_str(), ContentDisposition {
|
||||
disposition: DispositionType::Attachment,
|
||||
parameters: vec![
|
||||
DispositionParam::Filename(
|
||||
Charset::Us_Ascii, None,
|
||||
(fp.to_string() + ".asc").into_bytes()),
|
||||
],
|
||||
})
|
||||
});
|
||||
MyResponse::Key(armored_key, content_disposition)
|
||||
}
|
||||
|
||||
pub fn ise(e: anyhow::Error) -> Self {
|
||||
|
@ -135,10 +128,10 @@ impl MyResponse {
|
|||
MyResponse::ServerError(Template::render("500", ctx))
|
||||
}
|
||||
|
||||
pub fn bad_request(template: &'static str, e: anyhow::Error) -> Self {
|
||||
pub fn bad_request(template: &'static str, e: anyhow::Error, i18n: I18n, origin: RequestOrigin) -> Self {
|
||||
let ctx = templates::Error { error: format!("{}", e) };
|
||||
let context_json = serde_json::to_value(ctx).unwrap();
|
||||
MyResponse::BadRequest(HagridTemplate(template, context_json))
|
||||
MyResponse::BadRequest(HagridTemplate(template, context_json, i18n, origin))
|
||||
}
|
||||
|
||||
pub fn bad_request_plain(message: impl Into<String>) -> Self {
|
||||
|
@ -152,11 +145,13 @@ impl MyResponse {
|
|||
pub fn not_found(
|
||||
tmpl: Option<&'static str>,
|
||||
message: impl Into<Option<String>>,
|
||||
i18n: I18n,
|
||||
origin: RequestOrigin,
|
||||
) -> Self {
|
||||
let ctx = templates::Error { error: message.into()
|
||||
.unwrap_or_else(|| "Key not found".to_owned()) };
|
||||
let context_json = serde_json::to_value(ctx).unwrap();
|
||||
MyResponse::NotFound(HagridTemplate(tmpl.unwrap_or("index"), context_json))
|
||||
MyResponse::NotFound(HagridTemplate(tmpl.unwrap_or("index"), context_json, i18n, origin))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,7 +197,7 @@ mod templates {
|
|||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
commit: env!("VERGEN_SHA_SHORT").to_string(),
|
||||
base_uri: origin.get_base_uri().to_string(),
|
||||
page: page,
|
||||
page,
|
||||
lang: i18n.lang.to_string(),
|
||||
htmldir: if is_rtl { "rtl".to_owned() } else { "ltr".to_owned() },
|
||||
htmlclass: if is_rtl { "rtl".to_owned() } else { "".to_owned() },
|
||||
|
@ -226,11 +221,12 @@ pub enum RequestOrigin {
|
|||
OnionService(String),
|
||||
}
|
||||
|
||||
impl<'a, 'r> request::FromRequest<'a, 'r> for RequestOrigin {
|
||||
#[async_trait]
|
||||
impl<'r> request::FromRequest<'r> for RequestOrigin {
|
||||
type Error = ();
|
||||
|
||||
fn from_request(request: &'a request::Request<'r>) -> request::Outcome<Self, Self::Error> {
|
||||
let hagrid_state = request.guard::<rocket::State<HagridState>>().unwrap();
|
||||
async fn from_request(request: &'r request::Request<'_>) -> request::Outcome<Self, Self::Error> {
|
||||
let hagrid_state = request.rocket().state::<HagridState>().unwrap();
|
||||
let result = match request.headers().get("x-is-onion").next() {
|
||||
Some(_) => RequestOrigin::OnionService(hagrid_state.base_uri_onion.clone()),
|
||||
None => RequestOrigin::Direct(hagrid_state.base_uri.clone()),
|
||||
|
@ -249,7 +245,7 @@ impl RequestOrigin {
|
|||
}
|
||||
|
||||
pub fn key_to_response_plain(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
query: Query,
|
||||
) -> MyResponse {
|
||||
|
@ -270,8 +266,8 @@ pub fn key_to_response_plain(
|
|||
}
|
||||
|
||||
#[get("/assets/<file..>")]
|
||||
fn files(file: PathBuf, state: rocket::State<HagridState>) -> Option<NamedFile> {
|
||||
NamedFile::open(state.assets_dir.join(file)).ok()
|
||||
async fn files(file: PathBuf, state: &rocket::State<HagridState>) -> Option<NamedFile> {
|
||||
NamedFile::open(state.assets_dir.join(file)).await.ok()
|
||||
}
|
||||
|
||||
#[get("/")]
|
||||
|
@ -338,13 +334,13 @@ fn errors(
|
|||
Ok(Custom(status_code, response_body))
|
||||
}
|
||||
|
||||
pub fn serve() -> Result<()> {
|
||||
Err(rocket_factory(rocket::ignite())?.launch().into())
|
||||
pub fn serve() -> Result<rocket::Rocket<rocket::Build>> {
|
||||
Ok(rocket_factory(rocket::build())?)
|
||||
}
|
||||
|
||||
compile_i18n!();
|
||||
|
||||
fn rocket_factory(mut rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
||||
fn rocket_factory(mut rocket: rocket::Rocket<rocket::Build>) -> Result<rocket::Rocket<rocket::Build>> {
|
||||
let routes = routes![
|
||||
// infra
|
||||
root,
|
||||
|
@ -384,7 +380,7 @@ fn rocket_factory(mut rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
|||
hkp::pks_add_form,
|
||||
hkp::pks_add_form_data,
|
||||
hkp::pks_internal_index,
|
||||
// EManage
|
||||
// Manage
|
||||
manage::vks_manage,
|
||||
manage::vks_manage_key,
|
||||
manage::vks_manage_post,
|
||||
|
@ -395,17 +391,18 @@ fn rocket_factory(mut rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
|||
maintenance::maintenance_error_plain,
|
||||
];
|
||||
|
||||
let db_service = configure_db_service(rocket.config())?;
|
||||
let hagrid_state = configure_hagrid_state(rocket.config())?;
|
||||
let stateful_token_service = configure_stateful_token_service(rocket.config())?;
|
||||
let stateless_token_service = configure_stateless_token_service(rocket.config())?;
|
||||
let mail_service = configure_mail_service(rocket.config())?;
|
||||
let rate_limiter = configure_rate_limiter(rocket.config())?;
|
||||
let maintenance_mode = configure_maintenance_mode(rocket.config())?;
|
||||
let localized_template_list = configure_localized_template_list(rocket.config())?;
|
||||
let figment = rocket.figment();
|
||||
let db_service = configure_db_service(figment)?;
|
||||
let hagrid_state = configure_hagrid_state(figment)?;
|
||||
let stateful_token_service = configure_stateful_token_service(figment)?;
|
||||
let stateless_token_service = configure_stateless_token_service(figment)?;
|
||||
let mail_service = configure_mail_service(figment)?;
|
||||
let rate_limiter = configure_rate_limiter(figment)?;
|
||||
let maintenance_mode = configure_maintenance_mode(figment)?;
|
||||
let localized_template_list = configure_localized_template_list(figment)?;
|
||||
println!("{:?}", localized_template_list);
|
||||
|
||||
let prometheus = configure_prometheus(rocket.config());
|
||||
// let prometheus = configure_prometheus(rocket.config());
|
||||
|
||||
rocket = rocket
|
||||
.attach(Template::custom(|engines: &mut Engines| {
|
||||
|
@ -424,39 +421,43 @@ fn rocket_factory(mut rocket: rocket::Rocket) -> Result<rocket::Rocket> {
|
|||
.manage(localized_template_list)
|
||||
.mount("/", routes);
|
||||
|
||||
/*
|
||||
if let Some(prometheus) = prometheus {
|
||||
rocket = rocket
|
||||
.attach(prometheus.clone())
|
||||
.mount("/metrics", prometheus);
|
||||
}
|
||||
*/
|
||||
|
||||
Ok(rocket)
|
||||
}
|
||||
|
||||
fn configure_prometheus(config: &Config) -> Option<PrometheusMetrics> {
|
||||
if !config.get_bool("enable_prometheus").unwrap_or(false) {
|
||||
/*
|
||||
fn configure_prometheus(config: &Figment) -> Option<PrometheusMetrics> {
|
||||
if !config.extract_inner("enable_prometheus").unwrap_or(false) {
|
||||
return None;
|
||||
}
|
||||
let prometheus = PrometheusMetrics::new();
|
||||
counters::register_counters(&prometheus.registry());
|
||||
return Some(prometheus);
|
||||
}
|
||||
*/
|
||||
|
||||
fn configure_db_service(config: &Config) -> Result<KeyDatabase> {
|
||||
let keys_internal_dir: PathBuf = config.get_str("keys_internal_dir")?.into();
|
||||
let keys_external_dir: PathBuf = config.get_str("keys_external_dir")?.into();
|
||||
let tmp_dir: PathBuf = config.get_str("tmp_dir")?.into();
|
||||
fn configure_db_service(config: &Figment) -> Result<KeyDatabase> {
|
||||
let keys_internal_dir: PathBuf = config.extract_inner("keys_internal_dir")?;
|
||||
let keys_external_dir: PathBuf = config.extract_inner("keys_external_dir")?;
|
||||
let tmp_dir: PathBuf = config.extract_inner("tmp_dir")?;
|
||||
|
||||
let fs_db = KeyDatabase::new(keys_internal_dir, keys_external_dir, tmp_dir)?;
|
||||
Ok(fs_db)
|
||||
}
|
||||
|
||||
fn configure_hagrid_state(config: &Config) -> Result<HagridState> {
|
||||
let assets_dir: PathBuf = config.get_str("assets_dir")?.into();
|
||||
fn configure_hagrid_state(config: &Figment) -> Result<HagridState> {
|
||||
let assets_dir: PathBuf = config.extract_inner("assets_dir")?;
|
||||
|
||||
// State
|
||||
let base_uri = config.get_str("base-URI")?.to_string();
|
||||
let base_uri_onion = config.get_str("base-URI-Onion")
|
||||
let base_uri: String = config.extract_inner("base-URI")?;
|
||||
let base_uri_onion = config.extract_inner::<String>("base-URI-Onion")
|
||||
.map(|c| c.to_string())
|
||||
.unwrap_or(base_uri.clone());
|
||||
Ok(HagridState {
|
||||
|
@ -466,29 +467,25 @@ fn configure_hagrid_state(config: &Config) -> Result<HagridState> {
|
|||
})
|
||||
}
|
||||
|
||||
fn configure_stateful_token_service(config: &Config) -> Result<database::StatefulTokens> {
|
||||
let token_dir: PathBuf = config.get_str("token_dir")?.into();
|
||||
fn configure_stateful_token_service(config: &Figment) -> Result<database::StatefulTokens> {
|
||||
let token_dir: PathBuf = config.extract_inner("token_dir")?;
|
||||
database::StatefulTokens::new(token_dir)
|
||||
}
|
||||
|
||||
fn configure_stateless_token_service(config: &Config) -> Result<tokens::Service> {
|
||||
use std::convert::TryFrom;
|
||||
|
||||
let secret = config.get_str("token_secret")?.to_string();
|
||||
let validity = config.get_int("token_validity")?;
|
||||
let validity = u64::try_from(validity)?;
|
||||
fn configure_stateless_token_service(config: &Figment) -> Result<tokens::Service> {
|
||||
let secret: String = config.extract_inner("token_secret")?;
|
||||
let validity: u64 = config.extract_inner("token_validity")?;
|
||||
Ok(tokens::Service::init(&secret, validity))
|
||||
}
|
||||
|
||||
fn configure_mail_service(config: &Config) -> Result<mail::Service> {
|
||||
fn configure_mail_service(config: &Figment) -> Result<mail::Service> {
|
||||
// Mail service
|
||||
let email_template_dir: PathBuf = config.get_str("email_template_dir")?.into();
|
||||
let email_template_dir: PathBuf = config.extract_inner("email_template_dir")?;
|
||||
|
||||
let base_uri = config.get_str("base-URI")?;
|
||||
let from = config.get_str("from")?;
|
||||
let base_uri = config.extract_inner("base-URI")?;
|
||||
let from = config.extract_inner("from")?;
|
||||
|
||||
let filemail_into = config.get_str("filemail_into")
|
||||
.ok().map(|p| PathBuf::from(p));
|
||||
let filemail_into: Option<PathBuf> = config.extract_inner::<PathBuf>("filemail_into").ok();
|
||||
|
||||
if let Some(path) = filemail_into {
|
||||
mail::Service::filemail(from, base_uri, &email_template_dir, &path)
|
||||
|
@ -497,33 +494,33 @@ fn configure_mail_service(config: &Config) -> Result<mail::Service> {
|
|||
}
|
||||
}
|
||||
|
||||
fn configure_rate_limiter(config: &Config) -> Result<RateLimiter> {
|
||||
let timeout_secs = config.get_int("mail_rate_limit").unwrap_or(60);
|
||||
fn configure_rate_limiter(config: &Figment) -> Result<RateLimiter> {
|
||||
let timeout_secs: i32 = config.extract_inner("mail_rate_limit").unwrap_or(60);
|
||||
let timeout_secs = timeout_secs.try_into()?;
|
||||
Ok(RateLimiter::new(timeout_secs))
|
||||
}
|
||||
|
||||
fn configure_localized_template_list(config: &Config) -> Result<TemplateOverrides> {
|
||||
let template_dir: PathBuf = config.get_str("template_dir")?.into();
|
||||
fn configure_localized_template_list(config: &Figment) -> Result<TemplateOverrides> {
|
||||
let template_dir: PathBuf = config.extract_inner("template_dir")?;
|
||||
TemplateOverrides::load(&template_dir, "localized")
|
||||
}
|
||||
|
||||
fn configure_maintenance_mode(config: &Config) -> Result<MaintenanceMode> {
|
||||
let maintenance_file: PathBuf = config.get_str("maintenance_file")
|
||||
.unwrap_or("maintenance").into();
|
||||
fn configure_maintenance_mode(config: &Figment) -> Result<MaintenanceMode> {
|
||||
let maintenance_file: PathBuf = config.extract_inner("maintenance_file")
|
||||
.unwrap_or_else(|_| PathBuf::from("maintenance"));
|
||||
Ok(MaintenanceMode::new(maintenance_file))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use regex;
|
||||
use rocket::local::blocking::{Client, LocalResponse};
|
||||
use std::fs;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
use super::rocket;
|
||||
use rocket::local::{Client, LocalResponse};
|
||||
use rocket::http::Status;
|
||||
use rocket::http::ContentType;
|
||||
use rocket::http::Header;
|
||||
|
@ -559,49 +556,47 @@ pub 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.
|
||||
pub fn configuration() -> Result<(TempDir, rocket::Config)> {
|
||||
use rocket::config::Environment;
|
||||
|
||||
pub fn configuration() -> Result<(TempDir, rocket::figment::Figment)> {
|
||||
let root = tempdir()?;
|
||||
let filemail = root.path().join("filemail");
|
||||
::std::fs::create_dir_all(&filemail)?;
|
||||
|
||||
let base_dir: PathBuf = root.path().into();
|
||||
|
||||
let config = Config::build(Environment::Staging)
|
||||
.root(root.path().to_path_buf())
|
||||
.extra("template_dir",
|
||||
let config = Figment::new()
|
||||
.select("staging")
|
||||
.merge(("root", root.path()))
|
||||
.merge(("template_dir",
|
||||
::std::env::current_dir().unwrap().join("dist/templates")
|
||||
.to_str().unwrap())
|
||||
.extra("email_template_dir",
|
||||
.to_str().unwrap()))
|
||||
.merge(("email_template_dir",
|
||||
::std::env::current_dir().unwrap().join("dist/email-templates")
|
||||
.to_str().unwrap())
|
||||
.extra("assets_dir",
|
||||
.to_str().unwrap()))
|
||||
.merge(("assets_dir",
|
||||
::std::env::current_dir().unwrap().join("dist/assets")
|
||||
.to_str().unwrap())
|
||||
.extra("keys_internal_dir", base_dir.join("keys_internal").to_str().unwrap())
|
||||
.extra("keys_external_dir", base_dir.join("keys_external").to_str().unwrap())
|
||||
.extra("tmp_dir", base_dir.join("tmp").to_str().unwrap())
|
||||
.extra("token_dir", base_dir.join("tokens").to_str().unwrap())
|
||||
.extra("maintenance_file", base_dir.join("maintenance").to_str().unwrap())
|
||||
.extra("base-URI", BASE_URI)
|
||||
.extra("base-URI-Onion", BASE_URI_ONION)
|
||||
.extra("from", "from@example.com")
|
||||
.extra("token_secret", "hagrid")
|
||||
.extra("token_validity", 3600)
|
||||
.extra("filemail_into", filemail.into_os_string().into_string()
|
||||
.expect("path is valid UTF8"))
|
||||
.finalize()?;
|
||||
.to_str().unwrap()))
|
||||
.merge(("keys_internal_dir", base_dir.join("keys_internal").to_str().unwrap()))
|
||||
.merge(("keys_external_dir", base_dir.join("keys_external").to_str().unwrap()))
|
||||
.merge(("tmp_dir", base_dir.join("tmp").to_str().unwrap()))
|
||||
.merge(("token_dir", base_dir.join("tokens").to_str().unwrap()))
|
||||
.merge(("maintenance_file", base_dir.join("maintenance").to_str().unwrap()))
|
||||
.merge(("base-URI", BASE_URI))
|
||||
.merge(("base-URI-Onion", BASE_URI_ONION))
|
||||
.merge(("from", "from@example.com"))
|
||||
.merge(("token_secret", "hagrid"))
|
||||
.merge(("token_validity", 3600u64))
|
||||
.merge(("filemail_into", filemail.into_os_string().into_string()
|
||||
.expect("path is valid UTF8")));
|
||||
Ok((root, config))
|
||||
}
|
||||
|
||||
pub fn client() -> Result<(TempDir, Client)> {
|
||||
let (tmpdir, config) = configuration()?;
|
||||
let rocket = rocket_factory(rocket::custom(config))?;
|
||||
Ok((tmpdir, Client::new(rocket)?))
|
||||
Ok((tmpdir, Client::untracked(rocket)?))
|
||||
}
|
||||
|
||||
pub fn assert_consistency(rocket: &rocket::Rocket) {
|
||||
pub fn assert_consistency(rocket: &rocket::Rocket<rocket::Orbit>) {
|
||||
let db = rocket.state::<KeyDatabase>().unwrap();
|
||||
db.check_consistency().unwrap();
|
||||
}
|
||||
|
@ -610,7 +605,7 @@ pub mod tests {
|
|||
fn about_translation() {
|
||||
let (_tmpdir, config) = configuration().unwrap();
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
let client = Client::untracked(rocket).expect("valid rocket instance");
|
||||
|
||||
// Check that we see the landing page.
|
||||
let mut response = client.get("/about")
|
||||
|
@ -619,50 +614,50 @@ pub mod tests {
|
|||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
// TODO check translation
|
||||
assert!(response.body_string().unwrap().contains("Hagrid"));
|
||||
assert!(response.into_string().unwrap().contains("Hagrid"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basics() {
|
||||
let (_tmpdir, config) = configuration().unwrap();
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
let client = Client::untracked(rocket).expect("valid rocket instance");
|
||||
|
||||
// Check that we see the landing page.
|
||||
let mut response = client.get("/").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(response.body_string().unwrap().contains("Hagrid"));
|
||||
assert!(response.into_string().unwrap().contains("Hagrid"));
|
||||
|
||||
// Check that we see the privacy policy.
|
||||
let mut response = client.get("/about").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(response.body_string().unwrap().contains("distribution and discovery"));
|
||||
assert!(response.into_string().unwrap().contains("distribution and discovery"));
|
||||
|
||||
// Check that we see the privacy policy.
|
||||
let mut response = client.get("/about/privacy").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(response.body_string().unwrap().contains("Public Key Data"));
|
||||
assert!(response.into_string().unwrap().contains("Public Key Data"));
|
||||
|
||||
// Check that we see the API docs.
|
||||
let mut response = client.get("/about/api").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(response.body_string().unwrap().contains("/vks/v1/by-keyid"));
|
||||
assert!(response.into_string().unwrap().contains("/vks/v1/by-keyid"));
|
||||
|
||||
// Check that we see the upload form.
|
||||
let mut response = client.get("/upload").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(response.body_string().unwrap().contains("upload"));
|
||||
assert!(response.into_string().unwrap().contains("upload"));
|
||||
|
||||
// Check that we see the deletion form.
|
||||
let mut response = client.get("/manage").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(response.body_string().unwrap().contains("any verified email address"));
|
||||
assert!(response.into_string().unwrap().contains("any verified email address"));
|
||||
|
||||
assert_consistency(client.rocket());
|
||||
}
|
||||
|
@ -687,21 +682,21 @@ pub mod tests {
|
|||
let mut response = client.put("/").dispatch();
|
||||
assert_eq!(response.status(), Status::ServiceUnavailable);
|
||||
assert_eq!(response.content_type(), Some(ContentType::Plain));
|
||||
assert!(response.body_string().unwrap().contains("maintenance-message"));
|
||||
assert!(response.into_string().unwrap().contains("maintenance-message"));
|
||||
|
||||
fs::remove_file(&maintenance_path).unwrap();
|
||||
// Check that we see the upload form.
|
||||
let mut response = client.get("/upload").dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
assert!(!response.body_string().unwrap().contains("maintenance-message"));
|
||||
assert!(!response.into_string().unwrap().contains("maintenance-message"));
|
||||
}
|
||||
|
||||
fn check_maintenance(client: &Client, uri: &str, content_type: ContentType) {
|
||||
let mut response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), Status::ServiceUnavailable);
|
||||
assert_eq!(response.content_type(), Some(content_type));
|
||||
assert!(response.body_string().unwrap().contains("maintenance-message"));
|
||||
assert!(response.into_string().unwrap().contains("maintenance-message"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -781,7 +776,7 @@ pub mod tests {
|
|||
let (_tmpdir, config) = configuration().unwrap();
|
||||
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
let client = Client::untracked(rocket).expect("valid rocket instance");
|
||||
|
||||
// Generate two keys and upload them.
|
||||
let tpk_0 = build_cert("foo@invalid.example.com");
|
||||
|
@ -813,7 +808,7 @@ pub mod tests {
|
|||
let filemail_into = tmpdir.path().join("filemail");
|
||||
|
||||
let rocket = rocket_factory(rocket::custom(config)).unwrap();
|
||||
let client = Client::new(rocket).expect("valid rocket instance");
|
||||
let client = Client::untracked(rocket).expect("valid rocket instance");
|
||||
|
||||
// Generate two keys and upload them.
|
||||
let tpk_1 = build_cert("foo@invalid.example.com");
|
||||
|
@ -997,7 +992,7 @@ pub mod tests {
|
|||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(),
|
||||
Some(ContentType::new("application", "pgp-keys")));
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
assert!(body.contains("END PGP PUBLIC KEY BLOCK"));
|
||||
let tpk_ = Cert::from_bytes(body.as_bytes()).unwrap();
|
||||
assert_eq!(tpk.fingerprint(), tpk_.fingerprint());
|
||||
|
@ -1016,7 +1011,7 @@ pub mod tests {
|
|||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(),
|
||||
Some(ContentType::new("text", "plain")));
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
|
||||
assert!(body.contains("info:1:1"));
|
||||
let primary_fpr = tpk.fingerprint().to_hex();
|
||||
|
@ -1069,7 +1064,7 @@ pub mod tests {
|
|||
pub fn check_response(client: &Client, uri: &str, status: Status, needle: &str) {
|
||||
let mut response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), status);
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
println!("{}", body);
|
||||
assert!(body.contains(needle));
|
||||
}
|
||||
|
@ -1081,7 +1076,7 @@ pub mod tests {
|
|||
let mut response = client.get(uri).dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert_eq!(response.content_type(), Some(ContentType::HTML));
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
assert!(body.contains("found"));
|
||||
assert!(body.contains(&tpk.fingerprint().to_hex()));
|
||||
|
||||
|
@ -1106,7 +1101,7 @@ pub mod tests {
|
|||
.header(Header::new("X-Is-Onion", "true"))
|
||||
.dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let body = response.body_string().unwrap();
|
||||
let body = response.into_string().unwrap();
|
||||
assert!(body.contains("found"));
|
||||
assert!(body.contains(&tpk.fingerprint().to_hex()));
|
||||
|
||||
|
@ -1164,7 +1159,7 @@ pub mod tests {
|
|||
.body(json.as_bytes())
|
||||
.dispatch();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert!(response.body_string().unwrap().contains("pending"));
|
||||
assert!(response.into_string().unwrap().contains("pending"));
|
||||
}
|
||||
|
||||
fn check_mails_and_verify_email(client: &Client, filemail_path: &Path) {
|
||||
|
@ -1176,7 +1171,7 @@ pub mod tests {
|
|||
|
||||
let mut response_second = client.post(&confirm_uri).dispatch();
|
||||
assert_eq!(response_second.status(), Status::BadRequest);
|
||||
assert!(response_second.body_string().unwrap().contains("already been verified"));
|
||||
assert!(response_second.into_string().unwrap().contains("already been verified"));
|
||||
}
|
||||
|
||||
fn check_mails_and_confirm_deletion(client: &Client, filemail_path: &Path, address: &str) {
|
||||
|
@ -1196,7 +1191,7 @@ pub mod tests {
|
|||
|
||||
fn vks_publish_submit_multiple<'a>(client: &'a Client, data: &[u8]) {
|
||||
let mut response = vks_publish_submit_response(client, data);
|
||||
let response_body = response.body_string().unwrap();
|
||||
let response_body = response.into_string().unwrap();
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
assert!(response_body.contains("you must upload them individually"));
|
||||
|
@ -1204,7 +1199,7 @@ pub mod tests {
|
|||
|
||||
fn vks_publish_submit_get_token<'a>(client: &'a Client, data: &[u8]) -> String {
|
||||
let mut response = vks_publish_submit_response(client, data);
|
||||
let response_body = response.body_string().unwrap();
|
||||
let response_body = response.into_string().unwrap();
|
||||
|
||||
let pattern = "name=\"token\" value=\"([^\"]*)\"";
|
||||
let capture_re = regex::bytes::Regex::new(pattern).unwrap();
|
||||
|
@ -1247,8 +1242,8 @@ pub mod tests {
|
|||
let mut response = client.put("/")
|
||||
.body(data)
|
||||
.dispatch();
|
||||
let response_body = response.body_string().unwrap();
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
let response_body = response.into_string().unwrap();
|
||||
assert!(response_body.contains("Key successfully uploaded"));
|
||||
|
||||
let pattern = format!("{}/upload/([^ \t\n]*)", BASE_URI);
|
||||
|
@ -1263,7 +1258,7 @@ pub mod tests {
|
|||
.header(ContentType::JSON)
|
||||
.body(format!(r#"{{ "keytext": "{}" }}"#, base64::encode(data)))
|
||||
.dispatch();
|
||||
let response_body = response.body_string().unwrap();
|
||||
let response_body = response.into_string().unwrap();
|
||||
let result: vks_api::json::UploadResult = serde_json::from_str(&response_body).unwrap();
|
||||
|
||||
assert_eq!(response.status(), Status::Ok);
|
||||
|
|
|
@ -194,12 +194,12 @@ fn process_key_single(
|
|||
}
|
||||
|
||||
pub fn request_verify(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
request_origin: RequestOrigin,
|
||||
token_stateful: rocket::State<StatefulTokens>,
|
||||
token_stateless: rocket::State<tokens::Service>,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
token_stateful: &rocket::State<StatefulTokens>,
|
||||
token_stateless: &rocket::State<tokens::Service>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
token: String,
|
||||
addresses: Vec<String>,
|
||||
|
@ -273,9 +273,9 @@ fn send_verify_email(
|
|||
}
|
||||
|
||||
pub fn verify_confirm(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: &I18n,
|
||||
token_service: rocket::State<StatefulTokens>,
|
||||
token_service: &rocket::State<StatefulTokens>,
|
||||
token: String,
|
||||
) -> response::PublishResponse {
|
||||
let (fingerprint, email) = match check_publish_token(&db, &token_service, token) {
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use rocket_contrib::json::{Json,JsonValue,JsonError};
|
||||
use rocket::request::Request;
|
||||
use rocket::response::{self, Response, Responder};
|
||||
use rocket::request::Request; use rocket::response::{self, Response, Responder};
|
||||
use rocket::http::{ContentType,Status};
|
||||
use rocket::State;
|
||||
use rocket::serde::json::Json;
|
||||
use rocket_i18n::{I18n, Translations};
|
||||
use serde_json::json;
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::database::{KeyDatabase, StatefulTokens, Query};
|
||||
|
@ -17,6 +16,8 @@ use crate::web::{RequestOrigin, MyResponse};
|
|||
use crate::web::vks;
|
||||
use crate::web::vks::response::*;
|
||||
|
||||
use rocket::serde::json::Error as JsonError;
|
||||
|
||||
pub mod json {
|
||||
use crate::web::vks::response::EmailStatus;
|
||||
use std::collections::HashMap;
|
||||
|
@ -41,17 +42,17 @@ pub mod json {
|
|||
}
|
||||
}
|
||||
|
||||
type JsonResult = Result<JsonValue, JsonErrorResponse>;
|
||||
type JsonResult = Result<serde_json::Value, JsonErrorResponse>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct JsonErrorResponse(Status,String);
|
||||
|
||||
impl<'r> Responder<'r> for JsonErrorResponse {
|
||||
fn respond_to(self, _: &Request) -> response::Result<'r> {
|
||||
impl<'r> Responder<'r, 'static> for JsonErrorResponse {
|
||||
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
|
||||
let error_json = json!({"error": self.1});
|
||||
Response::build()
|
||||
.status(self.0)
|
||||
.sized_body(Cursor::new(error_json.to_string()))
|
||||
.sized_body(None, Cursor::new(error_json.to_string()))
|
||||
.header(ContentType::JSON)
|
||||
.ok()
|
||||
}
|
||||
|
@ -65,7 +66,7 @@ fn json_or_error<T>(data: Result<Json<T>, JsonError>) -> Result<Json<T>, JsonErr
|
|||
}
|
||||
}
|
||||
|
||||
fn upload_ok_json(response: UploadResponse) -> Result<JsonValue,JsonErrorResponse> {
|
||||
fn upload_ok_json(response: UploadResponse) -> Result<serde_json::Value, JsonErrorResponse> {
|
||||
match response {
|
||||
UploadResponse::Ok { token, key_fpr, status, .. } =>
|
||||
Ok(json!(json::UploadResult { token, key_fpr, status })),
|
||||
|
@ -76,9 +77,9 @@ fn upload_ok_json(response: UploadResponse) -> Result<JsonValue,JsonErrorRespons
|
|||
|
||||
#[post("/vks/v1/upload", format = "json", data = "<data>")]
|
||||
pub fn upload_json(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
data: Result<Json<json::UploadRequest>, JsonError>,
|
||||
) -> JsonResult {
|
||||
|
@ -98,7 +99,7 @@ pub fn upload_fallback(
|
|||
}
|
||||
|
||||
fn get_locale(
|
||||
langs: State<Translations>,
|
||||
langs: &rocket::State<Translations>,
|
||||
locales: Vec<String>,
|
||||
) -> I18n {
|
||||
locales
|
||||
|
@ -113,13 +114,13 @@ fn get_locale(
|
|||
|
||||
#[post("/vks/v1/request-verify", format = "json", data="<data>")]
|
||||
pub fn request_verify_json(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
langs: State<Translations>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
langs: &rocket::State<Translations>,
|
||||
request_origin: RequestOrigin,
|
||||
token_stateful: rocket::State<StatefulTokens>,
|
||||
token_stateless: rocket::State<tokens::Service>,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
token_stateful: &rocket::State<StatefulTokens>,
|
||||
token_stateless: &rocket::State<tokens::Service>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
data: Result<Json<json::VerifyRequest>, JsonError>,
|
||||
) -> JsonResult {
|
||||
let data = json_or_error(data)?;
|
||||
|
@ -141,7 +142,7 @@ pub fn request_verify_fallback(
|
|||
|
||||
#[get("/vks/v1/by-fingerprint/<fpr>")]
|
||||
pub fn vks_v1_by_fingerprint(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
fpr: String,
|
||||
) -> MyResponse {
|
||||
|
@ -155,7 +156,7 @@ pub fn vks_v1_by_fingerprint(
|
|||
|
||||
#[get("/vks/v1/by-email/<email>")]
|
||||
pub fn vks_v1_by_email(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
email: String,
|
||||
) -> MyResponse {
|
||||
|
@ -170,7 +171,7 @@ pub fn vks_v1_by_email(
|
|||
|
||||
#[get("/vks/v1/by-keyid/<kid>")]
|
||||
pub fn vks_v1_by_keyid(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
kid: String,
|
||||
) -> MyResponse {
|
||||
|
|
|
@ -4,11 +4,14 @@ use multipart::server::save::Entries;
|
|||
use multipart::server::save::SaveResult::*;
|
||||
use multipart::server::Multipart;
|
||||
|
||||
use rocket::data::ByteUnit;
|
||||
use rocket::form::Form;
|
||||
use rocket::form::ValueField;
|
||||
use rocket::http::ContentType;
|
||||
use rocket::request::Form;
|
||||
use rocket::Data;
|
||||
use rocket_i18n::I18n;
|
||||
use gettext_macros::i18n;
|
||||
use url::percent_encoding::percent_decode;
|
||||
|
||||
use crate::database::{KeyDatabase, StatefulTokens, Query, Database};
|
||||
use crate::mail;
|
||||
|
@ -17,13 +20,13 @@ use crate::web::{RequestOrigin, MyResponse};
|
|||
use crate::rate_limiter::RateLimiter;
|
||||
use crate::i18n_helpers::describe_query_error;
|
||||
|
||||
use std::io::Read;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Cursor;
|
||||
|
||||
use crate::web::vks;
|
||||
use crate::web::vks::response::*;
|
||||
|
||||
const UPLOAD_LIMIT: u64 = 1024 * 1024; // 1 MiB.
|
||||
const UPLOAD_LIMIT: ByteUnit = ByteUnit::Mebibyte(1);
|
||||
|
||||
mod forms {
|
||||
#[derive(FromForm,Deserialize)]
|
||||
|
@ -94,7 +97,7 @@ impl MyResponse {
|
|||
fn upload_response_quick(response: UploadResponse, base_uri: &str) -> Self {
|
||||
match response {
|
||||
UploadResponse::Ok { token, .. } => {
|
||||
let uri = uri!(quick_upload_proceed: token);
|
||||
let uri = uri!(quick_upload_proceed(token));
|
||||
let text = format!(
|
||||
"Key successfully uploaded. Proceed with verification here:\n{}{}\n",
|
||||
base_uri,
|
||||
|
@ -127,7 +130,7 @@ impl MyResponse {
|
|||
count_unparsed: usize,
|
||||
uid_status: HashMap<String,EmailStatus>,
|
||||
) -> Self {
|
||||
let key_link = uri!(search: &key_fpr).to_string();
|
||||
let key_link = uri!(search(q = &key_fpr)).to_string();
|
||||
|
||||
let count_revoked = uid_status.iter()
|
||||
.filter(|(_,status)| **status == EmailStatus::Revoked)
|
||||
|
@ -169,7 +172,7 @@ impl MyResponse {
|
|||
fn upload_ok_multi(key_fprs: Vec<String>) -> Self {
|
||||
let keys = key_fprs.into_iter()
|
||||
.map(|fpr| {
|
||||
let key_link = uri!(search: &fpr).to_string();
|
||||
let key_link = uri!(search(q = &fpr)).to_string();
|
||||
template::UploadOkKey {
|
||||
key_fpr: fpr.to_owned(),
|
||||
key_link,
|
||||
|
@ -192,9 +195,9 @@ pub fn upload() -> MyResponse {
|
|||
|
||||
#[post("/upload/submit", format = "multipart/form-data", data = "<data>")]
|
||||
pub fn upload_post_form_data(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
cont_type: &ContentType,
|
||||
data: Data,
|
||||
|
@ -206,9 +209,9 @@ pub fn upload_post_form_data(
|
|||
}
|
||||
|
||||
pub fn process_post_form_data(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
cont_type: &ContentType,
|
||||
data: Data,
|
||||
|
@ -225,7 +228,7 @@ pub fn process_post_form_data(
|
|||
|
||||
#[get("/search?<q>")]
|
||||
pub fn search(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
q: String,
|
||||
) -> MyResponse {
|
||||
|
@ -236,7 +239,7 @@ pub fn search(
|
|||
}
|
||||
|
||||
fn key_to_response(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
i18n: I18n,
|
||||
query_string: String,
|
||||
query: Query,
|
||||
|
@ -259,20 +262,18 @@ fn key_to_response(
|
|||
|
||||
|
||||
#[put("/", data = "<data>")]
|
||||
pub fn quick_upload(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
pub async fn quick_upload(
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
request_origin: RequestOrigin,
|
||||
data: Data,
|
||||
data: Data<'_>,
|
||||
) -> MyResponse {
|
||||
use std::io::Cursor;
|
||||
|
||||
let mut buf = Vec::default();
|
||||
if let Err(error) = std::io::copy(&mut data.open().take(UPLOAD_LIMIT), &mut buf) {
|
||||
return MyResponse::bad_request("400-plain", anyhow!(error));
|
||||
}
|
||||
let buf = match data.open(UPLOAD_LIMIT).into_bytes().await {
|
||||
Ok(buf) => buf.into_inner(),
|
||||
Err(error) => return MyResponse::bad_request("400-plain", anyhow!(error)),
|
||||
};
|
||||
|
||||
MyResponse::upload_response_quick(
|
||||
vks::process_key(
|
||||
|
@ -286,12 +287,12 @@ pub fn quick_upload(
|
|||
|
||||
#[get("/upload/<token>", rank = 2)]
|
||||
pub fn quick_upload_proceed(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
request_origin: RequestOrigin,
|
||||
token_stateful: rocket::State<StatefulTokens>,
|
||||
token_stateless: rocket::State<tokens::Service>,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
token_stateful: &rocket::State<StatefulTokens>,
|
||||
token_stateless: &rocket::State<tokens::Service>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
token: String,
|
||||
) -> MyResponse {
|
||||
|
@ -303,43 +304,37 @@ pub fn quick_upload_proceed(
|
|||
|
||||
|
||||
#[post("/upload/submit", format = "application/x-www-form-urlencoded", data = "<data>")]
|
||||
pub fn upload_post_form(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
tokens_stateless: rocket::State<tokens::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
pub async fn upload_post_form(
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
tokens_stateless: &rocket::State<tokens::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
data: Data,
|
||||
data: Data<'_>,
|
||||
) -> MyResponse {
|
||||
match process_post_form(&db, &tokens_stateless, &rate_limiter, &i18n, data) {
|
||||
match process_post_form(&db, &tokens_stateless, &rate_limiter, &i18n, data).await {
|
||||
Ok(response) => MyResponse::upload_response(response),
|
||||
Err(err) => MyResponse::bad_request("upload/upload", err),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_post_form(
|
||||
pub async fn process_post_form(
|
||||
db: &KeyDatabase,
|
||||
tokens_stateless: &tokens::Service,
|
||||
rate_limiter: &RateLimiter,
|
||||
i18n: &I18n,
|
||||
data: Data,
|
||||
data: Data<'_>,
|
||||
) -> Result<UploadResponse> {
|
||||
use rocket::request::FormItems;
|
||||
use std::io::Cursor;
|
||||
|
||||
// application/x-www-form-urlencoded
|
||||
let mut buf = Vec::default();
|
||||
let buf = data.open(UPLOAD_LIMIT).into_bytes().await?;
|
||||
|
||||
std::io::copy(&mut data.open().take(UPLOAD_LIMIT), &mut buf)?;
|
||||
|
||||
for item in FormItems::from(&*String::from_utf8_lossy(&buf)) {
|
||||
let (key, value) = item.key_value();
|
||||
let decoded_value = value.url_decode().or_else(|_| {
|
||||
for ValueField { name, value } in Form::values(&*String::from_utf8_lossy(&buf)) {
|
||||
let decoded_value = percent_decode(value.as_bytes()).decode_utf8().or_else(|_| {
|
||||
Err(anyhow!(
|
||||
"`Content-Type: application/x-www-form-urlencoded` \
|
||||
not valid"))
|
||||
})?;
|
||||
|
||||
match key.as_str() {
|
||||
match name.to_string().as_str() {
|
||||
"keytext" => {
|
||||
return Ok(vks::process_key(
|
||||
&db,
|
||||
|
@ -368,7 +363,7 @@ fn process_upload(
|
|||
// saves all fields, any field longer than 10kB goes to a temporary directory
|
||||
// Entries could implement FromData though that would give zero control over
|
||||
// how the files are saved; Multipart would be a good impl candidate though
|
||||
match Multipart::with_body(data.open().take(UPLOAD_LIMIT), boundary).save().temp() {
|
||||
match Multipart::with_body(data.open(UPLOAD_LIMIT), boundary).save().temp() {
|
||||
Full(entries) => {
|
||||
process_multipart(db, tokens_stateless, rate_limiter, i18n, entries)
|
||||
}
|
||||
|
@ -398,12 +393,12 @@ fn process_multipart(
|
|||
|
||||
#[post("/upload/request-verify", format = "application/x-www-form-urlencoded", data="<request>")]
|
||||
pub fn request_verify_form(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
request_origin: RequestOrigin,
|
||||
token_stateful: rocket::State<StatefulTokens>,
|
||||
token_stateless: rocket::State<tokens::Service>,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
token_stateful: &rocket::State<StatefulTokens>,
|
||||
token_stateless: &rocket::State<tokens::Service>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
request: Form<forms::VerifyRequest>,
|
||||
) -> MyResponse {
|
||||
|
@ -416,12 +411,12 @@ pub fn request_verify_form(
|
|||
|
||||
#[post("/upload/request-verify", format = "multipart/form-data", data="<request>")]
|
||||
pub fn request_verify_form_data(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
request_origin: RequestOrigin,
|
||||
token_stateful: rocket::State<StatefulTokens>,
|
||||
token_stateless: rocket::State<tokens::Service>,
|
||||
mail_service: rocket::State<mail::Service>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
token_stateful: &rocket::State<StatefulTokens>,
|
||||
token_stateless: &rocket::State<tokens::Service>,
|
||||
mail_service: &rocket::State<mail::Service>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
request: Form<forms::VerifyRequest>,
|
||||
) -> MyResponse {
|
||||
|
@ -434,9 +429,9 @@ pub fn request_verify_form_data(
|
|||
|
||||
#[post("/verify/<token>")]
|
||||
pub fn verify_confirm(
|
||||
db: rocket::State<KeyDatabase>,
|
||||
token_service: rocket::State<StatefulTokens>,
|
||||
rate_limiter: rocket::State<RateLimiter>,
|
||||
db: &rocket::State<KeyDatabase>,
|
||||
token_service: &rocket::State<StatefulTokens>,
|
||||
rate_limiter: &rocket::State<RateLimiter>,
|
||||
i18n: I18n,
|
||||
token: String,
|
||||
) -> MyResponse {
|
||||
|
@ -444,7 +439,7 @@ pub fn verify_confirm(
|
|||
match vks::verify_confirm(db, &i18n, token_service, token) {
|
||||
PublishResponse::Ok { fingerprint, email } => {
|
||||
rate_limiter.action_perform(rate_limit_id);
|
||||
let userid_link = uri!(search: &email).to_string();
|
||||
let userid_link = uri!(search(q = &email)).to_string();
|
||||
let context = template::Verify {
|
||||
userid: email,
|
||||
key_fpr: fingerprint,
|
||||
|
|
Loading…
Reference in New Issue