use rocket; use rocket::State; use rocket::request::Form; use failure::Fallible as Result; use web::{MyResponse,templates::General}; use database::{Database, Polymorphic}; use database::types::Email; use mail; use tokens; mod templates { #[derive(Serialize)] pub struct ManageKey { // pub uid_unpublished: Option, pub uid_status: Vec, 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, } } #[get("/manage")] pub fn vks_manage() -> Result { Ok(MyResponse::ok("manage/manage", General::default())) } #[get("/manage/")] pub fn vks_manage_key( db: State, token: String, token_service: rocket::State, ) -> MyResponse { if let Ok(fingerprint) = token_service.check(&token) { match db.lookup(&database::Query::ByFingerprint(fingerprint)) { Ok(Some(tpk)) => { let mut emails: Vec = tpk.userids() .map(|u| u.userid().to_string().parse::()) .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 context = templates::ManageKey { uid_status, token, 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::ok("manage/manage_expired", General::default()) } } #[post("/manage", data="")] pub fn vks_manage_post( db: State, request: Form, token_service: rocket::State, mail_service: Option>, ) -> MyResponse { use std::convert::TryInto; let email = match request.search_term.parse::() { Ok(email) => email, Err(_) => return MyResponse::not_found( Some("manage/manage"), Some(format!("Malformed email address: {:?}", request.search_term))) }; let tpk = match db.lookup(&database::Query::ByEmail(email.clone())) { Ok(Some(tpk)) => tpk, Ok(None) => return MyResponse::not_found( Some("manage/manage"), Some(format!("No key for address {:?}", request.search_term))), Err(e) => return MyResponse::ise(e), }; let fpr = tpk.fingerprint().try_into().unwrap(); let token = token_service.create(&fpr); let token_uri = uri!(vks_manage_key: token).to_string(); if let Some(mail_service) = mail_service { for binding in tpk.userids() { let email_candidate = binding.userid().to_string().parse::(); if let Ok(email_candidate) = email_candidate { if &email_candidate != &email { continue; } if let Err(e) = mail_service.send_manage_token( &[email_candidate], &token_uri) { return MyResponse::ise(e); } } } } let ctx = templates::ManageLinkSent { address: email.to_string(), }; MyResponse::ok("manage/manage_link_sent", ctx) } #[post("/manage/unpublish", data="")] pub fn vks_manage_unpublish( db: rocket::State, token_service: rocket::State, request: Form, ) -> MyResponse { match vks_manage_unpublish_or_fail(db, token_service, request) { Ok(response) => response, Err(e) => MyResponse::ise(e), } } pub fn vks_manage_unpublish_or_fail( db: rocket::State, token_service: rocket::State, request: Form, ) -> Result { let fpr = token_service.check(&request.token)?; let email = request.address.parse::()?; db.delete_userids_matching(&fpr, &email)?; Ok(vks_manage_key(db, request.token.to_owned(), token_service)) }