hagrid-keyserver--hagrid/src/web/manage.rs

196 lines
6.1 KiB
Rust
Raw Normal View History

2019-04-05 15:07:40 +00:00
use rocket;
use rocket::State;
use rocket::request::Form;
use failure::Fallible as Result;
use web::{RequestOrigin, MyResponse, templates::General};
use web::vks_web;
use database::{Database, KeyDatabase, types::Email, types::Fingerprint};
2019-04-05 15:07:40 +00:00
use mail;
use counters;
2019-05-05 12:58:05 +00:00
use rate_limiter::RateLimiter;
use tokens::{self, StatelessSerializable};
#[derive(Debug,Serialize,Deserialize)]
struct StatelessVerifyToken {
fpr: Fingerprint,
}
impl StatelessSerializable for StatelessVerifyToken {
}
2019-04-05 15:07:40 +00:00
mod templates {
#[derive(Serialize)]
pub struct ManageKey {
2019-04-26 21:13:56 +00:00
pub key_fpr: String,
pub key_link: String,
pub base_uri: String,
2019-04-05 15:07:40 +00:00
pub uid_status: Vec<ManageKeyUidStatus>,
pub token: String,
pub commit: String,
pub version: String,
}
#[derive(Serialize)]
pub struct ManageLinkSent {
pub address: String,
}
#[derive(Serialize)]
pub struct ManageKeyUidStatus {
pub address: String,
pub published: bool,
}
}
pub mod forms {
#[derive(FromForm)]
pub struct ManageRequest {
pub search_term: String,
}
#[derive(FromForm)]
pub struct ManageDelete {
pub token: String,
pub address: String,
}
}
2019-04-25 18:04:20 +00:00
#[get("/manage")]
2019-04-05 15:07:40 +00:00
pub fn vks_manage() -> Result<MyResponse> {
Ok(MyResponse::ok("manage/manage", General::default()))
}
2019-04-25 18:04:20 +00:00
#[get("/manage/<token>")]
2019-04-05 15:07:40 +00:00
pub fn vks_manage_key(
request_origin: RequestOrigin,
2019-04-26 22:21:30 +00:00
db: State<KeyDatabase>,
2019-04-05 15:07:40 +00:00
token: String,
token_service: rocket::State<tokens::Service>,
) -> MyResponse {
use database::types::Fingerprint;
use std::convert::TryFrom;
if let Ok(StatelessVerifyToken { fpr }) = token_service.check(&token) {
match db.lookup(&database::Query::ByFingerprint(fpr)) {
2019-04-05 15:07:40 +00:00
Ok(Some(tpk)) => {
let fp = Fingerprint::try_from(tpk.fingerprint()).unwrap();
2019-04-05 15:07:40 +00:00
let mut emails: Vec<Email> = tpk.userids()
.map(|u| u.userid().to_string().parse::<Email>())
.flatten()
.collect();
emails.sort_unstable();
emails.dedup();
let uid_status = emails.into_iter().map(|email|
templates::ManageKeyUidStatus {
address: email.to_string(),
published: true,
}
).collect();
let key_link = uri!(vks_web::search: fp.to_string()).to_string();
2019-04-05 15:07:40 +00:00
let context = templates::ManageKey {
2019-04-26 21:13:56 +00:00
key_fpr: fp.to_string(),
key_link,
2019-04-05 15:07:40 +00:00
uid_status,
token,
base_uri: request_origin.get_base_uri().to_owned(),
2019-04-05 15:07:40 +00:00
version: env!("VERGEN_SEMVER").to_string(),
commit: env!("VERGEN_SHA_SHORT").to_string(),
};
MyResponse::ok("manage/manage_key", context)
},
Ok(None) => MyResponse::not_found(
Some("manage/manage"),
Some("This link is invalid or expired".to_owned())),
Err(e) => MyResponse::ise(e),
}
} else {
MyResponse::not_found(
Some("manage/manage"),
Some("This link is invalid or expired".to_owned()))
2019-04-05 15:07:40 +00:00
}
}
2019-04-25 18:04:20 +00:00
#[post("/manage", data="<request>")]
2019-04-05 15:07:40 +00:00
pub fn vks_manage_post(
2019-04-26 22:21:30 +00:00
db: State<KeyDatabase>,
request_origin: RequestOrigin,
2019-05-05 12:58:05 +00:00
mail_service: rocket::State<mail::Service>,
rate_limiter: rocket::State<RateLimiter>,
2019-04-05 15:07:40 +00:00
request: Form<forms::ManageRequest>,
token_service: rocket::State<tokens::Service>,
) -> MyResponse {
use std::convert::TryInto;
let email = match request.search_term.parse::<Email>() {
Ok(email) => email,
Err(_) => return MyResponse::not_found(
Some("manage/manage"),
2019-05-05 12:58:05 +00:00
Some(format!("Malformed email address: {}", request.search_term)))
2019-04-05 15:07:40 +00:00
};
let tpk = match db.lookup(&database::Query::ByEmail(email.clone())) {
Ok(Some(tpk)) => tpk,
Ok(None) => return MyResponse::not_found(
Some("manage/manage"),
2019-05-05 12:58:05 +00:00
Some(format!("No key for address {}", request.search_term))),
2019-04-05 15:07:40 +00:00
Err(e) => return MyResponse::ise(e),
};
2019-05-05 12:58:05 +00:00
let email_exists = tpk.userids()
.flat_map(|binding| binding.userid().to_string().parse::<Email>())
.any(|candidate| candidate == email);
if !email_exists {
return MyResponse::ise(failure::err_msg("Address check failed!"));
}
if !rate_limiter.action_perform(format!("manage-{}", &email)) {
return MyResponse::not_found(
Some("manage/manage"),
Some("A request was already sent for this address recently.".to_owned()));
}
let fpr: Fingerprint = tpk.fingerprint().try_into().unwrap();
let fpr_text = fpr.to_string();
2019-05-20 21:17:50 +00:00
let token = token_service.create(&StatelessVerifyToken { fpr });
2019-06-06 16:10:47 +00:00
let link_path = uri!(vks_manage_key: token).to_string();
2019-05-05 12:58:05 +00:00
let base_uri = request_origin.get_base_uri();
if let Err(e) = mail_service.send_manage_token(base_uri, fpr_text, &email, &link_path) {
2019-05-05 12:58:05 +00:00
return MyResponse::ise(e);
2019-04-05 15:07:40 +00:00
}
2019-05-05 12:58:05 +00:00
2019-04-05 15:07:40 +00:00
let ctx = templates::ManageLinkSent {
address: email.to_string(),
};
MyResponse::ok("manage/manage_link_sent", ctx)
}
2019-04-25 18:04:20 +00:00
#[post("/manage/unpublish", data="<request>")]
2019-04-05 15:07:40 +00:00
pub fn vks_manage_unpublish(
request_origin: RequestOrigin,
2019-04-26 22:21:30 +00:00
db: rocket::State<KeyDatabase>,
2019-04-05 15:07:40 +00:00
token_service: rocket::State<tokens::Service>,
request: Form<forms::ManageDelete>,
) -> MyResponse {
match vks_manage_unpublish_or_fail(request_origin, db, token_service, request) {
2019-04-05 15:07:40 +00:00
Ok(response) => response,
Err(e) => MyResponse::ise(e),
}
}
pub fn vks_manage_unpublish_or_fail(
request_origin: RequestOrigin,
2019-04-26 22:21:30 +00:00
db: rocket::State<KeyDatabase>,
2019-04-05 15:07:40 +00:00
token_service: rocket::State<tokens::Service>,
request: Form<forms::ManageDelete>,
) -> Result<MyResponse> {
let verify_token = token_service.check::<StatelessVerifyToken>(&request.token)?;
2019-04-05 15:07:40 +00:00
let email = request.address.parse::<Email>()?;
db.set_email_unpublished(&verify_token.fpr, &email)?;
counters::inc_address_unpublished(&email);
Ok(vks_manage_key(request_origin, db, request.token.to_owned(), token_service))
2019-04-05 15:07:40 +00:00
}