use base64::{engine::general_purpose, Engine as _};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ResponseError {
#[error("decrypting response to plain text failed.")]
DecryptingResponseFailed,
#[error("the remote server is not implemented correctly.")]
ResponseImplementationError,
#[error("the server did not return a response.")]
ResponseMissing,
}
#[derive(Debug, Clone)]
pub struct Response {
pub status: reqwest::StatusCode,
pub headers: reqwest::header::HeaderMap,
pub body: Option<String>,
pub pk: Option<Vec<u8>>,
pub sk: Option<Vec<u8>>,
}
impl Response {
pub async fn new(response: reqwest::Response, sk: Vec<u8>) -> Result<Self, ResponseError> {
let mut r = Self {
status: response.status(),
headers: response.headers().to_owned(),
body: None,
pk: None,
sk: None,
};
match response.text().await {
Ok(body) => {
match r.headers.get("Content-Type") {
Some(h) => match h.to_str() {
Ok(crate::shared::NCRYPTF_CONTENT_TYPE) => {
if body.is_empty() {
r.body = None;
return Ok(r);
}
let body_bytes = general_purpose::STANDARD.decode(body).unwrap();
let ncryptf_response = crate::Response::from(sk.clone()).unwrap();
match ncryptf_response.decrypt(body_bytes.clone(), None, None) {
Ok(message) => {
let pk = crate::Response::get_public_key_from_response(
body_bytes.clone(),
)
.unwrap();
let sk = crate::Response::get_signing_public_key_from_response(
body_bytes.clone(),
)
.unwrap();
r.body = Some(message);
r.pk = Some(pk);
r.sk = Some(sk);
return Ok(r);
}
Err(_error) => return Err(ResponseError::DecryptingResponseFailed),
}
}
_ => {
if body.is_empty() {
r.body = None
} else {
r.body = Some(body)
}
return Ok(r);
}
},
_ => return Err(ResponseError::ResponseImplementationError),
}
}
Err(_error) => return Err(ResponseError::ResponseMissing),
}
}
pub fn into<T: for<'a> serde::Deserialize<'a>>(self) -> Result<T, serde_json::Error> {
return serde_json::from_str::<T>(&self.body.unwrap());
}
}