use hyper::{Body, Request, Response, StatusCode}; use hyper::body::Buf; use rust_util::{simple_error, XResult}; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; use crate::{db, jose}; use crate::db::Key; use crate::do_response; use crate::serve_common::{byte_to_multi_view_map, get_master_key, MultipleViewValue, open_local_db}; use crate::serve_common::Result; #[derive(Serialize, Deserialize)] struct Named { name: String, } #[derive(Serialize, Deserialize)] struct NamedValue { name: String, force_write: Option, value: MultipleViewValue, } pub async fn read(req: Request) -> Result> { do_response!(inner_read(req).await) } async fn inner_read(req: Request) -> XResult<(StatusCode, Value)> { let whole_body = hyper::body::aggregate(req).await?; let named: Named = serde_json::from_reader(whole_body.reader())?; let name = &named.name; if name.is_empty() { return simple_error!("Key name cannot be empty"); } let db_key_name = db::make_db_key_name(name); let conn = open_local_db()?; let db_key = db::find_key(&conn, &db_key_name)?; let db_key_value = match db_key { None => return simple_error!("Key '{}' already exists", name), Some(k) => k, }; let key = match get_master_key() { None => return Ok((StatusCode::BAD_REQUEST, json!({ "error": "status_not_ready" }))), Some(key) => key, }; let data = jose::deserialize_jwe_aes(&db_key_value.encrypted_key, &*key.read())?; drop(key); let mut map = byte_to_multi_view_map(&data.0); map.insert("name".to_string(), Value::String(name.to_string())); Ok((StatusCode::OK, Value::Object(map))) } pub async fn write(req: Request) -> Result> { do_response!(inner_write(req).await) } async fn inner_write(req: Request) -> XResult<(StatusCode, Value)> { let whole_body = hyper::body::aggregate(req).await?; let named_value: NamedValue = serde_json::from_reader(whole_body.reader())?; let name = &named_value.name; if name.is_empty() { return simple_error!("Key name cannot be empty"); } let db_key_name = db::make_db_key_name(name); let force_write = named_value.force_write.unwrap_or(false); let conn = open_local_db()?; let db_key = db::find_key(&conn, &db_key_name)?; if db_key.is_some() && !force_write { return simple_error!("Key '{}' already exists", name); } let value = named_value.value.to_bytes()?; let key = match get_master_key() { None => return Ok((StatusCode::BAD_REQUEST, json!({ "error": "status_not_ready" }))), Some(key) => key, }; let encrypt_value = jose::serialize_jwe_aes(&value, &*key.read())?; drop(key); let new_db_key = Key { name: db_key_name, encrypted_key: encrypt_value.clone(), }; if db_key.is_some() { db::update_key(&conn, &new_db_key)?; } else { db::insert_key(&conn, &new_db_key)?; } let response_body = if let Some(db_key) = db_key { json!({ "name": name.to_string(), "override": true, "encrypted_value": encrypt_value, "previous_encrypted_value": db_key.encrypted_key, }) } else { json!({ "name": name.to_string(), "override": false, "encrypted_value": encrypt_value, }) }; Ok((StatusCode::OK, response_body)) }