1use crate::didcomm::PlainMessage;
7use crate::error::{Error, Result};
8use crate::message::{
9 AddAgents, AuthorizationRequired, Authorize, BasicMessage, Cancel, ConfirmRelationship,
10 Connect, DIDCommPresentation, ErrorBody, OutOfBand, Payment, Presentation, Reject, RemoveAgent,
11 ReplaceAgent, RequestPresentation, Revert, Settle, Transfer, TrustPing, TrustPingResponse,
12 UpdateParty, UpdatePolicies,
13};
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, Serialize, Deserialize)]
18#[serde(untagged)]
19#[allow(clippy::large_enum_variant)]
20pub enum TapMessage {
21 AddAgents(AddAgents),
23 Authorize(Authorize),
25 AuthorizationRequired(AuthorizationRequired),
27 BasicMessage(BasicMessage),
29 Cancel(Cancel),
31 ConfirmRelationship(ConfirmRelationship),
33 Connect(Connect),
35 DIDCommPresentation(DIDCommPresentation),
37 Error(ErrorBody),
39 OutOfBand(OutOfBand),
41 Payment(Payment),
43 Presentation(Presentation),
45 Reject(Reject),
47 RemoveAgent(RemoveAgent),
49 ReplaceAgent(ReplaceAgent),
51 RequestPresentation(RequestPresentation),
53 Revert(Revert),
55 Settle(Settle),
57 Transfer(Transfer),
59 TrustPing(TrustPing),
61 TrustPingResponse(TrustPingResponse),
63 UpdateParty(UpdateParty),
65 UpdatePolicies(UpdatePolicies),
67}
68
69impl TapMessage {
70 pub fn from_plain_message(plain_msg: &PlainMessage) -> Result<Self> {
73 let message_type =
75 if !plain_msg.type_.is_empty() && plain_msg.type_ != "application/didcomm-plain+json" {
76 &plain_msg.type_
77 } else if let Some(body_obj) = plain_msg.body.as_object() {
78 if let Some(type_val) = body_obj.get("@type") {
79 type_val.as_str().unwrap_or("")
80 } else {
81 ""
82 }
83 } else {
84 ""
85 };
86
87 if message_type.is_empty() {
88 return Err(Error::Validation(
89 "Message type not found in PlainMessage".to_string(),
90 ));
91 }
92
93 match message_type {
95 "https://tap.rsvp/schema/1.0#AddAgents" => {
96 let msg: AddAgents =
97 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
98 Error::SerializationError(format!("Failed to parse AddAgents: {}", e))
99 })?;
100 Ok(TapMessage::AddAgents(msg))
101 }
102 "https://tap.rsvp/schema/1.0#Authorize" => {
103 let msg: Authorize =
104 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
105 Error::SerializationError(format!("Failed to parse Authorize: {}", e))
106 })?;
107 Ok(TapMessage::Authorize(msg))
108 }
109 "https://tap.rsvp/schema/1.0#AuthorizationRequired" => {
110 let msg: AuthorizationRequired = serde_json::from_value(plain_msg.body.clone())
111 .map_err(|e| {
112 Error::SerializationError(format!(
113 "Failed to parse AuthorizationRequired: {}",
114 e
115 ))
116 })?;
117 Ok(TapMessage::AuthorizationRequired(msg))
118 }
119 "https://didcomm.org/basicmessage/2.0/message" => {
120 let msg: BasicMessage =
121 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
122 Error::SerializationError(format!("Failed to parse BasicMessage: {}", e))
123 })?;
124 Ok(TapMessage::BasicMessage(msg))
125 }
126 "https://tap.rsvp/schema/1.0#Cancel" => {
127 let msg: Cancel = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
128 Error::SerializationError(format!("Failed to parse Cancel: {}", e))
129 })?;
130 Ok(TapMessage::Cancel(msg))
131 }
132 "https://tap.rsvp/schema/1.0#ConfirmRelationship" => {
133 let msg: ConfirmRelationship = serde_json::from_value(plain_msg.body.clone())
134 .map_err(|e| {
135 Error::SerializationError(format!(
136 "Failed to parse ConfirmRelationship: {}",
137 e
138 ))
139 })?;
140 Ok(TapMessage::ConfirmRelationship(msg))
141 }
142 "https://tap.rsvp/schema/1.0#Connect" => {
143 let msg: Connect = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
144 Error::SerializationError(format!("Failed to parse Connect: {}", e))
145 })?;
146 Ok(TapMessage::Connect(msg))
147 }
148 "https://didcomm.org/present-proof/3.0/presentation" => {
149 let msg: DIDCommPresentation = serde_json::from_value(plain_msg.body.clone())
150 .map_err(|e| {
151 Error::SerializationError(format!(
152 "Failed to parse DIDCommPresentation: {}",
153 e
154 ))
155 })?;
156 Ok(TapMessage::DIDCommPresentation(msg))
157 }
158 "https://tap.rsvp/schema/1.0#Error" => {
159 let msg: ErrorBody =
160 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
161 Error::SerializationError(format!("Failed to parse Error: {}", e))
162 })?;
163 Ok(TapMessage::Error(msg))
164 }
165 "https://tap.rsvp/schema/1.0#OutOfBand" => {
166 let msg: OutOfBand =
167 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
168 Error::SerializationError(format!("Failed to parse OutOfBand: {}", e))
169 })?;
170 Ok(TapMessage::OutOfBand(msg))
171 }
172 "https://tap.rsvp/schema/1.0#Payment" => {
173 let msg: Payment = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
174 Error::SerializationError(format!("Failed to parse Payment: {}", e))
175 })?;
176 Ok(TapMessage::Payment(msg))
177 }
178 "https://tap.rsvp/schema/1.0#Presentation" => {
179 let msg: Presentation =
180 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
181 Error::SerializationError(format!("Failed to parse Presentation: {}", e))
182 })?;
183 Ok(TapMessage::Presentation(msg))
184 }
185 "https://tap.rsvp/schema/1.0#Reject" => {
186 let msg: Reject = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
187 Error::SerializationError(format!("Failed to parse Reject: {}", e))
188 })?;
189 Ok(TapMessage::Reject(msg))
190 }
191 "https://tap.rsvp/schema/1.0#RemoveAgent" => {
192 let msg: RemoveAgent =
193 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
194 Error::SerializationError(format!("Failed to parse RemoveAgent: {}", e))
195 })?;
196 Ok(TapMessage::RemoveAgent(msg))
197 }
198 "https://tap.rsvp/schema/1.0#ReplaceAgent" => {
199 let msg: ReplaceAgent =
200 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
201 Error::SerializationError(format!("Failed to parse ReplaceAgent: {}", e))
202 })?;
203 Ok(TapMessage::ReplaceAgent(msg))
204 }
205 "https://tap.rsvp/schema/1.0#RequestPresentation" => {
206 let msg: RequestPresentation = serde_json::from_value(plain_msg.body.clone())
207 .map_err(|e| {
208 Error::SerializationError(format!(
209 "Failed to parse RequestPresentation: {}",
210 e
211 ))
212 })?;
213 Ok(TapMessage::RequestPresentation(msg))
214 }
215 "https://tap.rsvp/schema/1.0#Revert" => {
216 let msg: Revert = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
217 Error::SerializationError(format!("Failed to parse Revert: {}", e))
218 })?;
219 Ok(TapMessage::Revert(msg))
220 }
221 "https://tap.rsvp/schema/1.0#Settle" => {
222 let msg: Settle = serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
223 Error::SerializationError(format!("Failed to parse Settle: {}", e))
224 })?;
225 Ok(TapMessage::Settle(msg))
226 }
227 "https://tap.rsvp/schema/1.0#Transfer" => {
228 let msg: Transfer =
229 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
230 Error::SerializationError(format!("Failed to parse Transfer: {}", e))
231 })?;
232 Ok(TapMessage::Transfer(msg))
233 }
234 "https://tap.rsvp/schema/1.0#UpdateParty" => {
235 let msg: UpdateParty =
236 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
237 Error::SerializationError(format!("Failed to parse UpdateParty: {}", e))
238 })?;
239 Ok(TapMessage::UpdateParty(msg))
240 }
241 "https://tap.rsvp/schema/1.0#UpdatePolicies" => {
242 let msg: UpdatePolicies =
243 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
244 Error::SerializationError(format!("Failed to parse UpdatePolicies: {}", e))
245 })?;
246 Ok(TapMessage::UpdatePolicies(msg))
247 }
248 "https://didcomm.org/trust-ping/2.0/ping" => {
249 let msg: TrustPing =
250 serde_json::from_value(plain_msg.body.clone()).map_err(|e| {
251 Error::SerializationError(format!("Failed to parse TrustPing: {}", e))
252 })?;
253 Ok(TapMessage::TrustPing(msg))
254 }
255 "https://didcomm.org/trust-ping/2.0/ping-response" => {
256 let msg: TrustPingResponse = serde_json::from_value(plain_msg.body.clone())
257 .map_err(|e| {
258 Error::SerializationError(format!(
259 "Failed to parse TrustPingResponse: {}",
260 e
261 ))
262 })?;
263 Ok(TapMessage::TrustPingResponse(msg))
264 }
265 _ => Err(Error::Validation(format!(
266 "Unknown message type: {}",
267 message_type
268 ))),
269 }
270 }
271
272 pub fn message_type(&self) -> &'static str {
274 match self {
275 TapMessage::AddAgents(_) => "https://tap.rsvp/schema/1.0#AddAgents",
276 TapMessage::Authorize(_) => "https://tap.rsvp/schema/1.0#Authorize",
277 TapMessage::AuthorizationRequired(_) => {
278 "https://tap.rsvp/schema/1.0#AuthorizationRequired"
279 }
280 TapMessage::BasicMessage(_) => "https://didcomm.org/basicmessage/2.0/message",
281 TapMessage::Cancel(_) => "https://tap.rsvp/schema/1.0#Cancel",
282 TapMessage::ConfirmRelationship(_) => "https://tap.rsvp/schema/1.0#ConfirmRelationship",
283 TapMessage::Connect(_) => "https://tap.rsvp/schema/1.0#Connect",
284 TapMessage::DIDCommPresentation(_) => {
285 "https://didcomm.org/present-proof/3.0/presentation"
286 }
287 TapMessage::Error(_) => "https://tap.rsvp/schema/1.0#Error",
288 TapMessage::OutOfBand(_) => "https://tap.rsvp/schema/1.0#OutOfBand",
289 TapMessage::Payment(_) => "https://tap.rsvp/schema/1.0#Payment",
290 TapMessage::Presentation(_) => "https://tap.rsvp/schema/1.0#Presentation",
291 TapMessage::Reject(_) => "https://tap.rsvp/schema/1.0#Reject",
292 TapMessage::RemoveAgent(_) => "https://tap.rsvp/schema/1.0#RemoveAgent",
293 TapMessage::ReplaceAgent(_) => "https://tap.rsvp/schema/1.0#ReplaceAgent",
294 TapMessage::RequestPresentation(_) => "https://tap.rsvp/schema/1.0#RequestPresentation",
295 TapMessage::Revert(_) => "https://tap.rsvp/schema/1.0#Revert",
296 TapMessage::Settle(_) => "https://tap.rsvp/schema/1.0#Settle",
297 TapMessage::Transfer(_) => "https://tap.rsvp/schema/1.0#Transfer",
298 TapMessage::TrustPing(_) => "https://didcomm.org/trust-ping/2.0/ping",
299 TapMessage::TrustPingResponse(_) => "https://didcomm.org/trust-ping/2.0/ping-response",
300 TapMessage::UpdateParty(_) => "https://tap.rsvp/schema/1.0#UpdateParty",
301 TapMessage::UpdatePolicies(_) => "https://tap.rsvp/schema/1.0#UpdatePolicies",
302 }
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309 use serde_json::json;
310
311 #[test]
312 fn test_parse_transfer_body() {
313 let body = json!({
314 "@type": "https://tap.rsvp/schema/1.0#Transfer",
315 "transaction_id": "test-tx-123",
316 "asset": "eip155:1/slip44:60",
317 "originator": {
318 "@id": "did:example:alice"
319 },
320 "amount": "100",
321 "agents": [],
322 "metadata": {}
323 });
324
325 match serde_json::from_value::<Transfer>(body.clone()) {
326 Ok(transfer) => {
327 println!("Successfully parsed Transfer: {:?}", transfer);
328 assert_eq!(transfer.amount, "100");
329 }
330 Err(e) => {
331 panic!("Failed to parse Transfer: {}", e);
332 }
333 }
334 }
335
336 #[test]
337 fn test_from_plain_message_transfer() {
338 let plain_msg = PlainMessage {
339 id: "test-123".to_string(),
340 typ: "application/didcomm-plain+json".to_string(),
341 type_: "https://tap.rsvp/schema/1.0#Transfer".to_string(),
342 body: json!({
343 "@type": "https://tap.rsvp/schema/1.0#Transfer",
344 "transaction_id": "test-tx-456",
345 "asset": "eip155:1/slip44:60",
346 "originator": {
347 "@id": "did:example:alice"
348 },
349 "amount": "100",
350 "agents": [],
351 "metadata": {}
352 }),
353 from: "did:example:alice".to_string(),
354 to: vec!["did:example:bob".to_string()],
355 thid: None,
356 pthid: None,
357 created_time: Some(1234567890),
358 expires_time: None,
359 from_prior: None,
360 attachments: None,
361 extra_headers: Default::default(),
362 };
363
364 let tap_msg = TapMessage::from_plain_message(&plain_msg).unwrap();
365
366 match tap_msg {
367 TapMessage::Transfer(transfer) => {
368 assert_eq!(transfer.amount, "100");
369 assert_eq!(
370 transfer.originator.as_ref().unwrap().id,
371 "did:example:alice"
372 );
373 }
374 _ => panic!("Expected Transfer message"),
375 }
376 }
377
378 #[test]
379 fn test_message_type() {
380 let transfer = Transfer {
381 asset: "eip155:1/slip44:60".parse().unwrap(),
382 originator: Some(crate::message::Party::new("did:example:alice")),
383 beneficiary: None,
384 amount: "100".to_string(),
385 agents: vec![],
386 memo: None,
387 settlement_id: None,
388 connection_id: None,
389 transaction_id: Some("tx-123".to_string()),
390 metadata: Default::default(),
391 };
392
393 let tap_msg = TapMessage::Transfer(transfer);
394 assert_eq!(
395 tap_msg.message_type(),
396 "https://tap.rsvp/schema/1.0#Transfer"
397 );
398 }
399}