tap_msg/message/
authorize.rs

1//! Authorize message type for the Transaction Authorization Protocol.
2//!
3//! This module defines the Authorize message type, which is used
4//! for authorizing transactions in the TAP protocol.
5
6use chrono::Utc;
7use serde::{Deserialize, Serialize};
8
9use crate::didcomm::PlainMessage;
10use crate::error::{Error, Result};
11use crate::impl_tap_message;
12use crate::message::tap_message_trait::TapMessageBody;
13
14/// Authorize message body (TAIP-4).
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct Authorize {
17    /// ID of the transaction being authorized.
18    pub transaction_id: String,
19
20    /// Optional note.
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub note: Option<String>,
23}
24
25impl Authorize {
26    /// Create a new Authorize message
27    pub fn new(transaction_id: &str) -> Self {
28        Self {
29            transaction_id: transaction_id.to_string(),
30            note: None,
31        }
32    }
33
34    /// Create a new Authorize message with a note
35    pub fn with_note(transaction_id: &str, note: &str) -> Self {
36        Self {
37            transaction_id: transaction_id.to_string(),
38            note: Some(note.to_string()),
39        }
40    }
41}
42
43impl TapMessageBody for Authorize {
44    fn message_type() -> &'static str {
45        "https://tap.rsvp/schema/1.0#authorize"
46    }
47
48    fn validate(&self) -> Result<()> {
49        if self.transaction_id.is_empty() {
50            return Err(Error::Validation(
51                "Transaction ID is required in Authorize".to_string(),
52            ));
53        }
54
55        Ok(())
56    }
57
58    fn to_didcomm(&self, from_did: &str) -> Result<PlainMessage> {
59        // Create a JSON representation of self with explicit type field
60        let mut body_json =
61            serde_json::to_value(self).map_err(|e| Error::SerializationError(e.to_string()))?;
62
63        // Ensure the @type field is correctly set in the body
64        if let Some(body_obj) = body_json.as_object_mut() {
65            // Add or update the @type field with the message type
66            body_obj.insert(
67                "@type".to_string(),
68                serde_json::Value::String(Self::message_type().to_string()),
69            );
70        }
71
72        // Create a new message with a random ID
73        let id = uuid::Uuid::new_v4().to_string();
74        let created_time = Utc::now().timestamp() as u64;
75
76        // Create the message
77        let message = PlainMessage {
78            id,
79            typ: "application/didcomm-plain+json".to_string(),
80            type_: Self::message_type().to_string(),
81            from: from_did.to_string(),
82            to: Vec::new(), // Empty recipients, will be determined by the framework later
83            thid: Some(self.transaction_id.clone()),
84            pthid: None,
85            created_time: Some(created_time),
86            expires_time: None,
87            extra_headers: std::collections::HashMap::new(),
88            from_prior: None,
89            body: body_json,
90            attachments: None,
91        };
92
93        Ok(message)
94    }
95}
96
97impl_tap_message!(Authorize);