1use crate::error::Error;
2use rkyv::{
3 vec::ArchivedVec, AlignedVec, Archive, Archived, Deserialize as RkyvDeserialize,
4 Serialize as RkyvSerialize,
5};
6use secp256k1::{schnorr::Signature, Keypair, Message, XOnlyPublicKey, SECP256K1};
7use serde::{Deserialize, Serialize};
8use serde_json::{json, Value};
9use sha2::{Digest, Sha256};
10use std::{
11 fmt::Display,
12 str::FromStr,
13 time::{SystemTime, UNIX_EPOCH},
14};
15
16type Tags = Vec<(Vec<u8>, Vec<u8>)>;
17type BuildTags = (Tags, Option<u64>, Option<[u8; 32]>);
18#[derive(
19 Serialize,
20 Deserialize,
21 PartialEq,
22 Eq,
23 Debug,
24 Clone,
25 Default,
26 Archive,
27 RkyvDeserialize,
28 RkyvSerialize,
29)]
30pub struct EventIndex {
31 #[serde(with = "hex::serde")]
32 id: [u8; 32],
33
34 #[serde(with = "hex::serde")]
35 pubkey: [u8; 32],
36
37 created_at: u64,
38
39 kind: u16,
40
41 #[serde(skip)]
42 tags: Tags,
43
44 #[serde(skip)]
45 expiration: Option<u64>,
46
47 #[serde(skip)]
49 delegator: Option<[u8; 32]>,
50}
51
52impl EventIndex {
53 pub fn from_zeroes(bytes: &[u8]) -> Result<&ArchivedEventIndex, Error> {
54 let archived = unsafe { rkyv::archived_root::<Self>(bytes) };
55 Ok(archived)
56 }
57
58 pub fn from_bytes<B: AsRef<[u8]>>(bytes: B) -> Result<Self, Error> {
59 let bytes = bytes.as_ref();
60 let archived = unsafe { rkyv::archived_root::<Self>(bytes) };
61 let deserialized: Self = archived
62 .deserialize(&mut rkyv::Infallible)
63 .map_err(|e| Error::Deserialization(e.to_string()))?;
64 Ok(deserialized)
65 }
66
67 pub fn to_bytes(&self) -> Result<AlignedVec, Error> {
68 let vec =
69 rkyv::to_bytes::<_, 256>(self).map_err(|e| Error::Serialization(e.to_string()))?;
70 Ok(vec)
71 }
72
73 pub fn new(
74 id: [u8; 32],
75 pubkey: [u8; 32],
76 created_at: u64,
77 kind: u16,
78 tags: &Vec<Vec<String>>,
79 ) -> Result<Self, Error> {
80 let (tags, expiration, delegator) = Self::build_index_tags(tags)?;
81 Ok(Self {
82 id,
83 pubkey,
84 created_at,
85 kind,
86 tags,
87 expiration,
88 delegator,
89 })
90 }
91
92 pub fn build_index_tags(tags: &Vec<Vec<String>>) -> Result<BuildTags, Error> {
93 let mut t = vec![];
94 let mut expiration = None;
95 let mut delegator = None;
96
97 for tag in tags {
98 if tag.len() > 1 {
99 if tag[0] == "expiration" {
100 expiration = Some(
101 u64::from_str(&tag[1])
102 .map_err(|_| Error::Invalid("invalid expiration".to_string()))?,
103 );
104 } else if tag[0] == "delegation" {
105 let mut h = [0u8; 32];
106 hex::decode_to_slice(&tag[1], &mut h)?;
107 delegator = Some(h);
108 }
109
110 let key = tag[0].as_bytes().to_vec();
111 if key.len() == 1 && key[0] != 0 {
114 let v;
115 if tag[0] == "e" || tag[0] == "p" {
117 let h = hex::decode(&tag[1])?;
118 if h.len() != 32 {
119 return Err(Error::Invalid("invalid e or p tag value".to_string()));
120 }
121 v = h;
122 } else {
123 v = tag[1].as_bytes().to_vec();
124 if v.contains(&0) || v.len() > 255 {
128 continue;
129 }
130 };
131 t.push((key, v));
132 }
133 }
134 }
135 Ok((t, expiration, delegator))
136 }
137
138 pub fn id(&self) -> &[u8; 32] {
139 &self.id
140 }
141
142 pub fn pubkey(&self) -> &[u8; 32] {
143 &self.pubkey
144 }
145
146 pub fn created_at(&self) -> u64 {
147 self.created_at
148 }
149
150 pub fn kind(&self) -> u16 {
151 self.kind
152 }
153
154 pub fn tags(&self) -> &Vec<(Vec<u8>, Vec<u8>)> {
155 &self.tags
156 }
157
158 pub fn expiration(&self) -> Option<&u64> {
159 self.expiration.as_ref()
160 }
161
162 pub fn delegator(&self) -> Option<&[u8; 32]> {
163 self.delegator.as_ref()
164 }
165
166 pub fn is_ephemeral(&self) -> bool {
167 let kind = self.kind;
168 (20_000..30_000).contains(&kind)
169 }
170
171 pub fn is_expired(&self, now: u64) -> bool {
172 if let Some(exp) = self.expiration {
173 exp < now
174 } else {
175 false
176 }
177 }
178}
179
180impl ArchivedEventIndex {
181 pub fn id(&self) -> &Archived<[u8; 32]> {
182 &self.id
183 }
184 pub fn pubkey(&self) -> &Archived<[u8; 32]> {
185 &self.pubkey
186 }
187
188 pub fn created_at(&self) -> u64 {
189 self.created_at
190 }
191
192 pub fn kind(&self) -> u16 {
193 self.kind
194 }
195
196 pub fn tags(&self) -> &ArchivedVec<(ArchivedVec<u8>, ArchivedVec<u8>)> {
197 &self.tags
198 }
199
200 pub fn expiration(&self) -> Option<&u64> {
201 self.expiration.as_ref()
202 }
203
204 pub fn delegator(&self) -> Option<&Archived<[u8; 32]>> {
205 self.delegator.as_ref()
206 }
207
208 pub fn is_ephemeral(&self) -> bool {
209 let kind = self.kind;
210 (20_000..30_000).contains(&kind)
211 }
212
213 pub fn is_expired(&self, now: u64) -> bool {
214 if let Some(exp) = self.expiration.as_ref() {
215 exp < &now
216 } else {
217 false
218 }
219 }
220}
221#[derive(Deserialize)]
223struct _Event {
224 #[serde(with = "hex::serde")]
225 id: [u8; 32],
226 #[serde(with = "hex::serde")]
227 pubkey: [u8; 32],
228 created_at: u64,
229 kind: u16,
230 #[serde(default)]
231 tags: Vec<Vec<String>>,
232 #[serde(default)]
233 content: String,
234 #[serde(with = "hex::serde")]
235 sig: [u8; 64],
236 }
239
240#[derive(Serialize, Deserialize, Debug, Clone)]
243#[serde(try_from = "_Event")]
244pub struct Event {
245 #[serde(default)]
246 tags: Vec<Vec<String>>,
247
248 #[serde(default)]
249 content: String,
250
251 #[serde(with = "hex::serde")]
252 sig: [u8; 64],
253
254 #[serde(flatten)]
255 index: EventIndex,
256
257 #[serde(skip)]
258 pub words: Vec<Vec<u8>>,
259}
260
261impl TryFrom<_Event> for Event {
262 type Error = Error;
263
264 fn try_from(value: _Event) -> Result<Self, Self::Error> {
265 let event = Event {
266 content: value.content,
267 sig: value.sig,
268 index: EventIndex::new(
269 value.id,
270 value.pubkey,
271 value.created_at,
272 value.kind,
273 &value.tags,
274 )?,
275 tags: value.tags,
276 words: Default::default(),
277 };
278 Ok(event)
279 }
280}
281
282impl Event {
283 pub fn new(
284 id: [u8; 32],
285 pubkey: [u8; 32],
286 created_at: u64,
287 kind: u16,
288 tags: Vec<Vec<String>>,
289 content: String,
290 sig: [u8; 64],
291 ) -> Result<Self, Error> {
292 let index = EventIndex::new(id, pubkey, created_at, kind, &tags)?;
293 let event = Self {
294 tags,
295 content,
296 sig,
297 index,
298 words: Default::default(),
299 };
300 Ok(event)
301 }
302
303 pub fn create(
304 key_pair: &Keypair,
305 created_at: u64,
306 kind: u16,
307 tags: Vec<Vec<String>>,
308 content: String,
309 ) -> Result<Self, Error> {
310 let pubkey = XOnlyPublicKey::from_keypair(key_pair).0.serialize();
311 let id = hash(&pubkey, created_at, kind, &tags, &content);
312 let sig = *SECP256K1
313 .sign_schnorr(&Message::from_digest_slice(&id)?, key_pair)
314 .as_ref();
315 Self::new(id, pubkey, created_at, kind, tags, content, sig)
316 }
317}
318
319impl AsRef<Event> for Event {
320 fn as_ref(&self) -> &Event {
321 self
322 }
323}
324
325impl FromStr for Event {
326 type Err = Error;
327 fn from_str(s: &str) -> Result<Self, Self::Err> {
328 Ok(serde_json::from_str(s)?)
329 }
330}
331
332impl Display for Event {
333 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334 let str = serde_json::to_string(&self).unwrap();
335 f.write_str(&str)?;
336 Ok(())
337 }
338}
339
340impl TryInto<String> for Event {
341 type Error = Error;
342 fn try_into(self) -> Result<String, Self::Error> {
343 Ok(serde_json::to_string(&self)?)
344 }
345}
346
347pub trait FromEventData: Sized {
348 type Err: std::error::Error;
349 fn only_id() -> bool {
351 false
352 }
353 fn from_data<S: AsRef<[u8]>>(data: S) -> Result<Self, Self::Err>;
354}
355
356impl FromEventData for Vec<u8> {
358 type Err = Error;
359 fn only_id() -> bool {
360 true
361 }
362 fn from_data<S: AsRef<[u8]>>(data: S) -> Result<Self, Self::Err> {
363 Ok(data.as_ref().to_vec())
364 }
365}
366
367impl FromEventData for String {
369 type Err = Error;
370 fn from_data<S: AsRef<[u8]>>(json: S) -> Result<Self, Self::Err> {
371 let (t, bytes) = parse_data_type(json.as_ref());
372 if t == 1 {
373 #[cfg(feature = "zstd")]
374 {
375 let bytes = zstd::decode_all(bytes)?;
376 Ok(unsafe { String::from_utf8_unchecked(bytes) })
377 }
378 #[cfg(not(feature = "zstd"))]
379 {
380 Err(Error::Invalid("Need zstd feature".to_owned()))
381 }
382 } else {
383 Ok(unsafe { String::from_utf8_unchecked(bytes.to_vec()) })
384 }
385 }
386}
387
388fn parse_data_type(json: &[u8]) -> (u8, &[u8]) {
389 if !json.is_empty() {
390 let last = json.len() - 1;
391 let t = json[last];
392 if t == 0 || t == 1 {
393 return (t, &json[0..last]);
394 }
395 }
396 (0, json)
397}
398
399impl FromEventData for Event {
401 type Err = Error;
402 fn from_data<S: AsRef<[u8]>>(json: S) -> Result<Self, Self::Err> {
404 let (t, bytes) = parse_data_type(json.as_ref());
405 if t == 1 {
406 #[cfg(feature = "zstd")]
407 {
408 let bytes = zstd::decode_all(bytes)?;
409 Ok(serde_json::from_slice(&bytes)?)
410 }
411 #[cfg(not(feature = "zstd"))]
412 {
413 Err(Error::Invalid("Need zstd feature".to_owned()))
414 }
415 } else {
416 Ok(serde_json::from_slice(bytes)?)
417 }
418 }
419}
420
421#[cfg(feature = "search")]
422impl Event {
423 pub fn build_note_words(&mut self) {
425 if self.kind() == 1 {
426 let mut words = crate::segment(&self.content);
427 self.words.append(&mut words);
428 }
429 }
430}
431
432impl Event {
433 pub fn to_json(&self) -> Result<String, Error> {
435 Ok(serde_json::to_string(&self)?)
436 }
437
438 pub fn index(&self) -> &EventIndex {
439 &self.index
440 }
441
442 pub fn id(&self) -> &[u8; 32] {
443 &self.index.id
444 }
445
446 pub fn id_str(&self) -> String {
447 hex::encode(self.index.id)
448 }
449
450 pub fn pubkey(&self) -> &[u8; 32] {
451 &self.index.pubkey
452 }
453
454 pub fn pubkey_str(&self) -> String {
455 hex::encode(self.index.pubkey)
456 }
457
458 pub fn created_at(&self) -> u64 {
459 self.index.created_at
460 }
461
462 pub fn kind(&self) -> u16 {
463 self.index.kind
464 }
465
466 pub fn tags(&self) -> &Vec<Vec<String>> {
467 &self.tags
468 }
469
470 pub fn content(&self) -> &String {
471 &self.content
472 }
473
474 pub fn sig(&self) -> &[u8; 64] {
475 &self.sig
476 }
477}
478
479pub fn now() -> u64 {
480 SystemTime::now()
481 .duration_since(UNIX_EPOCH)
482 .unwrap_or_default()
483 .as_secs()
484}
485
486fn hash(
487 pubkey: &[u8],
488 created_at: u64,
489 kind: u16,
490 tags: &Vec<Vec<String>>,
491 content: &String,
492) -> [u8; 32] {
493 let json: Value = json!([0, hex::encode(pubkey), created_at, kind, tags, content]);
494 let mut hasher = Sha256::new();
495 hasher.update(json.to_string());
496 hasher.finalize().into()
497}
498
499impl Event {
500 pub fn hash(&self) -> [u8; 32] {
501 hash(
502 self.pubkey(),
503 self.created_at(),
504 self.kind(),
505 self.tags(),
506 self.content(),
507 )
508 }
509
510 pub fn verify_id(&self) -> Result<(), Error> {
511 if &self.hash() == self.id() {
512 Ok(())
513 } else {
514 Err(Error::Invalid("bad event id".to_owned()))
515 }
516 }
517
518 pub fn verify_sign(&self) -> Result<(), Error> {
519 if verify_sign(&self.sig, self.pubkey(), self.id()).is_ok() {
520 Ok(())
521 } else {
522 Err(Error::Invalid("signature is wrong".to_owned()))
523 }
524 }
525
526 pub fn verify_time(&self, now: u64, older: u64, newer: u64) -> Result<(), Error> {
529 let time = self.created_at();
530 if 0 != older && time < now - older {
531 return Err(Error::Invalid(format!(
532 "event creation date must be newer than {}",
533 now - older
534 )));
535 }
536
537 if 0 != newer && time > now + newer {
538 return Err(Error::Invalid(format!(
539 "event creation date must be older than {}",
540 now + newer
541 )));
542 }
543 Ok(())
544 }
545
546 pub fn verify_delegation(&self) -> Result<(), Error> {
547 if self.index.delegator.is_some() {
548 for tag in self.tags() {
549 if tag.len() == 4 && tag[0] == "delegation" {
550 return verify_delegation(self, &tag[1], &tag[2], &tag[3]);
551 }
552 }
553 Err(Error::Invalid("error delegation arguments".to_owned()))
554 } else {
555 Ok(())
556 }
557 }
558
559 pub fn validate(&self, now: u64, older: u64, newer: u64) -> Result<(), Error> {
560 if self.index.is_expired(now) {
561 return Err(Error::Invalid("event is expired".to_owned()));
562 }
563 self.verify_time(now, older, newer)?;
564 self.verify_id()?;
565 self.verify_sign()?;
566 self.verify_delegation()?;
567 Ok(())
568 }
569}
570
571fn verify_delegation(
572 event: &Event,
573 delegator: &String,
574 conditions: &String,
575 sig: &String,
576) -> Result<(), Error> {
577 let msg = format!(
578 "nostr:delegation:{}:{}",
579 hex::encode(event.pubkey()),
580 conditions
581 );
582 let mut hasher = Sha256::new();
583 hasher.update(msg);
584 let token = hasher.finalize().to_vec();
585 verify_sign(&hex::decode(sig)?, &hex::decode(delegator)?, &token)?;
586 let time = event.created_at();
587 for cond in conditions.split('&') {
589 if let Some(kind) = cond.strip_prefix("kind=") {
590 let n = u16::from_str(kind)?;
591 if n != event.kind() {
592 return Err(Error::Invalid(format!(
593 "event kind must be {}",
594 event.kind()
595 )));
596 }
597 }
598 if let Some(t) = cond.strip_prefix("created_at<") {
599 let n = u64::from_str(t)?;
600 if time >= n {
601 return Err(Error::Invalid(format!(
602 "event created_at must older than {}",
603 n
604 )));
605 }
606 }
607 if let Some(t) = cond.strip_prefix("created_at>") {
608 let n = u64::from_str(t)?;
609 if time <= n {
610 return Err(Error::Invalid(format!(
611 "event created_at must newer than {}",
612 n
613 )));
614 }
615 }
616 }
617
618 Ok(())
619}
620
621fn verify_sign(sig: &[u8], pk: &[u8], msg: &[u8]) -> Result<(), Error> {
622 let sig = Signature::from_slice(sig)?;
623 let pk = XOnlyPublicKey::from_slice(pk)?;
624 let msg = Message::from_digest_slice(msg)?;
625 Ok(SECP256K1.verify_schnorr(&sig, &msg, &pk)?)
626}
627
628#[cfg(test)]
629mod tests {
630 use super::*;
631 use anyhow::Result;
632 use secp256k1::rand::thread_rng;
633 use serde_json::Value;
634 use std::str::FromStr;
635
636 #[test]
637 fn index_event() -> Result<()> {
638 let note = r#"
639 {
640 "content": "Good morning everyone 😃",
641 "created_at": 1680690006,
642 "id": "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d",
643 "kind": 1,
644 "pubkey": "7abf57d516b1ff7308ca3bd5650ea6a4674d469c7c5057b1d005fb13d218bfef",
645 "sig": "ef4ff4f69ac387239eb1401fb07d7a44a5d5d57127e0dc3466a0403cf7d5486b668608ebfcbe9ff1f8d3b5d710545999fe08ee767284ec0b474e4cf92537678f",
646 "tags": [["t", "nostr"], ["t", ""], ["expiration", "1"], ["delegation", "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd"]]
647 }
648 "#;
649 let event: Event = Event::from_str(note)?;
650 assert_eq!(event.index().tags().len(), 2);
651 let e2 = EventIndex::from_bytes(&event.index().to_bytes()?)?;
652 assert_eq!(&e2, event.index());
653 assert!(&e2.expiration().is_some());
654 assert!(&e2.delegator().is_some());
655
656 let note = r#"
657 {
658 "content": "Good morning everyone 😃",
659 "created_at": 1680690006,
660 "id": "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d",
661 "kind": 1,
662 "pubkey": "7abf57d516b1ff7308ca3bd5650ea6a4674d469c7c5057b1d005fb13d218bfef",
663 "sig": "ef4ff4f69ac387239eb1401fb07d7a44a5d5d57127e0dc3466a0403cf7d5486b668608ebfcbe9ff1f8d3b5d710545999fe08ee767284ec0b474e4cf92537678f",
664 "tags": []
665 }
666 "#;
667 let event: Event = Event::from_str(note)?;
668 assert_eq!(event.index().tags().len(), 0);
669 let e2 = EventIndex::from_bytes(&event.index().to_bytes()?)?;
670 assert_eq!(&e2, event.index());
671 Ok(())
672 }
673
674 #[test]
675 fn string() -> Result<()> {
676 let note = r#"
677 {
678 "content": "Good morning everyone 😃",
679 "created_at": 1680690006,
680 "id": "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d",
681 "kind": 1,
682 "pubkey": "7abf57d516b1ff7308ca3bd5650ea6a4674d469c7c5057b1d005fb13d218bfef",
683 "sig": "ef4ff4f69ac387239eb1401fb07d7a44a5d5d57127e0dc3466a0403cf7d5486b668608ebfcbe9ff1f8d3b5d710545999fe08ee767284ec0b474e4cf92537678f",
684 "tags": [["t", "nostr"]]
685 }
686 "#;
687 let event: Event = Event::from_str(note)?;
688 assert_eq!(
689 hex::encode(event.index().id()),
690 "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d"
691 );
692 assert_eq!(
693 hex::encode(event.index().id()),
694 "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d"
695 );
696 assert_eq!(event.index().id().len(), 32);
697 let json: String = event.try_into()?;
698 let val: Value = serde_json::from_str(&json)?;
699 assert_eq!(
700 val["id"],
701 Value::String(
702 "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d".to_string()
703 )
704 );
705 Ok(())
706 }
707 #[test]
708 fn deserialize() -> Result<()> {
709 let note = r#"
710 {
711 "content": "Good morning everyone 😃",
712 "created_at": 1680690006,
713 "id": "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d",
714 "kind": 1,
715 "pubkey": "7abf57d516b1ff7308ca3bd5650ea6a4674d469c7c5057b1d005fb13d218bfef",
716 "sig": "ef4ff4f69ac387239eb1401fb07d7a44a5d5d57127e0dc3466a0403cf7d5486b668608ebfcbe9ff1f8d3b5d710545999fe08ee767284ec0b474e4cf92537678f",
717 "tags": [["t", "nostr"]]
718 }
719 "#;
720 let event: Event = serde_json::from_str(note)?;
721 assert_eq!(
722 hex::encode(event.index().id()),
723 "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d"
724 );
725 assert_eq!(
726 hex::encode(event.index().id()),
727 "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d"
728 );
729 assert_eq!(event.index().id().len(), 32);
730 assert_eq!(&event.tags, &vec![vec!["t", "nostr"]]);
731 assert_eq!(event.index().tags.len(), 1);
732
733 let note = r#"
735 {"content":"","created_at":1681838474,"id":"bf2b783de44b814778d02ca9e4e87aacd0bc7a629bad29b5db62a1c151580ed1","kind":1,"pubkey":"d477a41316e6d28c469181690237705024eb313b43ed3e1f059dc2ff49a6dd2f","sig":"96fa5e33aefd4b18f2d5ab5dc199e731fd6c33162ef3eeee945959b98901e80d1b8fb62856f4f0baed166f4aab2d4401aa8ce9e48071dbe220d2b8e9773755de","tags":[["e","fad5161223be749e364f0eac0fc8cf1566659a32c75d9ce388be42c36ac33e44",null,"root"]]}
736 "#;
737 let event = Event::from_str(note);
738 assert!(event.is_err());
739
740 let note = r#"
742 {
743 "content": "Good morning everyone 😃",
744 "created_at": 1680690006,
745 "id": "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d",
746 "kind": 65536,
747 "pubkey": "7abf57d516b1ff7308ca3bd5650ea6a4674d469c7c5057b1d005fb13d218bfef",
748 "sig": "ef4ff4f69ac387239eb1401fb07d7a44a5d5d57127e0dc3466a0403cf7d5486b668608ebfcbe9ff1f8d3b5d710545999fe08ee767284ec0b474e4cf92537678f",
749 "tags": [["t", "nostr"]]
750 }
751 "#;
752 let event = Event::from_str(note);
753 assert!(event.is_err());
754
755 Ok(())
756 }
757
758 #[test]
759 fn default() -> Result<()> {
760 let note = r#"
761 {
762 "created_at": 1680690006,
763 "id": "332747c0fab8a1a92def4b0937e177be6df4382ce6dd7724f86dc4710b7d4d7d",
764 "kind": 1,
765 "pubkey": "7abf57d516b1ff7308ca3bd5650ea6a4674d469c7c5057b1d005fb13d218bfef",
766 "sig": "ef4ff4f69ac387239eb1401fb07d7a44a5d5d57127e0dc3466a0403cf7d5486b668608ebfcbe9ff1f8d3b5d710545999fe08ee767284ec0b474e4cf92537678f"
767 }
768 "#;
769 let event: Event = serde_json::from_str(note)?;
770 assert_eq!(&event.content, "");
771 assert_eq!(&event.tags, &Vec::<Vec<String>>::new());
772 Ok(())
773 }
774
775 #[test]
776 fn verify() -> Result<()> {
777 let note = r#"
778 {"content":"bgQih8o+R83t00qvueD7twglJRvvabI+nDu+bTvRsAs=?iv=92TlqnpEeiUMzDtUxsZeUA==","created_at":1682257003,"id":"dba1951f0959dfea6e3123ad916d191a07b35392c4b541d4b4814e77113de14a","kind":4,"pubkey":"3f770d65d3a764a9c5cb503ae123e62ec7598ad035d836e2a810f3877a745b24","sig":"15dcc89bca7d037d6a5282c1e63ea40ca4f76d81821ca1260898a324c99516a0cb577617cf18a3febe6303ed32e7a1a08382eecde5a7183195ca8f186a0cb037","tags":[["p","6efb74e66b7ed7fb9fb7b8b8f12e1fbbabe7f45823a33a14ac60cc9241285536"]]}
779 "#;
780 let event: Event = serde_json::from_str(note)?;
781 assert!(event.verify_sign().is_ok());
782 assert!(event.verify_id().is_ok());
783 assert!(!event.index().is_expired(now()));
784 assert!(!event.index().is_ephemeral());
785
786 let note = r#"
787 {"content":"{\"display_name\": \"maglevclient\", \"uptime\": 103180, \"maglev\": \"1a98030114cf\"}","created_at":1682258083,"id":"153a480d7bb9d7564147241b330a8667b19c3f9178b8179e64bf57f200654cb0","kind":0,"pubkey":"fb7324a1b807b48756be8df06bd9ccf11741a9678b120e91e044b5137734dcb2","sig":"08c0ffa072fd49f405df467ccab25152a54073fc0639ea0952e1eabff7962e008c54cb8f4d2d55dc4398703df4a5654d2ae3e93f68a801bcbabcdb8050a918ef","tags":[["t","TESTmaglev"],["expiration","1682258683"]]}
788 "#;
789 let event: Event = serde_json::from_str(note)?;
790 assert!(event.verify_sign().is_ok());
791 assert!(event.verify_id().is_ok());
792 assert!(event.index().is_expired(now()));
793
794 let event = Event::new([0; 32], [0; 32], 10, 1, vec![], "".to_string(), [0; 64])?;
795 assert!(event.verify_time(10, 1, 1).is_ok());
796 assert!(event.verify_time(20, 1, 1).is_err());
797 assert!(event.verify_time(5, 1, 1).is_err());
798
799 let note = r#"
800 {
801 "id": "e93c6095c3db1c31d15ac771f8fc5fb672f6e52cd25505099f62cd055523224f",
802 "pubkey": "477318cfb5427b9cfc66a9fa376150c1ddbc62115ae27cef72417eb959691396",
803 "created_at": 1677426298,
804 "kind": 1,
805 "tags": [
806 [
807 "delegation",
808 "8e0d3d3eb2881ec137a11debe736a9086715a8c8beeeda615780064d68bc25dd",
809 "kind=1&created_at>1674834236&created_at<1677426236",
810 "6f44d7fe4f1c09f3954640fb58bd12bae8bb8ff4120853c4693106c82e920e2b898f1f9ba9bd65449a987c39c0423426ab7b53910c0c6abfb41b30bc16e5f524"
811 ]
812 ],
813 "content": "Hello, world!",
814 "sig": "633db60e2e7082c13a47a6b19d663d45b2a2ebdeaf0b4c35ef83be2738030c54fc7fd56d139652937cdca875ee61b51904a1d0d0588a6acd6168d7be2909d693"
815 }
816 "#;
817 let event: Event = serde_json::from_str(note)?;
818 assert!(event.verify_delegation().is_err());
819 assert!(event
820 .verify_delegation()
821 .unwrap_err()
822 .to_string()
823 .contains("older"));
824
825 Ok(())
826 }
827
828 #[test]
829 fn create() -> Result<()> {
830 let mut rng = thread_rng();
831 let key_pair = Keypair::new_global(&mut rng);
832 let event = Event::create(&key_pair, 0, 1, vec![], "".to_owned())?;
833 assert!(event.verify_sign().is_ok());
834 assert!(event.verify_id().is_ok());
835 Ok(())
836 }
837}