upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/key_handling/users.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2023-10-01 00:00:00 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2023-10-01 00:00:00 +0100
commite237328ec611a5891586530c1d3cb26c16c1093b (patch)
tree22ac36baa240354d06ae82eb070609fa3e3fcb82 /src/key_handling/users.rs
parent000901c0cbca8464b5a89bcc93c5474f6564bafd (diff)
feat(login) fetch user relays and metadata
get user relay list and metadata events from relays when keys are used and last fetch attempt was more than an hour ago uses user's write relays if known, otherwise uses fallback relays to achieve this a method for intergration testing event fetching from relays was added
Diffstat (limited to 'src/key_handling/users.rs')
-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}