use axum::{
Json,
body::Bytes,
extract::State,
http::StatusCode,
response::{IntoResponse, Response},
};
use serde_json::Value;
use trust_tasks_https::{HttpsHandler, status_for_code};
use trust_tasks_rs::{ErrorResponse, RejectReason, TransportHandler, TrustTask};
use uuid::Uuid;
use crate::SharedData;
use crate::embed::with_reply_signer;
use crate::storage::repository::TrustRecordRepository;
use crate::trust_tasks::TaskHandler;
fn new_id() -> String {
Uuid::new_v4().to_string()
}
fn error_response(err: ErrorResponse) -> Response {
let status =
StatusCode::from_u16(status_for_code(&err.payload.code)).unwrap_or(StatusCode::BAD_REQUEST);
let body = serde_json::to_value(&err).unwrap_or_else(|_| serde_json::json!({}));
(status, Json(body)).into_response()
}
pub async fn handle_trust_task<R>(State(state): State<SharedData<R>>, body: Bytes) -> Response
where
R: TrustRecordRepository + Send + ?Sized + 'static,
{
let my_vid = state.config.didcomm_config.profile_config.did.clone();
let doc: TrustTask<Value> = match serde_json::from_slice(&body) {
Ok(doc) => doc,
Err(e) => {
return (
StatusCode::BAD_REQUEST,
Json(serde_json::json!({
"code": "malformedRequest",
"message": format!("invalid Trust Task document: {e}"),
})),
)
.into_response();
}
};
let tasks = with_reply_signer(
TaskHandler::new(
state.query_dispatcher.clone(),
my_vid.clone(),
Vec::new(),
state.verifier.clone(),
)
.with_audit(state.audit.clone()),
&state.config,
);
let transport = HttpsHandler::new(Some(my_vid), None);
if let Err(consistency) = transport.resolve_parties(&doc) {
let rejection = doc.reject_with(new_id(), RejectReason::from(consistency));
return error_response(tasks.seal_reply(rejection).await);
}
match tasks.handle(doc, None).await {
Ok(response) => {
let body = serde_json::to_value(&response).unwrap_or_else(|_| serde_json::json!({}));
(StatusCode::OK, Json(body)).into_response()
}
Err(err) => error_response(err),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn error_for(reason: RejectReason) -> ErrorResponse {
let doc: TrustTask<Value> = TrustTask::new(
"req-1",
"https://trusttasks.org/spec/registry/recognition/0.1"
.parse()
.expect("valid type uri"),
serde_json::json!({}),
);
doc.reject_with(new_id(), reason)
}
#[test]
fn malformed_request_maps_to_400() {
let resp = error_response(error_for(RejectReason::MalformedRequest {
reason: "bad".into(),
}));
assert_eq!(resp.status(), StatusCode::BAD_REQUEST);
}
#[test]
fn unsupported_type_maps_to_client_error() {
let resp = error_response(error_for(RejectReason::UnsupportedType {
type_uri: "https://trusttasks.org/spec/registry/nope/0.1".into(),
}));
assert!(resp.status().is_client_error());
}
}