2022-01-10 20:32:59 -05:00
|
|
|
use rocket::request::Request; use rocket::response::{self, Response, Responder};
|
2019-05-23 19:01:24 -04:00
|
|
|
use rocket::http::{ContentType,Status};
|
2022-01-10 20:32:59 -05:00
|
|
|
use rocket::serde::json::Json;
|
2019-08-28 14:33:24 -04:00
|
|
|
use rocket_i18n::{I18n, Translations};
|
2022-01-10 20:32:59 -05:00
|
|
|
use serde_json::json;
|
2019-05-23 19:01:24 -04:00
|
|
|
use std::io::Cursor;
|
|
|
|
|
2019-09-02 16:49:02 -04:00
|
|
|
use crate::database::{KeyDatabase, StatefulTokens, Query};
|
|
|
|
use crate::database::types::{Email, Fingerprint, KeyID};
|
|
|
|
use crate::mail;
|
|
|
|
use crate::tokens;
|
|
|
|
use crate::rate_limiter::RateLimiter;
|
2019-05-23 19:01:24 -04:00
|
|
|
|
2019-09-02 16:49:02 -04:00
|
|
|
use crate::web;
|
2022-01-04 07:33:03 -05:00
|
|
|
use crate::web::{RequestOrigin, MyResponse};
|
2019-09-02 16:49:02 -04:00
|
|
|
use crate::web::vks;
|
|
|
|
use crate::web::vks::response::*;
|
2019-05-23 19:01:24 -04:00
|
|
|
|
2022-01-10 20:32:59 -05:00
|
|
|
use rocket::serde::json::Error as JsonError;
|
|
|
|
|
2019-05-23 19:01:24 -04:00
|
|
|
pub mod json {
|
2019-09-02 16:49:02 -04:00
|
|
|
use crate::web::vks::response::EmailStatus;
|
2019-05-23 19:01:24 -04:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct VerifyRequest {
|
|
|
|
pub token: String,
|
|
|
|
pub addresses: Vec<String>,
|
2019-08-28 14:33:24 -04:00
|
|
|
pub locale: Option<Vec<String>>,
|
2019-05-23 19:01:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize)]
|
|
|
|
pub struct UploadRequest {
|
|
|
|
pub keytext: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize,Deserialize)]
|
|
|
|
pub struct UploadResult {
|
|
|
|
pub token: String,
|
|
|
|
pub key_fpr: String,
|
|
|
|
pub status: HashMap<String,EmailStatus>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-10 20:32:59 -05:00
|
|
|
type JsonResult = Result<serde_json::Value, JsonErrorResponse>;
|
2019-05-23 19:01:24 -04:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct JsonErrorResponse(Status,String);
|
|
|
|
|
2022-01-10 20:32:59 -05:00
|
|
|
impl<'r> Responder<'r, 'static> for JsonErrorResponse {
|
|
|
|
fn respond_to(self, _: &'r Request<'_>) -> response::Result<'static> {
|
2019-05-23 19:01:24 -04:00
|
|
|
let error_json = json!({"error": self.1});
|
|
|
|
Response::build()
|
|
|
|
.status(self.0)
|
2022-01-10 20:32:59 -05:00
|
|
|
.sized_body(None, Cursor::new(error_json.to_string()))
|
2019-05-23 19:01:24 -04:00
|
|
|
.header(ContentType::JSON)
|
|
|
|
.ok()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn json_or_error<T>(data: Result<Json<T>, JsonError>) -> Result<Json<T>, JsonErrorResponse> {
|
|
|
|
match data {
|
|
|
|
Ok(data) => Ok(data),
|
|
|
|
Err(JsonError::Io(_)) => Err(JsonErrorResponse(Status::InternalServerError, "i/o error!".to_owned())),
|
|
|
|
Err(JsonError::Parse(_, e)) => Err(JsonErrorResponse(Status::BadRequest, e.to_string())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-10 20:32:59 -05:00
|
|
|
fn upload_ok_json(response: UploadResponse) -> Result<serde_json::Value, JsonErrorResponse> {
|
2019-05-23 19:01:24 -04:00
|
|
|
match response {
|
2019-06-08 11:15:46 -04:00
|
|
|
UploadResponse::Ok { token, key_fpr, status, .. } =>
|
2019-05-23 19:01:24 -04:00
|
|
|
Ok(json!(json::UploadResult { token, key_fpr, status })),
|
|
|
|
UploadResponse::OkMulti { key_fprs } => Ok(json!(key_fprs)),
|
|
|
|
UploadResponse::Error(error) => Err(JsonErrorResponse(Status::BadRequest, error)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[post("/vks/v1/upload", format = "json", data = "<data>")]
|
|
|
|
pub fn upload_json(
|
2022-01-10 20:32:59 -05:00
|
|
|
db: &rocket::State<KeyDatabase>,
|
|
|
|
tokens_stateless: &rocket::State<tokens::Service>,
|
|
|
|
rate_limiter: &rocket::State<RateLimiter>,
|
2019-09-28 15:54:00 -04:00
|
|
|
i18n: I18n,
|
2019-05-23 19:01:24 -04:00
|
|
|
data: Result<Json<json::UploadRequest>, JsonError>,
|
|
|
|
) -> JsonResult {
|
|
|
|
let data = json_or_error(data)?;
|
|
|
|
use std::io::Cursor;
|
|
|
|
let data_reader = Cursor::new(data.keytext.as_bytes());
|
2019-09-28 15:54:00 -04:00
|
|
|
let result = vks::process_key(&db, &i18n, &tokens_stateless, &rate_limiter, data_reader);
|
2019-05-23 19:01:24 -04:00
|
|
|
upload_ok_json(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[post("/vks/v1/upload", rank = 2)]
|
|
|
|
pub fn upload_fallback(
|
2022-01-17 10:03:56 -05:00
|
|
|
origin: RequestOrigin,
|
2019-05-23 19:01:24 -04:00
|
|
|
) -> JsonErrorResponse {
|
2022-01-17 10:03:56 -05:00
|
|
|
let error_msg = format!("expected application/json data. see {}/about/api for api docs.", origin.get_base_uri());
|
2019-05-24 05:55:34 -04:00
|
|
|
JsonErrorResponse(Status::BadRequest, error_msg)
|
2019-05-23 19:01:24 -04:00
|
|
|
}
|
|
|
|
|
2019-08-28 14:33:24 -04:00
|
|
|
fn get_locale(
|
2022-01-10 20:32:59 -05:00
|
|
|
langs: &rocket::State<Translations>,
|
2019-08-28 14:33:24 -04:00
|
|
|
locales: Vec<String>,
|
|
|
|
) -> I18n {
|
|
|
|
locales
|
|
|
|
.iter()
|
|
|
|
.flat_map(|lang| lang.split(|c| c == '-' || c == ';' || c == '_').next())
|
|
|
|
.flat_map(|lang| langs.iter().find(|(trans, _)| trans == &lang))
|
|
|
|
.next()
|
|
|
|
.or_else(|| langs.iter().find(|(trans, _)| trans == &"en"))
|
|
|
|
.map(|(lang, catalog)| I18n { catalog: catalog.clone(), lang })
|
|
|
|
.expect("Expected to have an english translation!")
|
|
|
|
}
|
|
|
|
|
2019-05-23 19:01:24 -04:00
|
|
|
#[post("/vks/v1/request-verify", format = "json", data="<data>")]
|
|
|
|
pub fn request_verify_json(
|
2022-01-10 20:32:59 -05:00
|
|
|
db: &rocket::State<KeyDatabase>,
|
|
|
|
langs: &rocket::State<Translations>,
|
2022-01-17 10:03:56 -05:00
|
|
|
origin: RequestOrigin,
|
2022-01-10 20:32:59 -05:00
|
|
|
token_stateful: &rocket::State<StatefulTokens>,
|
|
|
|
token_stateless: &rocket::State<tokens::Service>,
|
|
|
|
mail_service: &rocket::State<mail::Service>,
|
|
|
|
rate_limiter: &rocket::State<RateLimiter>,
|
2019-05-23 19:01:24 -04:00
|
|
|
data: Result<Json<json::VerifyRequest>, JsonError>,
|
|
|
|
) -> JsonResult {
|
|
|
|
let data = json_or_error(data)?;
|
2019-08-28 14:33:24 -04:00
|
|
|
let json::VerifyRequest { token, addresses, locale } = data.into_inner();
|
|
|
|
let i18n = get_locale(langs, locale.unwrap_or_default());
|
2019-05-23 19:01:24 -04:00
|
|
|
let result = vks::request_verify(
|
2022-01-17 10:03:56 -05:00
|
|
|
db, &origin, token_stateful, token_stateless, mail_service,
|
2022-01-17 08:21:07 -05:00
|
|
|
rate_limiter, &i18n, token, addresses);
|
2019-05-23 19:01:24 -04:00
|
|
|
upload_ok_json(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[post("/vks/v1/request-verify", rank = 2)]
|
|
|
|
pub fn request_verify_fallback(
|
2022-01-17 10:03:56 -05:00
|
|
|
origin: RequestOrigin,
|
2019-05-23 19:01:24 -04:00
|
|
|
) -> JsonErrorResponse {
|
2022-01-17 10:03:56 -05:00
|
|
|
let error_msg = format!("expected application/json data. see {}/about/api for api docs.", origin.get_base_uri());
|
2019-05-24 05:55:34 -04:00
|
|
|
JsonErrorResponse(Status::BadRequest, error_msg)
|
2019-05-23 19:01:24 -04:00
|
|
|
}
|
2019-06-11 10:59:27 -04:00
|
|
|
|
|
|
|
#[get("/vks/v1/by-fingerprint/<fpr>")]
|
2021-02-20 07:28:32 -05:00
|
|
|
pub fn vks_v1_by_fingerprint(
|
2022-01-10 20:32:59 -05:00
|
|
|
db: &rocket::State<KeyDatabase>,
|
2021-02-20 07:28:32 -05:00
|
|
|
i18n: I18n,
|
|
|
|
fpr: String,
|
|
|
|
) -> MyResponse {
|
2019-06-11 10:59:27 -04:00
|
|
|
let query = match fpr.parse::<Fingerprint>() {
|
|
|
|
Ok(fpr) => Query::ByFingerprint(fpr),
|
2019-07-11 16:30:46 -04:00
|
|
|
Err(_) => return MyResponse::bad_request_plain("malformed fingerprint"),
|
2019-06-11 10:59:27 -04:00
|
|
|
};
|
|
|
|
|
2022-01-04 07:33:03 -05:00
|
|
|
web::key_to_response_plain(db, i18n, query)
|
2019-06-11 10:59:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/vks/v1/by-email/<email>")]
|
2021-02-20 07:28:32 -05:00
|
|
|
pub fn vks_v1_by_email(
|
2022-01-10 20:32:59 -05:00
|
|
|
db: &rocket::State<KeyDatabase>,
|
2021-02-20 07:28:32 -05:00
|
|
|
i18n: I18n,
|
|
|
|
email: String,
|
|
|
|
) -> MyResponse {
|
2019-07-11 16:30:46 -04:00
|
|
|
let email = email.replace("%40", "@");
|
2019-06-11 10:59:27 -04:00
|
|
|
let query = match email.parse::<Email>() {
|
|
|
|
Ok(email) => Query::ByEmail(email),
|
2019-07-11 16:30:46 -04:00
|
|
|
Err(_) => return MyResponse::bad_request_plain("malformed e-mail address"),
|
2019-06-11 10:59:27 -04:00
|
|
|
};
|
|
|
|
|
2022-01-04 07:33:03 -05:00
|
|
|
web::key_to_response_plain(db, i18n, query)
|
2019-06-11 10:59:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#[get("/vks/v1/by-keyid/<kid>")]
|
2021-02-20 07:28:32 -05:00
|
|
|
pub fn vks_v1_by_keyid(
|
2022-01-10 20:32:59 -05:00
|
|
|
db: &rocket::State<KeyDatabase>,
|
2021-02-20 07:28:32 -05:00
|
|
|
i18n: I18n,
|
|
|
|
kid: String,
|
|
|
|
) -> MyResponse {
|
2019-06-11 10:59:27 -04:00
|
|
|
let query = match kid.parse::<KeyID>() {
|
|
|
|
Ok(keyid) => Query::ByKeyID(keyid),
|
2019-07-11 16:30:46 -04:00
|
|
|
Err(_) => return MyResponse::bad_request_plain("malformed key id"),
|
2019-06-11 10:59:27 -04:00
|
|
|
};
|
|
|
|
|
2022-01-04 07:33:03 -05:00
|
|
|
web::key_to_response_plain(db, i18n, query)
|
2019-06-11 10:59:27 -04:00
|
|
|
}
|