use crate::messaging::shim::{
DIDCommResponse, DIDCommServiceError, Extension, HandlerContext, ProblemReport,
ServiceProblemReport,
};
use affinidi_messaging_didcomm::Message;
use tracing::warn;
use crate::error::AppError;
use crate::server::AppState;
type HandlerResult = Result<Option<DIDCommResponse>, DIDCommServiceError>;
fn handler_err(e: impl std::fmt::Display) -> DIDCommServiceError {
DIDCommServiceError::Handler(e.to_string())
}
use trust_tasks_didcomm::ENVELOPE_TYPE as TRUST_TASK_ENVELOPE_TYPE;
pub async fn handle_trust_task(
_ctx: HandlerContext,
message: Message,
Extension(app_state): Extension<AppState>,
) -> HandlerResult {
let body = serde_json::to_vec(&message.body).map_err(handler_err)?;
let authenticated = match message.from.as_deref() {
Some(sender) => Ok(sender),
None => Err(AppError::Authentication(
"message has no sender (from)".into(),
)),
};
let response = match authenticated {
Ok(sender) => {
crate::trust_tasks::transport::with_binding(
"didcomm",
crate::trust_tasks::accept_from_proven_sender(
&app_state,
sender,
&body,
crate::trust_tasks::transport::TransportConfidentiality::EndToEnd,
),
)
.await
}
Err(e) => {
crate::trust_tasks::sign_response(
&app_state,
crate::trust_tasks::reject_trust_task(
&body,
trust_tasks_rs::RejectReason::PermissionDenied {
reason: e.to_string(),
},
),
)
.await
}
};
if response.body.is_empty() {
return Ok(None);
}
let doc: serde_json::Value = serde_json::from_slice(&response.body).map_err(handler_err)?;
Ok(Some(DIDCommResponse::new(TRUST_TASK_ENVELOPE_TYPE, doc)))
}
pub async fn handle_problem_report(_ctx: HandlerContext, message: Message) -> HandlerResult {
let code = message
.body
.get("code")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let comment = message
.body
.get("comment")
.and_then(|v| v.as_str())
.unwrap_or("no details provided");
let from = message.from.as_deref().unwrap_or("unknown");
let thid = message.thid.as_deref().unwrap_or("none");
warn!(from, code, comment, thid, msg_type = %message.typ, "received problem-report");
Ok(None)
}
pub async fn handle_unknown(_ctx: HandlerContext, message: Message) -> HandlerResult {
let from = message.from.as_deref().unwrap_or("unknown");
let thid = message.thid.as_deref().unwrap_or("none");
if message.typ.contains("problem-report") {
let code = message
.body
.get("code")
.and_then(|v| v.as_str())
.unwrap_or("unknown");
let comment = message
.body
.get("comment")
.and_then(|v| v.as_str())
.unwrap_or("no details provided");
warn!(
from,
code,
comment,
thid,
msg_type = %message.typ,
"received unhandled problem-report"
);
return Ok(None);
}
if let Some(comment) = trust_task_needs_envelope(&message.typ) {
warn!(
from,
msg_type = %message.typ,
"Trust Task arrived typed as its task URI, not in the DIDComm binding envelope — refused"
);
return Ok(Some(
DIDCommResponse::problem_report(ProblemReport::bad_request(comment))
.thid(message.id.clone()),
));
}
warn!(from, thid, msg_type = %message.typ, "unknown message type — ignoring");
Ok(Some(
DIDCommResponse::problem_report(ProblemReport::bad_request(format!(
"unsupported message type: {}",
message.typ
)))
.thid(message.id.clone()),
))
}
const TRUST_TASK_SPEC_PREFIX: &str = "https://trusttasks.org/spec/";
pub(crate) fn trust_task_needs_envelope(typ: &str) -> Option<String> {
typ.starts_with(TRUST_TASK_SPEC_PREFIX).then(|| {
format!(
"unsupported message type: {typ} — Trust Tasks must be carried in the DIDComm \
binding envelope `{TRUST_TASK_ENVELOPE_TYPE}` with the task document as the body"
)
})
}