1use base64::URL_SAFE_NO_PAD;
2use serde::Deserialize;
3use std::convert::TryFrom;
4
5use crate::event::receipt::Receipt;
6use crate::event::sections::seal::{EventSeal, SourceSeal};
7use crate::event::EventMessage;
8use crate::event_message::key_event_message::KeyEvent;
9use crate::event_message::signed_event_message::{
10 Message, SignedEventMessage, SignedNontransferableReceipt, SignedTransferableReceipt,
11};
12use crate::event_parsing::payload_size::PayloadType;
13use crate::prefix::{
14 AttachedSignaturePrefix, BasicPrefix, IdentifierPrefix, Prefix, SelfSigningPrefix,
15};
16
17#[cfg(feature = "query")]
18use crate::query::{
19 query::QueryEvent,
20 reply::{ReplyEvent, SignedReply},
21};
22use crate::{error::Error, event::event_data::EventData};
23
24pub mod attachment;
25pub mod message;
26pub mod payload_size;
27pub mod prefix;
28
29#[derive(Debug, Clone, Deserialize, PartialEq)]
30pub enum Attachment {
31 SealSourceCouplets(Vec<SourceSeal>),
33 AttachedSignatures(Vec<AttachedSignaturePrefix>),
34 ReceiptCouplets(Vec<(BasicPrefix, SelfSigningPrefix)>),
35 SealSignaturesGroups(Vec<(EventSeal, Vec<AttachedSignaturePrefix>)>),
37 LastEstSignaturesGroups(Vec<(IdentifierPrefix, Vec<AttachedSignaturePrefix>)>),
39 Frame(Vec<Attachment>),
41}
42
43impl Attachment {
44 pub fn to_cesr(&self) -> String {
45 let (payload_type, att_len, serialized_attachment) = match self {
46 Attachment::SealSourceCouplets(sources) => {
47 let serialzied_sources = sources.iter().fold("".into(), |acc, s| {
48 [acc, Self::pack_sn(s.sn), s.digest.to_str()].join("")
49 });
50
51 (PayloadType::MG, sources.len(), serialzied_sources)
52 }
53 Attachment::SealSignaturesGroups(seals_signatures) => {
54 let serialized_seals =
55 seals_signatures
56 .iter()
57 .fold("".into(), |acc, (seal, sigs)| {
58 [
59 acc,
60 seal.prefix.to_str(),
61 Self::pack_sn(seal.sn),
62 seal.event_digest.to_str(),
63 Attachment::AttachedSignatures(sigs.to_vec()).to_cesr(),
64 ]
65 .join("")
66 });
67 (PayloadType::MF, seals_signatures.len(), serialized_seals)
68 }
69 Attachment::AttachedSignatures(sigs) => {
70 let serialized_sigs = sigs
71 .iter()
72 .fold("".into(), |acc, sig| [acc, sig.to_str()].join(""));
73 (PayloadType::MA, sigs.len(), serialized_sigs)
74 }
75 Attachment::ReceiptCouplets(couplets) => {
76 let packed_couplets = couplets.iter().fold("".into(), |acc, (bp, sp)| {
77 [acc, bp.to_str(), sp.to_str()].join("")
78 });
79
80 (PayloadType::MC, couplets.len(), packed_couplets)
81 }
82 Attachment::LastEstSignaturesGroups(signers) => {
83 let packed_signers = signers.iter().fold("".to_string(), |acc, (signer, sigs)| {
84 [
85 acc,
86 signer.to_str(),
87 Attachment::AttachedSignatures(sigs.clone()).to_cesr(),
88 ]
89 .concat()
90 });
91 (PayloadType::MH, signers.len(), packed_signers)
92 }
93 Attachment::Frame(att) => {
94 let packed_attachments = att
95 .iter()
96 .fold("".to_string(), |acc, att| [acc, att.to_cesr()].concat());
97 (
98 PayloadType::MV,
99 packed_attachments.len(),
100 packed_attachments,
101 )
102 }
103 };
104 [
105 payload_type.adjust_with_num(att_len as u16),
106 serialized_attachment,
107 ]
108 .join("")
109 }
110
111 fn pack_sn(sn: u64) -> String {
112 let payload_type = PayloadType::OA;
113 let sn_raw: Vec<u8> = sn.to_be_bytes().into();
114 let missing_zeros =
117 payload_type.size() / 4 * 3 - payload_type.master_code_size(false) - sn_raw.len();
118 let sn_vec: Vec<u8> = std::iter::repeat(0)
119 .take(missing_zeros)
120 .chain(sn_raw)
121 .collect();
122 [
123 payload_type.to_string(),
124 base64::encode_config(sn_vec, URL_SAFE_NO_PAD),
125 ]
126 .join("")
127 }
128}
129
130#[derive(Clone, Debug, PartialEq)]
131pub struct SignedEventData {
132 pub deserialized_event: EventType,
133 pub attachments: Vec<Attachment>,
134}
135
136#[derive(Clone, Debug, PartialEq)]
137pub enum EventType {
138 KeyEvent(Box<EventMessage<KeyEvent>>),
139 Receipt(EventMessage<Receipt>),
140 #[cfg(feature = "query")]
141 Qry(EventMessage<QueryEvent>),
142 #[cfg(feature = "query")]
143 Rpy(EventMessage<ReplyEvent>),
144}
145
146impl EventType {
147 pub fn serialize(&self) -> Result<Vec<u8>, Error> {
148 match self {
149 EventType::KeyEvent(event) => event.serialize(),
150 EventType::Receipt(rcp) => rcp.serialize(),
151 #[cfg(feature = "query")]
152 EventType::Qry(qry) => qry.serialize(),
153 #[cfg(feature = "query")]
154 EventType::Rpy(rpy) => rpy.serialize(),
155 }
156 }
157}
158
159impl SignedEventData {
160 pub fn to_cesr(&self) -> Result<Vec<u8>, Error> {
161 let attachments = self
162 .attachments
163 .iter()
164 .fold(String::default(), |acc, att| [acc, att.to_cesr()].concat())
165 .as_bytes()
166 .to_vec();
167 Ok([self.deserialized_event.serialize()?, attachments].concat())
168 }
169}
170
171impl From<&SignedEventMessage> for SignedEventData {
172 fn from(ev: &SignedEventMessage) -> Self {
173 let attachments = match ev.delegator_seal.clone() {
174 Some(delegator_seal) => [
175 Attachment::SealSourceCouplets(vec![delegator_seal]),
176 Attachment::AttachedSignatures(ev.signatures.clone()),
177 ]
178 .into(),
179 None => [Attachment::AttachedSignatures(ev.signatures.clone())].into(),
180 };
181
182 SignedEventData {
183 deserialized_event: EventType::KeyEvent(Box::new(ev.event_message.clone())),
184 attachments,
185 }
186 }
187}
188
189impl From<SignedNontransferableReceipt> for SignedEventData {
190 fn from(rcp: SignedNontransferableReceipt) -> SignedEventData {
191 let attachments = [Attachment::ReceiptCouplets(rcp.couplets)].into();
192 SignedEventData {
193 deserialized_event: EventType::Receipt(rcp.body),
194 attachments,
195 }
196 }
197}
198
199impl From<SignedTransferableReceipt> for SignedEventData {
200 fn from(rcp: SignedTransferableReceipt) -> SignedEventData {
201 let attachments = [Attachment::SealSignaturesGroups(vec![(
202 rcp.validator_seal,
203 rcp.signatures,
204 )])]
205 .into();
206 SignedEventData {
207 deserialized_event: EventType::Receipt(rcp.body),
208 attachments,
209 }
210 }
211}
212
213#[cfg(feature = "query")]
214impl From<SignedReply> for SignedEventData {
215 fn from(ev: SignedReply) -> Self {
216 use crate::event_message::signature::Signature;
217 let attachments = vec![match ev.signature.clone() {
218 Signature::Transferable(seal, sig) => {
219 Attachment::SealSignaturesGroups(vec![(seal, sig)])
220 }
221 Signature::NonTransferable(pref, sig) => Attachment::ReceiptCouplets(vec![(pref, sig)]),
222 }];
223
224 SignedEventData {
225 deserialized_event: EventType::Rpy(ev.reply),
226 attachments,
227 }
228 }
229}
230
231impl TryFrom<SignedEventData> for Message {
232 type Error = Error;
233
234 fn try_from(value: SignedEventData) -> Result<Self, Self::Error> {
235 match value.deserialized_event {
236 EventType::KeyEvent(ev) => signed_key_event(*ev, value.attachments),
237 EventType::Receipt(rct) => signed_receipt(rct, value.attachments),
238 #[cfg(feature = "query")]
239 EventType::Qry(qry) => signed_query(qry, value.attachments),
240 #[cfg(feature = "query")]
241 EventType::Rpy(rpy) => signed_reply(rpy, value.attachments),
242 }
243 }
244}
245
246#[cfg(feature = "query")]
247fn signed_reply(
248 rpy: EventMessage<ReplyEvent>,
249 mut attachments: Vec<Attachment>,
250) -> Result<Message, Error> {
251 match attachments
252 .pop()
253 .ok_or_else(|| Error::SemanticError("Missing attachment".into()))?
254 {
255 Attachment::ReceiptCouplets(couplets) => {
256 let signer = couplets[0].0.clone();
257 let signature = couplets[0].1.clone();
258 Ok(Message::KeyStateNotice(SignedReply::new_nontrans(
259 rpy, signer, signature,
260 )))
261 }
262 Attachment::SealSignaturesGroups(data) => {
263 let (seal, sigs) = data
264 .last()
266 .ok_or_else(|| Error::SemanticError("More than one seal".into()))?
267 .to_owned();
268 Ok(Message::KeyStateNotice(SignedReply::new_trans(
269 rpy, seal, sigs,
270 )))
271 }
272 Attachment::Frame(atts) => signed_reply(rpy, atts),
273 _ => {
274 Err(Error::SemanticError("Improper payload type".into()))
276 }
277 }
278}
279
280#[cfg(feature = "query")]
281fn signed_query(
282 qry: EventMessage<QueryEvent>,
283 mut attachments: Vec<Attachment>,
284) -> Result<Message, Error> {
285 use crate::query::query::SignedQuery;
286
287 match attachments
288 .pop()
289 .ok_or_else(|| Error::SemanticError("Missing attachment".into()))?
290 {
291 Attachment::LastEstSignaturesGroups(groups) => {
292 let (signer, signatures) = groups[0].clone();
293 Ok(Message::Query(SignedQuery {
294 envelope: qry,
295 signer,
296 signatures,
297 }))
298 }
299 Attachment::Frame(atts) => signed_query(qry, atts),
300 _ => {
301 Err(Error::SemanticError(
303 "Improper attachments for query message".into(),
304 ))
305 }
306 }
307}
308
309fn signed_key_event(
310 event_message: EventMessage<KeyEvent>,
311 mut attachments: Vec<Attachment>,
312) -> Result<Message, Error> {
313 match event_message.event.get_event_data() {
314 EventData::Dip(_) | EventData::Drt(_) => {
315 let (att1, att2) = (
316 attachments
317 .pop()
318 .ok_or_else(|| Error::SemanticError("Missing attachment".into()))?,
319 attachments
320 .pop()
321 .ok_or_else(|| Error::SemanticError("Missing attachment".into()))?,
322 );
323
324 let (seals, sigs) = match (att1, att2) {
325 (Attachment::SealSourceCouplets(seals), Attachment::AttachedSignatures(sigs)) => {
326 Ok((seals, sigs))
327 }
328 (Attachment::AttachedSignatures(sigs), Attachment::SealSourceCouplets(seals)) => {
329 Ok((seals, sigs))
330 }
331 _ => {
332 Err(Error::SemanticError("Improper attachment type".into()))
334 }
335 }?;
336 let delegator_seal = match seals.len() {
337 0 => Err(Error::SemanticError("Missing delegator seal".into())),
338 1 => Ok(seals.first().cloned()),
339 _ => Err(Error::SemanticError("Too many seals".into())),
340 };
341
342 Ok(Message::Event(Box::new(SignedEventMessage::new(
343 &event_message,
344 sigs,
345 delegator_seal?,
346 ))))
347 }
348 _ => {
349 let sigs = attachments
350 .first()
351 .cloned()
352 .ok_or_else(|| Error::SemanticError("Missing attachment".into()))?;
353 if let Attachment::AttachedSignatures(sigs) = sigs {
354 Ok(Message::Event(Box::new(SignedEventMessage::new(
355 &event_message,
356 sigs.to_vec(),
357 None,
358 ))))
359 } else {
360 Err(Error::SemanticError("Improper attachment type".into()))
362 }
363 }
364 }
365}
366
367fn signed_receipt(
368 event_message: EventMessage<Receipt>,
369 mut attachments: Vec<Attachment>,
370) -> Result<Message, Error> {
371 let att = attachments
372 .pop()
373 .ok_or_else(|| Error::SemanticError("Missing attachment".into()))?;
374 match att {
375 Attachment::ReceiptCouplets(couplets) => {
377 Ok(Message::NontransferableRct(SignedNontransferableReceipt {
378 body: event_message,
379 couplets,
380 }))
381 }
382 Attachment::SealSignaturesGroups(data) => {
383 let (seal, sigs) = data
385 .last()
387 .ok_or_else(|| Error::SemanticError("More than one seal".into()))?
388 .to_owned();
389 Ok(Message::TransferableRct(Box::new(
390 SignedTransferableReceipt::new(event_message, seal, sigs),
391 )))
392 }
393 Attachment::Frame(atts) => signed_receipt(event_message, atts),
394 _ => {
395 Err(Error::SemanticError("Improper payload type".into()))
397 }
398 }
399}
400
401#[test]
402fn test_stream1() {
403 use crate::event_parsing;
404 let stream = br#"{"v":"KERI10JSON000120_","t":"icp","d":"EG4EuTsxPiRM7soX10XXzNsS1KqXKUp8xsQ-kW_tWHoI","i":"DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","s":"0","kt":"1","k":["DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA"],"n":"EPYuj8mq_PYYsoBKkzX1kxSPGYBWaIya3slgCOyOtlqU","bt":"0","b":[],"c":[],"a":[]}-AABAA0aSisI4ZZTH_6JCqsvAsEpuf_Jq6bDbvPWj_eCDnAGbSARqYHipNs-9W7MHnwnMfIXwLpcoJkKGrQ-SiaklhAw"#;
406
407 let parsed = event_parsing::message::signed_message(stream).unwrap().1;
408 let msg = Message::try_from(parsed).unwrap();
409 assert!(matches!(msg, Message::Event(_)));
410
411 match msg {
412 Message::Event(signed_event) => {
413 assert_eq!(
414 signed_event.event_message.serialize().unwrap().len(),
415 signed_event.event_message.serialization_info.size
416 );
417
418 let serialized_again = signed_event.serialize();
419 assert!(serialized_again.is_ok());
420 let stringified = String::from_utf8(serialized_again.unwrap()).unwrap();
421 assert_eq!(stream, stringified.as_bytes())
422 }
423 _ => panic!(),
424 }
425}
426
427#[test]
428fn test_stream2() {
429 use crate::event_parsing;
430 let stream = br#"{"v":"KERI10JSON00017e_","t":"icp","d":"ELYk-z-SuTIeDncLr6GhwVUKnv3n3F1bF18qkXNd2bpk","i":"ELYk-z-SuTIeDncLr6GhwVUKnv3n3F1bF18qkXNd2bpk","s":"0","kt":"2","k":["DSuhyBcPZEZLK-fcw5tzHn2N46wRCG_ZOoeKtWTOunRA","DVcuJOOJF1IE8svqEtrSuyQjGTd2HhfAkt9y2QkUtFJI","DT1iAhBWCkvChxNWsby2J0pJyxBIxbAtbLA0Ljx-Grh8"],"n":"E9izzBkXX76sqt0N-tfLzJeRqj0W56p4pDQ_ZqNCDpyw","bt":"0","b":[],"c":[],"a":[]}-AADAA39j08U7pcU66OPKsaPExhBuHsL5rO1Pjq5zMgt_X6jRbezevis6YBUg074ZNKAGdUwHLqvPX_kse4buuuSUpAQABphobpuQEZ6EhKLhBuwgJmIQu80ZUV1GhBL0Ht47Hsl1rJiMwE2yW7-yi8k3idw2ahlpgdd9ka9QOP9yQmMWGAQACM7yfK1b86p1H62gonh1C7MECDCFBkoH0NZRjHKAEHebvd2_LLz6cpCaqKWDhbM2Rq01f9pgyDTFNLJMxkC-fAQ"#;
432
433 let parsed = event_parsing::message::signed_message(stream).unwrap().1;
434 let msg = Message::try_from(parsed);
435 assert!(msg.is_ok());
436 assert!(matches!(msg, Ok(Message::Event(_))));
437
438 match msg.unwrap() {
439 Message::Event(signed_event) => {
440 assert_eq!(
441 signed_event.event_message.serialize().unwrap().len(),
442 signed_event.event_message.serialization_info.size
443 );
444
445 let serialized_again = signed_event.serialize();
446 assert!(serialized_again.is_ok());
447 let stringified = String::from_utf8(serialized_again.unwrap()).unwrap();
448 assert_eq!(stream, stringified.as_bytes())
449 }
450 _ => panic!(),
451 }
452}
453
454#[test]
455fn test_deserialize_signed_receipt() {
456 use crate::event_parsing::message::signed_message;
457 let trans_receipt_event = br#"{"v":"KERI10JSON000091_","t":"rct","d":"EsZuhYAPBDnexP3SOl9YsGvWBrYkjYcRjomUYmCcLAYY","i":"EsZuhYAPBDnexP3SOl9YsGvWBrYkjYcRjomUYmCcLAYY","s":"0"}-FABE7pB5IKuaYh3aIWKxtexyYFhpSjDNTEGSQuxeJbWiylg0AAAAAAAAAAAAAAAAAAAAAAAE7pB5IKuaYh3aIWKxtexyYFhpSjDNTEGSQuxeJbWiylg-AABAAlIts3z2kNyis9l0Pfu54HhVN_yZHEV7NWIVoSTzl5IABelbY8xi7VRyW42ZJvBaaFTGtiqwMOywloVNpG_ZHAQ"#;
459 let parsed_trans_receipt = signed_message(trans_receipt_event).unwrap().1;
460 let msg = Message::try_from(parsed_trans_receipt);
461 assert!(matches!(msg, Ok(Message::TransferableRct(_))));
462 assert!(msg.is_ok());
463
464 let nontrans_rcp = br#"{"v":"KERI10JSON000091_","t":"rct","d":"E77aKmmdHtYKuJeBOYWRHbi8C6dYqzG-ESfdvlUAptlo","i":"EHz9RXAr9JiJn-3wkBvsUo1Qq3hvMQPaITxzcfJND8NM","s":"2"}-CABB389hKezugU2LFKiFVbitoHAxXqJh6HQ8Rn9tH7fxd680Bpx_cu_UoMtD0ES-bS9Luh-b2A_AYmM3PmVNfgFrFXls4IE39-_D14dS46NEMqCf0vQmqDcQmhY-UOpgoyFS2Bw"#;
466 let parsed_nontrans_receipt = signed_message(nontrans_rcp).unwrap().1;
467 let msg = Message::try_from(parsed_nontrans_receipt);
468 assert!(msg.is_ok());
469 assert!(matches!(msg, Ok(Message::NontransferableRct(_))));
470
471 }