trust-registry 0.20.0

Trust Registry
use std::sync::Arc;

use affinidi_tdk::{
    didcomm::Message,
    messaging::{ATM, profiles::ATMProfile},
};
use serde_json::Value;
use tracing::{error, info};

use crate::didcomm::{error::DIDCommError, new_message_id};

use super::problem_report::ProblemReport;

const PROBLEM_REPORT_TYPE: &str = "https://didcomm.org/report-problem/2.0/problem-report";

pub fn build_response(
    type_: String,
    from: String,
    to: String,
    body: Value,
    thid: Option<String>,
    pthid: Option<String>,
) -> Message {
    let mut builder = Message::build(new_message_id(), type_, body)
        .from(from)
        .to(to)
        .thid(thid.unwrap_or_else(new_message_id));

    if let Some(parent_id) = pthid {
        builder = builder.header("pthid".into(), Value::String(parent_id));
    }

    builder.finalize()
}

pub fn build_problem_report(
    from: String,
    to: String,
    report: ProblemReport,
    thid: Option<String>,
    pthid: Option<String>,
) -> Message {
    build_response(
        PROBLEM_REPORT_TYPE.to_string(),
        from,
        to,
        report.to_body(),
        thid,
        pthid,
    )
}

pub async fn send_response(
    atm: &Arc<ATM>,
    profile: &Arc<ATMProfile>,
    message_type: String,
    body: Value,
    recipient: &str,
    thid: Option<String>,
    pthid: Option<String>,
) -> Result<(), DIDCommError> {
    let response_message = build_response(
        message_type,
        profile.inner.did.clone(),
        recipient.to_string(),
        body,
        thid,
        pthid,
    );

    let message_id = response_message.id.clone();

    let packed_msg = atm
        .pack_encrypted(
            &response_message,
            recipient,
            Some(&profile.inner.did),
            Some(&profile.inner.did),
        )
        .await?;

    let sending_result = atm
        .forward_and_send_message(
            profile,
            false,
            &packed_msg.0,
            Some(&message_id),
            &profile
                .to_tdk_profile()
                .mediator
                .ok_or(DIDCommError::MissingMediator)?,
            recipient,
            None,
            None,
            false,
        )
        .await;

    if let Err(sending_error) = sending_result {
        error!(
            "[profile = {}] Failed to send response. Error: {:?}",
            &profile.inner.alias, sending_error
        );
        return Err(sending_error.into());
    }

    info!(
        "[profile = {}] Response sent successfully",
        &profile.inner.alias
    );
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_build_response() {
        let msg = build_response(
            "https://example.com/test".to_string(),
            "did:example:alice".to_string(),
            "did:example:bob".to_string(),
            serde_json::json!({"result": "ok"}),
            Some("thread-123".to_string()),
            Some("parent-456".to_string()),
        );

        assert_eq!(msg.typ, "https://example.com/test");
        assert_eq!(msg.from.as_ref().unwrap(), "did:example:alice");
        assert_eq!(msg.to.as_ref().unwrap()[0], "did:example:bob");
        assert_eq!(msg.thid.as_ref().unwrap(), "thread-123");
    }
    #[test]
    fn test_build_problem_report() {
        let report = ProblemReport::unauthorized("Invalid DID");
        let msg = build_problem_report(
            "did:example:alice".to_string(),
            "did:example:bob".to_string(),
            report,
            Some("thread-123".to_string()),
            Some("parent-456".to_string()),
        );
        assert_eq!(msg.typ, PROBLEM_REPORT_TYPE);
        assert_eq!(msg.from.as_ref().unwrap(), "did:example:alice");
        assert_eq!(msg.to.as_ref().unwrap()[0], "did:example:bob");
        assert_eq!(msg.thid.as_ref().unwrap(), "thread-123");
    }
}