upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/key_handling
diff options
context:
space:
mode:
Diffstat (limited to 'src/key_handling')
-rw-r--r--src/key_handling/users.rs683
1 files changed, 667 insertions, 16 deletions
diff --git a/src/key_handling/users.rs b/src/key_handling/users.rs
index 1d2cc34..91519bc 100644
--- a/src/key_handling/users.rs
+++ b/src/key_handling/users.rs
@@ -1,11 +1,21 @@
1use std::time::SystemTime;
2
1use anyhow::{Context, Result}; 3use anyhow::{Context, Result};
4use async_trait::async_trait;
2use nostr::prelude::*; 5use nostr::prelude::*;
3use zeroize::Zeroize; 6use zeroize::Zeroize;
4 7
5use super::encryption::{EncryptDecrypt, Encryptor}; 8use super::encryption::{EncryptDecrypt, Encryptor};
9#[cfg(not(test))]
10use crate::client::Client;
11#[cfg(test)]
12use crate::client::MockConnect;
6use crate::{ 13use crate::{
7 cli_interactor::{Interactor, InteractorPrompt, PromptInputParms, PromptPasswordParms}, 14 cli_interactor::{Interactor, InteractorPrompt, PromptInputParms, PromptPasswordParms},
8 config::{self, ConfigManagement, ConfigManager}, 15 client::Connect,
16 config::{
17 self, ConfigManagement, ConfigManager, UserMetadata, UserRef, UserRelayRef, UserRelays,
18 },
9}; 19};
10 20
11#[derive(Default)] 21#[derive(Default)]
@@ -15,13 +25,29 @@ pub struct UserManager {
15 encryptor: Encryptor, 25 encryptor: Encryptor,
16} 26}
17 27
28#[async_trait]
18pub trait UserManagement { 29pub trait UserManagement {
19 fn add(&self, nsec: &Option<String>, password: &Option<String>) -> Result<nostr::Keys>; 30 fn add(&self, nsec: &Option<String>, password: &Option<String>) -> Result<nostr::Keys>;
31 async fn get_user(
32 &self,
33 #[cfg(test)] client: &MockConnect,
34 #[cfg(not(test))] client: &Client,
35 public_key: &XOnlyPublicKey,
36 after: u64,
37 ) -> Result<UserRef>;
38 fn get_user_from_cache(&self, public_key: &XOnlyPublicKey) -> Result<UserRef>;
39 fn add_user_to_config(
40 &self,
41 public_key: XOnlyPublicKey,
42 encrypted_secret_key: Option<String>,
43 overwrite: bool,
44 ) -> Result<()>;
20} 45}
21 46
22#[cfg(test)] 47#[cfg(test)]
23use duplicate::duplicate_item; 48use duplicate::duplicate_item;
24#[cfg_attr(test, duplicate_item(UserManager; [UserManager]; [self::tests::MockUserManager]))] 49#[cfg_attr(test, duplicate_item(UserManager; [UserManager]; [self::tests::MockUserManager]))]
50#[async_trait]
25impl UserManagement for UserManager { 51impl UserManagement for UserManager {
26 fn add(&self, nsec: &Option<String>, password: &Option<String>) -> Result<nostr::Keys> { 52 fn add(&self, nsec: &Option<String>, password: &Option<String>) -> Result<nostr::Keys> {
27 let mut prompt = "login with nsec (or hex private key)"; 53 let mut prompt = "login with nsec (or hex private key)";
@@ -66,9 +92,152 @@ impl UserManagement for UserManager {
66 .context("failed to encrypt nsec with password.")?; 92 .context("failed to encrypt nsec with password.")?;
67 pass.zeroize(); 93 pass.zeroize();
68 94
69 let user_ref = config::UserRef { 95 self.add_user_to_config(keys.public_key(), Some(encrypted_secret_key), true)?;
70 public_key: keys.public_key(), 96
71 encrypted_key: encrypted_secret_key, 97 Ok(keys)
98 }
99
100 fn add_user_to_config(
101 &self,
102 public_key: XOnlyPublicKey,
103 encrypted_secret_key: Option<String>,
104 overwrite: bool,
105 ) -> Result<()> {
106 let user_ref =
107 config::UserRef::new(public_key, encrypted_secret_key.unwrap_or(String::new()));
108
109 let mut cfg = self.config_manager.load().context("failed to load application config to find and remove any old versions of the user's encrypted key")?;
110 // don't overwrite unless specified
111 if !overwrite
112 && cfg
113 .users
114 .clone()
115 .into_iter()
116 .any(|r| r.public_key.eq(&public_key))
117 {
118 return Ok(());
119 }
120 // if overwrite remove any duplicate entries for key before adding it to config
121 cfg.users = cfg
122 .users
123 .clone()
124 .into_iter()
125 .filter(|r| !r.public_key.eq(&public_key))
126 .collect();
127 cfg.users.push(user_ref);
128 self.config_manager
129 .save(&cfg)
130 .context("failed to save application configuration with new user details in")
131 }
132
133 fn get_user_from_cache(&self, public_key: &XOnlyPublicKey) -> Result<UserRef> {
134 let cfg = self
135 .config_manager
136 .load()
137 .context("failed to load application config")?;
138 Ok(cfg
139 .users
140 .iter()
141 .find(|u| u.public_key.eq(public_key))
142 .context(format!("pubkey isn't a current user: {public_key}"))?
143 .clone())
144 }
145 /// get UserRef fetching most recent user relays and metadata infomation
146 /// from relays
147 async fn get_user(
148 &self,
149 #[cfg(test)] client: &MockConnect,
150 #[cfg(not(test))] client: &Client,
151 public_key: &XOnlyPublicKey,
152 use_cache_unless_checked_more_than_x_secs_ago: u64,
153 ) -> Result<UserRef> {
154 let cfg = self
155 .config_manager
156 .load()
157 .context("failed to load application config")?;
158 let user_ref = cfg
159 .users
160 .iter()
161 .find(|u| u.public_key.eq(public_key))
162 .context(format!("pubkey isn't a current user: {public_key}"))?;
163 // return cache if last fetched was within X minutes
164 if !unix_timestamp_after_now_plus_secs(
165 user_ref.last_checked,
166 use_cache_unless_checked_more_than_x_secs_ago,
167 ) {
168 return Ok(user_ref.clone());
169 }
170 let events: Vec<Event> = match client
171 .get_events(
172 if user_ref.relays.write().is_empty() {
173 client.get_fallback_relays().clone()
174 } else {
175 user_ref.relays.write()
176 },
177 vec![
178 nostr::Filter::default()
179 .author(public_key.to_string())
180 .since(nostr::Timestamp::from(user_ref.metadata.created_at + 1))
181 .kind(Kind::Metadata),
182 nostr::Filter::default()
183 .author(public_key.to_string())
184 .since(nostr::Timestamp::from(user_ref.relays.created_at + 1))
185 .kind(Kind::RelayList),
186 ],
187 )
188 .await
189 {
190 Ok(events) => events,
191 Err(_) => {
192 // TODO error reporting
193 return Ok(user_ref.clone());
194 }
195 };
196
197 let mut user_ref = user_ref.clone();
198
199 user_ref.last_checked = SystemTime::now()
200 .duration_since(SystemTime::UNIX_EPOCH)
201 .context("system time should be after the year 1970")?
202 .as_secs();
203
204 if let Some(new_metadata_event) = events
205 .iter()
206 .filter(|e| e.kind.eq(&nostr::Kind::Metadata) && e.pubkey.eq(public_key))
207 .max_by_key(|e| e.created_at)
208 {
209 if new_metadata_event.created_at.as_u64() > user_ref.metadata.created_at {
210 let metadata = nostr::Metadata::from_json(new_metadata_event.content.clone())
211 .context("metadata cannot be found in kind 0 event content")?;
212 user_ref.metadata = UserMetadata {
213 name: metadata
214 .name
215 .context("user metadata should always have name")?,
216 created_at: new_metadata_event.created_at.as_u64(),
217 };
218 }
219 };
220
221 if let Some(new_relays_event) = events
222 .iter()
223 .filter(|e| e.kind.eq(&nostr::Kind::RelayList) && e.pubkey.eq(public_key))
224 .max_by_key(|e| e.created_at)
225 {
226 if new_relays_event.created_at.as_u64() > user_ref.relays.created_at {
227 user_ref.relays = UserRelays {
228 relays: new_relays_event
229 .tags
230 .iter()
231 .filter(|t| t.kind().eq(&nostr::TagKind::R))
232 .map(|t| UserRelayRef {
233 url: t.as_vec()[1].clone(),
234 read: t.as_vec().len() == 2 || t.as_vec()[2].eq("read"),
235 write: t.as_vec().len() == 2 || t.as_vec()[2].eq("write"),
236 })
237 .collect(),
238 created_at: new_relays_event.created_at.as_u64(),
239 };
240 }
72 }; 241 };
73 242
74 // remove any duplicate entries for key before adding it to config 243 // remove any duplicate entries for key before adding it to config
@@ -77,19 +246,27 @@ impl UserManagement for UserManager {
77 .users 246 .users
78 .clone() 247 .clone()
79 .into_iter() 248 .into_iter()
80 .filter(|r| !r.public_key.eq(&keys.public_key())) 249 .filter(|r| !r.public_key.eq(public_key))
81 .collect(); 250 .collect();
82 cfg.users.push(user_ref); 251 cfg.users.push(user_ref.clone());
83 self.config_manager 252 self.config_manager
84 .save(&cfg) 253 .save(&cfg)
85 .context("failed to save application configuration with new user details in")?; 254 .context("failed to save application configuration with new user details in")?;
255 Ok(user_ref)
256 }
257}
86 258
87 Ok(keys) 259fn unix_timestamp_after_now_plus_secs(timestamp: u64, secs: u64) -> bool {
260 if let Ok(now) = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
261 now.as_secs() > (timestamp + secs)
262 } else {
263 true
88 } 264 }
89} 265}
90 266
91#[cfg(test)] 267#[cfg(test)]
92mod tests { 268mod tests {
269 use nostr;
93 use test_utils::*; 270 use test_utils::*;
94 271
95 use super::*; 272 use super::*;
@@ -278,11 +455,10 @@ mod tests {
278 m.config_manager = MockConfigManagement::default(); 455 m.config_manager = MockConfigManagement::default();
279 m.config_manager.expect_load().returning(|| { 456 m.config_manager.expect_load().returning(|| {
280 Ok(MyConfig { 457 Ok(MyConfig {
281 users: vec![UserRef { 458 users: vec![UserRef::new(
282 public_key: TEST_KEY_1_KEYS.public_key(), 459 TEST_KEY_1_KEYS.public_key(),
283 // different key to TEST_KEY_1_ENCYPTED 460 TEST_KEY_2_ENCRYPTED.into(),
284 encrypted_key: TEST_KEY_2_ENCRYPTED.into(), 461 )],
285 }],
286 ..MyConfig::default() 462 ..MyConfig::default()
287 }) 463 })
288 }); 464 });
@@ -308,10 +484,10 @@ mod tests {
308 m.config_manager = MockConfigManagement::default(); 484 m.config_manager = MockConfigManagement::default();
309 m.config_manager.expect_load().returning(|| { 485 m.config_manager.expect_load().returning(|| {
310 Ok(MyConfig { 486 Ok(MyConfig {
311 users: vec![UserRef { 487 users: vec![UserRef::new(
312 public_key: TEST_KEY_2_KEYS.public_key(), 488 TEST_KEY_2_KEYS.public_key(),
313 encrypted_key: TEST_KEY_2_ENCRYPTED.into(), 489 TEST_KEY_2_ENCRYPTED.into(),
314 }], 490 )],
315 ..MyConfig::default() 491 ..MyConfig::default()
316 }) 492 })
317 }); 493 });
@@ -329,4 +505,479 @@ mod tests {
329 } 505 }
330 } 506 }
331 } 507 }
508
509 fn now_timestamp() -> u64 {
510 SystemTime::now()
511 .duration_since(SystemTime::UNIX_EPOCH)
512 .unwrap()
513 .as_secs()
514 }
515 fn roughly_now(timestamp: u64) -> bool {
516 let now = now_timestamp();
517 timestamp < now + 100 && timestamp > now - 100
518 }
519
520 mod get_user {
521 use anyhow::anyhow;
522
523 use super::*;
524 use crate::client::MockConnect;
525
526 fn generate_relaylist_event() -> nostr::Event {
527 nostr::event::EventBuilder::new(
528 nostr::Kind::RelayList,
529 "",
530 &[
531 nostr::Tag::RelayMetadata(
532 "wss://fredswrite1.relay".into(),
533 Some(nostr::RelayMetadata::Write),
534 ),
535 nostr::Tag::RelayMetadata(
536 "wss://fredsread1.relay".into(),
537 Some(nostr::RelayMetadata::Read),
538 ),
539 nostr::Tag::RelayMetadata("wss://fredsreadwrite.relay".into(), None),
540 ],
541 )
542 .to_event(&TEST_KEY_1_KEYS)
543 .unwrap()
544 }
545
546 fn generate_relaylist_event_user_2() -> nostr::Event {
547 nostr::event::EventBuilder::new(
548 nostr::Kind::RelayList,
549 "",
550 &[
551 nostr::Tag::RelayMetadata(
552 "wss://carolswrite1.relay".into(),
553 Some(nostr::RelayMetadata::Write),
554 ),
555 nostr::Tag::RelayMetadata(
556 "wss://carolsread1.relay".into(),
557 Some(nostr::RelayMetadata::Read),
558 ),
559 nostr::Tag::RelayMetadata("wss://carolsreadwrite.relay".into(), None),
560 ],
561 )
562 .to_event(&TEST_KEY_2_KEYS)
563 .unwrap()
564 }
565
566 fn fallback_relays() -> Vec<String> {
567 vec!["ws://fallback1".to_string(), "ws://fallback2".to_string()].clone()
568 }
569
570 fn generate_mock_client() -> MockConnect {
571 let mut client = <MockConnect as std::default::Default>::default();
572 client
573 .expect_get_fallback_relays()
574 .return_const(fallback_relays());
575 client
576 }
577
578 fn generate_standard_config() -> MyConfig {
579 MyConfig {
580 users: vec![UserRef {
581 public_key: TEST_KEY_1_KEYS.public_key(),
582 encrypted_key: TEST_KEY_1_ENCRYPTED.to_string(),
583 metadata: UserMetadata {
584 name: "Fred".to_string(),
585 created_at: 10,
586 },
587 relays: UserRelays {
588 relays: vec![
589 UserRelayRef {
590 url: "ws://existingread".to_string(),
591 read: true,
592 write: false,
593 },
594 UserRelayRef {
595 url: "ws://existingreadwrite".to_string(),
596 read: true,
597 write: true,
598 },
599 UserRelayRef {
600 url: "ws://existingwrite".to_string(),
601 read: false,
602 write: true,
603 },
604 ],
605 created_at: 10,
606 },
607 last_checked: now_timestamp() - (60 * 60), // 1h ago
608 }],
609 ..MyConfig::default()
610 }
611 .clone()
612 }
613
614 fn expected_userrelayrefs() -> Vec<UserRelayRef> {
615 vec![
616 UserRelayRef {
617 url: "wss://fredswrite1.relay".into(),
618 read: false,
619 write: true,
620 },
621 UserRelayRef {
622 url: "wss://fredsread1.relay".into(),
623 read: true,
624 write: false,
625 },
626 UserRelayRef {
627 url: "wss://fredsreadwrite.relay".into(),
628 read: true,
629 write: true,
630 },
631 ]
632 }
633
634 mod when_within_caching_time_window {
635 use super::*;
636
637 #[test]
638 fn returns_cached_details_without_checking_relays_or_updaing_config() -> Result<()> {
639 let mut m = MockUserManager::default();
640 let client = generate_mock_client();
641 m.config_manager
642 .expect_load()
643 .returning(|| Ok(generate_standard_config()));
644 let res = futures::executor::block_on(m.get_user(
645 &client,
646 &TEST_KEY_1_KEYS.public_key(),
647 24 * 60 * 60, // within 24 hours
648 ))?;
649 assert_eq!(res.metadata.name, "Fred");
650 assert_eq!(res.relays.relays[0].url, "ws://existingread");
651 Ok(())
652 }
653 }
654
655 mod returns_userref_with_latest_details_from_events_on_relays {
656 use super::*;
657
658 #[test]
659 fn name() -> Result<()> {
660 let mut m = MockUserManager::default();
661 let mut client = generate_mock_client();
662 m.config_manager
663 .expect_load()
664 .returning(|| Ok(generate_standard_config()));
665 m.config_manager.expect_save().returning(|_| Ok(()));
666 client
667 .expect_get_events()
668 .returning(|_, _| Ok(vec![generate_test_key_1_metadata_event("fred")]));
669
670 let res = futures::executor::block_on(m.get_user(
671 &client,
672 &TEST_KEY_1_KEYS.public_key(),
673 5 * 60, // 5 mins ago
674 ))?;
675 assert_eq!(res.metadata.name, "fred");
676 Ok(())
677 }
678
679 #[test]
680 fn name_ignoring_other_users_events() -> Result<()> {
681 let mut m = MockUserManager::default();
682 let mut client = generate_mock_client();
683 m.config_manager
684 .expect_load()
685 .returning(|| Ok(generate_standard_config()));
686 m.config_manager.expect_save().returning(|_| Ok(()));
687 client.expect_get_events().returning(|_, _| {
688 Ok(vec![
689 generate_test_key_2_metadata_event("carole"),
690 generate_test_key_1_metadata_event_old("fred"),
691 ])
692 });
693
694 let res = futures::executor::block_on(m.get_user(
695 &client,
696 &TEST_KEY_1_KEYS.public_key(),
697 5 * 60, // 5 mins ago
698 ))?;
699 assert_eq!(res.metadata.name, "fred");
700 Ok(())
701 }
702
703 #[test]
704 fn relays() -> Result<()> {
705 let mut m = MockUserManager::default();
706 let mut client = generate_mock_client();
707 m.config_manager
708 .expect_load()
709 .returning(|| Ok(generate_standard_config()));
710 m.config_manager.expect_save().returning(|_| Ok(()));
711 client.expect_get_events().returning(|_, _| {
712 Ok(vec![
713 generate_test_key_1_metadata_event("fred"),
714 generate_relaylist_event(),
715 ])
716 });
717
718 let res = futures::executor::block_on(m.get_user(
719 &client,
720 &TEST_KEY_1_KEYS.public_key(),
721 5 * 60, // 5 mins ago
722 ))?;
723 assert_eq!(res.relays.relays, expected_userrelayrefs(),);
724 Ok(())
725 }
726
727 #[test]
728 fn relays_ignoring_other_users_events() -> Result<()> {
729 let mut m = MockUserManager::default();
730 let mut client = generate_mock_client();
731 m.config_manager
732 .expect_load()
733 .returning(|| Ok(generate_standard_config()));
734 m.config_manager.expect_save().returning(|_| Ok(()));
735 client.expect_get_events().returning(|_, _| {
736 Ok(vec![
737 make_event_old_or_change_user(
738 generate_relaylist_event(),
739 &TEST_KEY_1_KEYS,
740 10000,
741 ),
742 generate_relaylist_event_user_2(),
743 ])
744 });
745
746 let res = futures::executor::block_on(m.get_user(
747 &client,
748 &TEST_KEY_1_KEYS.public_key(),
749 5 * 60, // 5 mins ago
750 ))?;
751 assert_eq!(res.relays.relays, expected_userrelayrefs(),);
752 Ok(())
753 }
754 }
755
756 mod saves_updates_to_config {
757 use super::*;
758
759 #[test]
760 fn saves_name_to_config() -> Result<()> {
761 let mut m = MockUserManager::default();
762 let mut client = generate_mock_client();
763 m.config_manager
764 .expect_load()
765 .returning(|| Ok(generate_standard_config()));
766 m.config_manager
767 .expect_save()
768 .once()
769 .withf(|cfg| cfg.users[0].metadata.name.eq("fred"))
770 .returning(|_| Ok(()));
771 client
772 .expect_get_events()
773 .returning(|_, _| Ok(vec![generate_test_key_1_metadata_event("fred")]));
774
775 futures::executor::block_on(m.get_user(
776 &client,
777 &TEST_KEY_1_KEYS.public_key(),
778 5 * 60, // 5 mins ago
779 ))?;
780 Ok(())
781 }
782
783 #[test]
784 fn updates_metadata_created_at() -> Result<()> {
785 let mut m = MockUserManager::default();
786 let mut client = generate_mock_client();
787 m.config_manager
788 .expect_load()
789 .returning(|| Ok(generate_standard_config()));
790 m.config_manager
791 .expect_save()
792 .once()
793 .withf(|cfg| roughly_now(cfg.users[0].metadata.created_at))
794 .returning(|_| Ok(()));
795 client
796 .expect_get_events()
797 .returning(|_, _| Ok(vec![generate_test_key_1_metadata_event("fred")]));
798
799 futures::executor::block_on(m.get_user(
800 &client,
801 &TEST_KEY_1_KEYS.public_key(),
802 5 * 60, // 5 mins ago
803 ))?;
804 Ok(())
805 }
806
807 #[test]
808 fn saves_relays_to_config() -> Result<()> {
809 let mut m = MockUserManager::default();
810 let mut client = generate_mock_client();
811 m.config_manager
812 .expect_load()
813 .returning(|| Ok(generate_standard_config()));
814 m.config_manager
815 .expect_save()
816 .once()
817 .withf(|cfg| expected_userrelayrefs().eq(&cfg.users[0].relays.relays))
818 .returning(|_| Ok(()));
819 client
820 .expect_get_events()
821 .returning(|_, _| Ok(vec![generate_relaylist_event()]));
822
823 futures::executor::block_on(m.get_user(
824 &client,
825 &TEST_KEY_1_KEYS.public_key(),
826 5 * 60, // 5 mins ago
827 ))?;
828 Ok(())
829 }
830
831 #[test]
832 fn updates_relays_created_at() -> Result<()> {
833 let mut m = MockUserManager::default();
834 let mut client = generate_mock_client();
835 m.config_manager
836 .expect_load()
837 .returning(|| Ok(generate_standard_config()));
838 m.config_manager
839 .expect_save()
840 .once()
841 .withf(|cfg| roughly_now(cfg.users[0].relays.created_at))
842 .returning(|_| Ok(()));
843 client
844 .expect_get_events()
845 .returning(|_, _| Ok(vec![generate_relaylist_event()]));
846
847 futures::executor::block_on(m.get_user(
848 &client,
849 &TEST_KEY_1_KEYS.public_key(),
850 5 * 60, // 5 mins ago
851 ))?;
852 Ok(())
853 }
854
855 #[test]
856 fn when_no_changes_updates_last_updated() -> Result<()> {
857 let mut m = MockUserManager::default();
858 let mut client = generate_mock_client();
859 m.config_manager
860 .expect_load()
861 .returning(|| Ok(generate_standard_config()));
862 m.config_manager
863 .expect_save()
864 .once()
865 .withf(|cfg| roughly_now(cfg.users[0].last_checked))
866 .returning(|_| Ok(()));
867 client.expect_get_events().returning(|_, _| Ok(vec![]));
868
869 futures::executor::block_on(m.get_user(
870 &client,
871 &TEST_KEY_1_KEYS.public_key(),
872 5 * 60, // 5 mins ago
873 ))?;
874 Ok(())
875 }
876
877 #[test]
878 fn when_changes_updates_last_updated() -> Result<()> {
879 let mut m = MockUserManager::default();
880 let mut client = generate_mock_client();
881 m.config_manager
882 .expect_load()
883 .returning(|| Ok(generate_standard_config()));
884 m.config_manager
885 .expect_save()
886 .once()
887 .withf(|cfg| roughly_now(cfg.users[0].last_checked))
888 .returning(|_| Ok(()));
889 client
890 .expect_get_events()
891 .returning(|_, _| Ok(vec![generate_test_key_1_metadata_event("fred")]));
892
893 futures::executor::block_on(m.get_user(
894 &client,
895 &TEST_KEY_1_KEYS.public_key(),
896 5 * 60, // 5 mins ago
897 ))?;
898 Ok(())
899 }
900 }
901
902 mod fetches_from_correct_relays {
903 use super::*;
904 #[test]
905 fn when_userref_write_relays_present_fetches_only_from_them() -> Result<()> {
906 let mut m = MockUserManager::default();
907 let mut client = generate_mock_client();
908 m.config_manager
909 .expect_load()
910 .returning(|| Ok(generate_standard_config()));
911 m.config_manager.expect_save().returning(|_| Ok(()));
912 client
913 .expect_get_events()
914 .once()
915 .withf(move |relays, _filters| {
916 vec![
917 "ws://existingreadwrite".to_string(),
918 "ws://existingwrite".to_string(),
919 ]
920 .eq(relays)
921 })
922 .returning(|_, _| Ok(vec![]));
923
924 futures::executor::block_on(m.get_user(
925 &client,
926 &TEST_KEY_1_KEYS.public_key(),
927 5 * 60, // 5 mins ago
928 ))?;
929 Ok(())
930 }
931 #[test]
932 fn when_userref_write_relays_not_present_fetches_from_fallback_relays() -> Result<()> {
933 let mut m = MockUserManager::default();
934 let mut client = generate_mock_client();
935 m.config_manager.expect_load().returning(|| {
936 Ok(MyConfig {
937 users: vec![UserRef {
938 relays: UserRelays {
939 relays: vec![],
940 created_at: 0,
941 },
942 ..generate_standard_config().users[0].clone()
943 }],
944 ..generate_standard_config()
945 })
946 });
947 m.config_manager.expect_save().returning(|_| Ok(()));
948 client
949 .expect_get_events()
950 .once()
951 .withf(move |relays, _filters| fallback_relays().eq(relays))
952 .returning(|_, _| Ok(vec![]));
953
954 futures::executor::block_on(m.get_user(
955 &client,
956 &TEST_KEY_1_KEYS.public_key(),
957 5 * 60, // 5 mins ago
958 ))?;
959 Ok(())
960 }
961 }
962
963 #[test]
964 fn when_failed_to_fetch_events_returns_cached_details() -> Result<()> {
965 let mut m = MockUserManager::default();
966 let mut client = generate_mock_client();
967 m.config_manager
968 .expect_load()
969 .returning(|| Ok(generate_standard_config()));
970 client
971 .expect_get_events()
972 .returning(|_, _| Err(anyhow!("test error")));
973
974 let res = futures::executor::block_on(m.get_user(
975 &client,
976 &TEST_KEY_1_KEYS.public_key(),
977 5 * 60, // 10 mins ago
978 ))?;
979 assert_eq!(res.metadata.name, "Fred");
980 Ok(())
981 }
982 }
332} 983}