use crate::{negative_report::EncryptedNegativeReport, positive_report::PositiveReport, *}; use hyper::{body, header::HeaderValue, Body, Method, Request, Response, StatusCode}; use serde_json::json; use sled::Db; use std::convert::Infallible; // Handle submitted reports pub async fn handle(db: &Db, req: Request) -> Result, Infallible> { match req.method() { &Method::OPTIONS => Ok(Response::builder() .header("Access-Control-Allow-Origin", HeaderValue::from_static("*")) .header("Access-Control-Allow-Headers", "accept, content-type") .header("Access-Control-Allow-Methods", "POST") .status(200) .body(Body::from("Allow POST")) .unwrap()), _ => match (req.method(), req.uri().path()) { #[cfg(feature = "simulation")] (&Method::POST, "/nrkey") => Ok::<_, Infallible>({ // We need a way for simulated users to get the keys to // encrypt their negative reports. As Troll Patrol may // not be directly accessible when users are submitting // negative reports, in practice we expect that these // keys will be made available elsewhere. let bytes = body::to_bytes(req.into_body()).await.unwrap(); // Expect the body to contain the date for the key the // user requests. let date: u32 = match serde_json::from_slice(&bytes) { Ok(date) => date, Err(e) => { let response = json!({"error": e.to_string()}); let val = serde_json::to_string(&response).unwrap(); return Ok(prepare_header(val)); } }; // Get the current key or generate a new one. Note that // this code is only called in simulation. In // production, users should not be able to induce Troll // Patrol to generate new keys. let pubkey = match get_negative_report_public_key(&db, date) { Some(k) => Some(k), None => new_negative_report_key(&db, date), }; prepare_header(serde_json::to_string(&pubkey).unwrap()) }), (&Method::POST, "/negativereport") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); // We cannot depend on the transport layer providing E2EE, so // negative reports should be separately encrypted. let enr: EncryptedNegativeReport = match bincode::deserialize(&bytes) { Ok(enr) => enr, Err(e) => { let response = json!({"error": e.to_string()}); let val = serde_json::to_string(&response).unwrap(); return Ok(prepare_header(val)); } }; handle_encrypted_negative_report(db, enr); prepare_header("OK".to_string()) }), (&Method::POST, "/positivereport") => Ok::<_, Infallible>({ let bytes = body::to_bytes(req.into_body()).await.unwrap(); let pr = match PositiveReport::from_slice(&bytes) { Ok(pr) => pr, Err(e) => { let response = json!({"error": e}); let val = serde_json::to_string(&response).unwrap(); return Ok(prepare_header(val)); } }; save_positive_report_to_process(db, pr); prepare_header("OK".to_string()) }), _ => { // Return 404 not found response. Ok(Response::builder() .status(StatusCode::NOT_FOUND) .body(Body::from("Not found")) .unwrap()) } }, } } // Prepare HTTP Response for successful Server Request pub fn prepare_header(response: String) -> Response { let mut resp = Response::new(Body::from(response)); resp.headers_mut() .insert("Access-Control-Allow-Origin", HeaderValue::from_static("*")); resp }