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
}