upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-04-01 14:31:34 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2025-04-01 14:35:50 +0100
commit948fe972eb2bddf187b79f2673a091b6331cfd90 (patch)
treeec1c538d28108b104b5a00afd673631538f9aa00 /src/lib
parent70966d571fce16f707725c6b0af0fd585bfce607 (diff)
chore: bump rust-nostr v0.37 ~> v0.40
and fix all of the breaking changes
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/client.rs223
-rw-r--r--src/lib/git/mod.rs2
-rw-r--r--src/lib/git/nostr_url.rs150
-rw-r--r--src/lib/git_events.rs42
-rw-r--r--src/lib/login/existing.rs2
-rw-r--r--src/lib/login/fresh.rs2
-rw-r--r--src/lib/login/key_encryption.rs2
-rw-r--r--src/lib/login/mod.rs4
-rw-r--r--src/lib/repo_ref.rs103
9 files changed, 313 insertions, 217 deletions
diff --git a/src/lib/client.rs b/src/lib/client.rs
index 59ec583..142df64 100644
--- a/src/lib/client.rs
+++ b/src/lib/client.rs
@@ -29,9 +29,14 @@ use futures::{
29use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressState, ProgressStyle}; 29use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressState, ProgressStyle};
30#[cfg(test)] 30#[cfg(test)]
31use mockall::*; 31use mockall::*;
32use nostr::{Event, nips::nip01::Coordinate, signer::SignerBackend}; 32use nostr::{
33use nostr_database::NostrEventsDatabase; 33 Event,
34 nips::{nip01::Coordinate, nip19::Nip19Coordinate},
35 signer::SignerBackend,
36};
37use nostr_database::{NostrEventsDatabase, SaveEventStatus};
34use nostr_lmdb::NostrLMDB; 38use nostr_lmdb::NostrLMDB;
39use nostr_relay_pool::relay::ReqExitPolicy;
35use nostr_sdk::{ 40use nostr_sdk::{
36 EventBuilder, EventId, Kind, NostrSigner, Options, PublicKey, RelayUrl, SingleLetterTag, 41 EventBuilder, EventId, Kind, NostrSigner, Options, PublicKey, RelayUrl, SingleLetterTag,
37 Timestamp, prelude::RelayLimits, 42 Timestamp, prelude::RelayLimits,
@@ -89,7 +94,7 @@ pub trait Connect {
89 async fn fetch_all<'a>( 94 async fn fetch_all<'a>(
90 &self, 95 &self,
91 git_repo_path: Option<&'a Path>, 96 git_repo_path: Option<&'a Path>,
92 repo_coordinates: Option<&'a Coordinate>, 97 repo_coordinates: Option<&'a Nip19Coordinate>,
93 user_profiles: &HashSet<PublicKey>, 98 user_profiles: &HashSet<PublicKey>,
94 ) -> Result<(Vec<Result<FetchReport>>, MultiProgress)>; 99 ) -> Result<(Vec<Result<FetchReport>>, MultiProgress)>;
95 async fn fetch_all_from_relay<'a>( 100 async fn fetch_all_from_relay<'a>(
@@ -182,8 +187,8 @@ impl Connect for Client {
182 187
183 if !relay.is_connected() { 188 if !relay.is_connected() {
184 #[allow(clippy::large_futures)] 189 #[allow(clippy::large_futures)]
185 relay 190 let _ = relay
186 .connect(Some(std::time::Duration::from_secs(CONNECTION_TIMEOUT))) 191 .try_connect(std::time::Duration::from_secs(CONNECTION_TIMEOUT))
187 .await; 192 .await;
188 } 193 }
189 194
@@ -194,7 +199,7 @@ impl Connect for Client {
194 } 199 }
195 200
196 async fn disconnect(&self) -> Result<()> { 201 async fn disconnect(&self) -> Result<()> {
197 self.client.disconnect().await?; 202 self.client.disconnect().await;
198 Ok(()) 203 Ok(())
199 } 204 }
200 205
@@ -223,11 +228,7 @@ impl Connect for Client {
223 self.client.add_relay(url).await?; 228 self.client.add_relay(url).await?;
224 #[allow(clippy::large_futures)] 229 #[allow(clippy::large_futures)]
225 self.client.connect_relay(url).await?; 230 self.client.connect_relay(url).await?;
226 self.client 231 self.client.relay(url).await?.send_event(&event).await?;
227 .relay(url)
228 .await?
229 .send_event(event.clone())
230 .await?;
231 if let Some(git_repo_path) = git_repo_path { 232 if let Some(git_repo_path) = git_repo_path {
232 save_event_in_local_cache(git_repo_path, &event).await?; 233 save_event_in_local_cache(git_repo_path, &event).await?;
233 } 234 }
@@ -329,7 +330,7 @@ impl Connect for Client {
329 async fn fetch_all<'a>( 330 async fn fetch_all<'a>(
330 &self, 331 &self,
331 git_repo_path: Option<&'a Path>, 332 git_repo_path: Option<&'a Path>,
332 trusted_maintainer_coordinate: Option<&'a Coordinate>, 333 trusted_maintainer_coordinate: Option<&'a Nip19Coordinate>,
333 user_profiles: &HashSet<PublicKey>, 334 user_profiles: &HashSet<PublicKey>,
334 ) -> Result<(Vec<Result<FetchReport>>, MultiProgress)> { 335 ) -> Result<(Vec<Result<FetchReport>>, MultiProgress)> {
335 let fallback_relays = &self 336 let fallback_relays = &self
@@ -504,7 +505,7 @@ impl Connect for Client {
504 request: FetchRequest, 505 request: FetchRequest,
505 pb: &Option<ProgressBar>, 506 pb: &Option<ProgressBar>,
506 ) -> Result<FetchReport> { 507 ) -> Result<FetchReport> {
507 let mut fresh_coordinates: HashSet<Coordinate> = HashSet::new(); 508 let mut fresh_coordinates: HashSet<Nip19Coordinate> = HashSet::new();
508 for (c, _) in request.repo_coordinates_without_relays.clone() { 509 for (c, _) in request.repo_coordinates_without_relays.clone() {
509 fresh_coordinates.insert(c); 510 fresh_coordinates.insert(c);
510 } 511 }
@@ -617,8 +618,8 @@ async fn get_events_of(
617 618
618 if !relay.is_connected() { 619 if !relay.is_connected() {
619 #[allow(clippy::large_futures)] 620 #[allow(clippy::large_futures)]
620 relay 621 let _ = relay
621 .connect(Some(std::time::Duration::from_secs(CONNECTION_TIMEOUT))) 622 .try_connect(std::time::Duration::from_secs(CONNECTION_TIMEOUT))
622 .await; 623 .await;
623 } 624 }
624 625
@@ -627,16 +628,27 @@ async fn get_events_of(
627 } else if let Some(pb) = pb { 628 } else if let Some(pb) = pb {
628 pb.set_prefix(format!("connected {}", relay.url())); 629 pb.set_prefix(format!("connected {}", relay.url()));
629 } 630 }
630 let events = relay 631
631 .fetch_events( 632 let events_res = join_all(filters.into_iter().map(|filter| async {
632 filters, 633 relay
633 // 20 is nostr_sdk default 634 .fetch_events(
634 std::time::Duration::from_secs(GET_EVENTS_TIMEOUT), 635 filter,
635 nostr_sdk::FilterOptions::ExitOnEOSE, 636 // 20 is nostr_sdk default
636 ) 637 std::time::Duration::from_secs(GET_EVENTS_TIMEOUT),
637 .await? 638 ReqExitPolicy::ExitOnEOSE,
638 .to_vec(); 639 )
639 Ok(events) 640 .await
641 }))
642 .await;
643
644 // no Event is being mutated, just new items added to the set
645 #[allow(clippy::mutable_key_type)]
646 let mut events: HashSet<Event> = HashSet::new();
647
648 for res in events_res {
649 events.extend(res?);
650 }
651 Ok(events.into_iter().collect())
640} 652}
641 653
642#[derive(Default)] 654#[derive(Default)]
@@ -770,50 +782,81 @@ pub async fn get_events_from_local_cache(
770 git_repo_path: &Path, 782 git_repo_path: &Path,
771 filters: Vec<nostr::Filter>, 783 filters: Vec<nostr::Filter>,
772) -> Result<Vec<nostr::Event>> { 784) -> Result<Vec<nostr::Event>> {
773 Ok(get_local_cache_database(git_repo_path) 785 let db = get_local_cache_database(git_repo_path).await?;
774 .await? 786
775 .query(filters.clone()) 787 let query_results = join_all(filters.into_iter().map(|filter| async {
776 .await 788 db.query(filter)
777 .context( 789 .await
778 "failed to execute query on opened git repo nostr cache database .git/nostr-cache.lmdb", 790 .context("failed to execute query on opened ngit nostr cache database")
779 )? 791 }))
780 .to_vec()) 792 .await;
793
794 // no Event is being mutated, just new items added to the set
795 #[allow(clippy::mutable_key_type)]
796 let mut events: HashSet<Event> = HashSet::new();
797
798 for result in query_results {
799 events.extend(result?);
800 }
801
802 Ok(events.into_iter().collect())
781} 803}
782 804
783pub async fn get_event_from_global_cache( 805pub async fn get_event_from_global_cache(
784 git_repo_path: Option<&Path>, 806 git_repo_path: Option<&Path>,
785 filters: Vec<nostr::Filter>, 807 filters: Vec<nostr::Filter>,
786) -> Result<Vec<nostr::Event>> { 808) -> Result<Vec<nostr::Event>> {
787 Ok(get_global_cache_database(git_repo_path) 809 let db = get_global_cache_database(git_repo_path).await?;
788 .await? 810
789 .query(filters.clone()) 811 let query_results = join_all(filters.into_iter().map(|filter| async {
790 .await 812 db.query(filter)
791 .context("failed to execute query on opened ngit nostr cache database")? 813 .await
792 .to_vec()) 814 .context("failed to execute query on opened ngit nostr cache database")
815 }))
816 .await;
817
818 // no Event is being mutated, just new items added to the set
819 #[allow(clippy::mutable_key_type)]
820 let mut events: HashSet<Event> = HashSet::new();
821
822 for result in query_results {
823 events.extend(result?);
824 }
825
826 Ok(events.into_iter().collect())
793} 827}
794 828
795pub async fn save_event_in_local_cache(git_repo_path: &Path, event: &nostr::Event) -> Result<bool> { 829pub async fn save_event_in_local_cache(git_repo_path: &Path, event: &nostr::Event) -> Result<bool> {
796 get_local_cache_database(git_repo_path) 830 match get_local_cache_database(git_repo_path)
797 .await? 831 .await?
798 .save_event(event) 832 .save_event(event)
799 .await 833 .await
800 .context("failed to save event in local cache") 834 .context("failed to save event in local cache")?
835 {
836 SaveEventStatus::Success => Ok(true),
837 _ => Ok(false),
838 }
801} 839}
802 840
803pub async fn save_event_in_global_cache( 841pub async fn save_event_in_global_cache(
804 git_repo_path: Option<&Path>, 842 git_repo_path: Option<&Path>,
805 event: &nostr::Event, 843 event: &nostr::Event,
806) -> Result<bool> { 844) -> Result<bool> {
807 get_global_cache_database(git_repo_path) 845 match get_global_cache_database(git_repo_path)
808 .await? 846 .await?
809 .save_event(event) 847 .save_event(event)
810 .await 848 .await
811 .context("failed to save event in local cache") 849 .context("failed to save event in local cache")
850 {
851 Ok(SaveEventStatus::Success) => Ok(true),
852 Ok(_) => Ok(false),
853 Err(e) => Err(e).context("failed to save event in local cache"),
854 }
812} 855}
813 856
814pub async fn get_repo_ref_from_cache( 857pub async fn get_repo_ref_from_cache(
815 git_repo_path: Option<&Path>, 858 git_repo_path: Option<&Path>,
816 repo_coordinate: &Coordinate, 859 repo_coordinate: &Nip19Coordinate,
817) -> Result<RepoRef> { 860) -> Result<RepoRef> {
818 let mut maintainers = HashSet::new(); 861 let mut maintainers = HashSet::new();
819 let mut new_coordinate: bool; 862 let mut new_coordinate: bool;
@@ -824,10 +867,12 @@ pub async fn get_repo_ref_from_cache(
824 new_coordinate = false; 867 new_coordinate = false;
825 let repo_events_filter = 868 let repo_events_filter =
826 get_filter_repo_events(&HashSet::from_iter(maintainers.iter().map(|m| { 869 get_filter_repo_events(&HashSet::from_iter(maintainers.iter().map(|m| {
827 Coordinate { 870 Nip19Coordinate {
828 kind: Kind::GitRepoAnnouncement, 871 coordinate: Coordinate {
829 public_key: *m, 872 kind: Kind::GitRepoAnnouncement,
830 identifier: repo_coordinate.identifier.to_string(), 873 public_key: *m,
874 identifier: repo_coordinate.identifier.to_string(),
875 },
831 relays: vec![], 876 relays: vec![],
832 } 877 }
833 }))); 878 })));
@@ -859,19 +904,21 @@ pub async fn get_repo_ref_from_cache(
859 let repo_ref = RepoRef::try_from(( 904 let repo_ref = RepoRef::try_from((
860 repo_events 905 repo_events
861 .first() 906 .first()
862 .context("no repo announcement event found at specified coordinates. if you are the repository maintainer consider running `ngit init` to create one")? 907 .context("no repo announcement event found at specified Nip19Coordinates. if you are the repository maintainer consider running `ngit init` to create one")?
863 .clone(), 908 .clone(),
864 Some(repo_coordinate.public_key), 909 Some(repo_coordinate.public_key),
865 ))?; 910 ))?;
866 911
867 let mut events: HashMap<Coordinate, nostr::Event> = HashMap::new(); 912 let mut events: HashMap<Nip19Coordinate, nostr::Event> = HashMap::new();
868 for m in &maintainers { 913 for m in &maintainers {
869 if let Some(e) = repo_events.iter().find(|e| e.pubkey.eq(m)) { 914 if let Some(e) = repo_events.iter().find(|e| e.pubkey.eq(m)) {
870 events.insert( 915 events.insert(
871 Coordinate { 916 Nip19Coordinate {
872 kind: e.kind, 917 coordinate: Coordinate {
873 identifier: e.tags.identifier().unwrap().to_string(), 918 kind: e.kind,
874 public_key: e.pubkey, 919 identifier: e.tags.identifier().unwrap().to_string(),
920 public_key: e.pubkey,
921 },
875 relays: vec![], 922 relays: vec![],
876 }, 923 },
877 e.clone(), 924 e.clone(),
@@ -912,7 +959,7 @@ pub async fn get_state_from_cache(
912#[allow(clippy::too_many_lines)] 959#[allow(clippy::too_many_lines)]
913async fn create_relays_request( 960async fn create_relays_request(
914 git_repo_path: Option<&Path>, 961 git_repo_path: Option<&Path>,
915 trusted_maintainer_coordinate: Option<&Coordinate>, 962 trusted_maintainer_coordinate: Option<&Nip19Coordinate>,
916 user_profiles: &HashSet<PublicKey>, 963 user_profiles: &HashSet<PublicKey>,
917 fallback_relays: HashSet<RelayUrl>, 964 fallback_relays: HashSet<RelayUrl>,
918) -> Result<FetchRequest> { 965) -> Result<FetchRequest> {
@@ -929,9 +976,9 @@ async fn create_relays_request(
929 }; 976 };
930 977
931 let repo_coordinates = { 978 let repo_coordinates = {
932 // add coordinates of users listed in maintainers to explicitly specified 979 // add Nip19Coordinates of users listed in maintainers to explicitly
933 // coodinates 980 // specified coodinates
934 let mut set: HashSet<Coordinate> = HashSet::new(); 981 let mut set: HashSet<Nip19Coordinate> = HashSet::new();
935 if let Some(trusted_maintainer_coordinate) = trusted_maintainer_coordinate { 982 if let Some(trusted_maintainer_coordinate) = trusted_maintainer_coordinate {
936 set.insert(trusted_maintainer_coordinate.clone()); 983 set.insert(trusted_maintainer_coordinate.clone());
937 } 984 }
@@ -951,10 +998,12 @@ async fn create_relays_request(
951 let repo_coordinates_without_relays = { 998 let repo_coordinates_without_relays = {
952 let mut set = HashSet::new(); 999 let mut set = HashSet::new();
953 for c in &repo_coordinates { 1000 for c in &repo_coordinates {
954 set.insert(Coordinate { 1001 set.insert(Nip19Coordinate {
955 kind: c.kind, 1002 coordinate: Coordinate {
956 identifier: c.identifier.clone(), 1003 kind: c.kind,
957 public_key: c.public_key, 1004 identifier: c.identifier.clone(),
1005 public_key: c.public_key,
1006 },
958 relays: vec![], 1007 relays: vec![],
959 }); 1008 });
960 } 1009 }
@@ -976,11 +1025,11 @@ async fn create_relays_request(
976 for event in &get_events_from_local_cache(git_repo_path, vec![ 1025 for event in &get_events_from_local_cache(git_repo_path, vec![
977 nostr::Filter::default() 1026 nostr::Filter::default()
978 .kinds(vec![Kind::GitPatch]) 1027 .kinds(vec![Kind::GitPatch])
979 .custom_tag( 1028 .custom_tags(
980 SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), 1029 SingleLetterTag::lowercase(nostr_sdk::Alphabet::A),
981 repo_coordinates_without_relays 1030 repo_coordinates_without_relays
982 .iter() 1031 .iter()
983 .map(std::string::ToString::to_string) 1032 .map(|c| c.coordinate.to_string())
984 .collect::<Vec<String>>(), 1033 .collect::<Vec<String>>(),
985 ), 1034 ),
986 ]) 1035 ])
@@ -1153,7 +1202,7 @@ async fn process_fetched_events(
1153 events: Vec<nostr::Event>, 1202 events: Vec<nostr::Event>,
1154 request: &FetchRequest, 1203 request: &FetchRequest,
1155 git_repo_path: Option<&Path>, 1204 git_repo_path: Option<&Path>,
1156 fresh_coordinates: &mut HashSet<Coordinate>, 1205 fresh_coordinates: &mut HashSet<Nip19Coordinate>,
1157 fresh_proposal_roots: &mut HashSet<EventId>, 1206 fresh_proposal_roots: &mut HashSet<EventId>,
1158 fresh_profiles: &mut HashSet<PublicKey>, 1207 fresh_profiles: &mut HashSet<PublicKey>,
1159 report: &mut FetchReport, 1208 report: &mut FetchReport,
@@ -1188,10 +1237,12 @@ async fn process_fetched_events(
1188 }); 1237 });
1189 if update_to_existing { 1238 if update_to_existing {
1190 report.updated_repo_announcements.push(( 1239 report.updated_repo_announcements.push((
1191 Coordinate { 1240 Nip19Coordinate {
1192 kind: event.kind, 1241 coordinate: Coordinate {
1193 public_key: event.pubkey, 1242 kind: event.kind,
1194 identifier: event.tags.identifier().unwrap().to_owned(), 1243 public_key: event.pubkey,
1244 identifier: event.tags.identifier().unwrap().to_owned(),
1245 },
1195 relays: vec![], 1246 relays: vec![],
1196 }, 1247 },
1197 event.created_at, 1248 event.created_at,
@@ -1204,14 +1255,16 @@ async fn process_fetched_events(
1204 .repo_coordinates_without_relays // prexisting maintainers 1255 .repo_coordinates_without_relays // prexisting maintainers
1205 .iter() 1256 .iter()
1206 .map(|(c, _)| c.clone()) 1257 .map(|(c, _)| c.clone())
1207 .collect::<HashSet<Coordinate>>() 1258 .collect::<HashSet<Nip19Coordinate>>()
1208 .union(&report.repo_coordinates_without_relays) // already added maintainers 1259 .union(&report.repo_coordinates_without_relays) // already added maintainers
1209 .any(|c| c.identifier.eq(&repo_ref.identifier) && m.eq(&c.public_key)) 1260 .any(|c| c.identifier.eq(&repo_ref.identifier) && m.eq(&c.public_key))
1210 { 1261 {
1211 let c = Coordinate { 1262 let c = Nip19Coordinate {
1212 kind: event.kind, 1263 coordinate: Coordinate {
1213 public_key: *m, 1264 kind: event.kind,
1214 identifier: repo_ref.identifier.clone(), 1265 public_key: *m,
1266 identifier: repo_ref.identifier.clone(),
1267 },
1215 relays: vec![], 1268 relays: vec![],
1216 }; 1269 };
1217 fresh_coordinates.insert(c.clone()); 1270 fresh_coordinates.insert(c.clone());
@@ -1343,7 +1396,7 @@ pub fn consolidate_fetch_reports(reports: Vec<Result<FetchReport>>) -> FetchRepo
1343 report 1396 report
1344} 1397}
1345pub fn get_fetch_filters( 1398pub fn get_fetch_filters(
1346 repo_coordinates: &HashSet<Coordinate>, 1399 repo_coordinates: &HashSet<Nip19Coordinate>,
1347 proposal_ids: &HashSet<EventId>, 1400 proposal_ids: &HashSet<EventId>,
1348 required_profiles: &HashSet<PublicKey>, 1401 required_profiles: &HashSet<PublicKey>,
1349) -> Vec<nostr::Filter> { 1402) -> Vec<nostr::Filter> {
@@ -1356,11 +1409,11 @@ pub fn get_fetch_filters(
1356 get_filter_repo_events(repo_coordinates), 1409 get_filter_repo_events(repo_coordinates),
1357 nostr::Filter::default() 1410 nostr::Filter::default()
1358 .kinds(vec![Kind::GitPatch, Kind::EventDeletion]) 1411 .kinds(vec![Kind::GitPatch, Kind::EventDeletion])
1359 .custom_tag( 1412 .custom_tags(
1360 SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), 1413 SingleLetterTag::lowercase(nostr_sdk::Alphabet::A),
1361 repo_coordinates 1414 repo_coordinates
1362 .iter() 1415 .iter()
1363 .map(std::string::ToString::to_string) 1416 .map(|c| c.coordinate.to_string())
1364 .collect::<Vec<String>>(), 1417 .collect::<Vec<String>>(),
1365 ), 1418 ),
1366 ] 1419 ]
@@ -1383,7 +1436,7 @@ pub fn get_fetch_filters(
1383 .concat() 1436 .concat()
1384} 1437}
1385 1438
1386pub fn get_filter_repo_events(repo_coordinates: &HashSet<Coordinate>) -> nostr::Filter { 1439pub fn get_filter_repo_events(repo_coordinates: &HashSet<Nip19Coordinate>) -> nostr::Filter {
1387 nostr::Filter::default() 1440 nostr::Filter::default()
1388 .kind(Kind::GitRepoAnnouncement) 1441 .kind(Kind::GitRepoAnnouncement)
1389 .identifiers( 1442 .identifiers(
@@ -1401,7 +1454,7 @@ pub fn get_filter_repo_events(repo_coordinates: &HashSet<Coordinate>) -> nostr::
1401} 1454}
1402 1455
1403pub static STATE_KIND: nostr::Kind = Kind::Custom(30618); 1456pub static STATE_KIND: nostr::Kind = Kind::Custom(30618);
1404pub fn get_filter_state_events(repo_coordinates: &HashSet<Coordinate>) -> nostr::Filter { 1457pub fn get_filter_state_events(repo_coordinates: &HashSet<Nip19Coordinate>) -> nostr::Filter {
1405 nostr::Filter::default() 1458 nostr::Filter::default()
1406 .kind(STATE_KIND) 1459 .kind(STATE_KIND)
1407 .identifiers( 1460 .identifiers(
@@ -1426,8 +1479,8 @@ pub fn get_filter_contributor_profiles(contributors: HashSet<PublicKey>) -> nost
1426 1479
1427#[derive(Default)] 1480#[derive(Default)]
1428pub struct FetchReport { 1481pub struct FetchReport {
1429 repo_coordinates_without_relays: HashSet<Coordinate>, 1482 repo_coordinates_without_relays: HashSet<Nip19Coordinate>,
1430 updated_repo_announcements: Vec<(Coordinate, Timestamp)>, 1483 updated_repo_announcements: Vec<(Nip19Coordinate, Timestamp)>,
1431 updated_state: Option<(Timestamp, EventId)>, 1484 updated_state: Option<(Timestamp, EventId)>,
1432 proposals: HashSet<EventId>, 1485 proposals: HashSet<EventId>,
1433 /// commits against existing propoals 1486 /// commits against existing propoals
@@ -1518,7 +1571,7 @@ pub struct FetchRequest {
1518 repo_relays: HashSet<RelayUrl>, 1571 repo_relays: HashSet<RelayUrl>,
1519 selected_relay: Option<RelayUrl>, 1572 selected_relay: Option<RelayUrl>,
1520 relay_column_width: usize, 1573 relay_column_width: usize,
1521 repo_coordinates_without_relays: Vec<(Coordinate, Option<Timestamp>)>, 1574 repo_coordinates_without_relays: Vec<(Nip19Coordinate, Option<Timestamp>)>,
1522 state: Option<(Timestamp, EventId)>, 1575 state: Option<(Timestamp, EventId)>,
1523 proposals: HashSet<EventId>, 1576 proposals: HashSet<EventId>,
1524 contributors: HashSet<PublicKey>, 1577 contributors: HashSet<PublicKey>,
@@ -1532,7 +1585,7 @@ pub async fn fetching_with_report(
1532 git_repo_path: &Path, 1585 git_repo_path: &Path,
1533 #[cfg(test)] client: &crate::client::MockConnect, 1586 #[cfg(test)] client: &crate::client::MockConnect,
1534 #[cfg(not(test))] client: &Client, 1587 #[cfg(not(test))] client: &Client,
1535 trusted_maintainer_coordinate: &Coordinate, 1588 trusted_maintainer_coordinate: &Nip19Coordinate,
1536) -> Result<FetchReport> { 1589) -> Result<FetchReport> {
1537 let term = console::Term::stderr(); 1590 let term = console::Term::stderr();
1538 term.write_line("fetching updates...")?; 1591 term.write_line("fetching updates...")?;
@@ -1557,16 +1610,16 @@ pub async fn fetching_with_report(
1557 1610
1558pub async fn get_proposals_and_revisions_from_cache( 1611pub async fn get_proposals_and_revisions_from_cache(
1559 git_repo_path: &Path, 1612 git_repo_path: &Path,
1560 repo_coordinates: HashSet<Coordinate>, 1613 repo_coordinates: HashSet<Nip19Coordinate>,
1561) -> Result<Vec<nostr::Event>> { 1614) -> Result<Vec<nostr::Event>> {
1562 let mut proposals = get_events_from_local_cache(git_repo_path, vec![ 1615 let mut proposals = get_events_from_local_cache(git_repo_path, vec![
1563 nostr::Filter::default() 1616 nostr::Filter::default()
1564 .kind(nostr::Kind::GitPatch) 1617 .kind(nostr::Kind::GitPatch)
1565 .custom_tag( 1618 .custom_tags(
1566 nostr::SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), 1619 nostr::SingleLetterTag::lowercase(nostr_sdk::Alphabet::A),
1567 repo_coordinates 1620 repo_coordinates
1568 .iter() 1621 .iter()
1569 .map(std::string::ToString::to_string) 1622 .map(|c| c.coordinate.to_string())
1570 .collect::<Vec<String>>(), 1623 .collect::<Vec<String>>(),
1571 ), 1624 ),
1572 ]) 1625 ])
diff --git a/src/lib/git/mod.rs b/src/lib/git/mod.rs
index 2b78f38..1329820 100644
--- a/src/lib/git/mod.rs
+++ b/src/lib/git/mod.rs
@@ -1141,7 +1141,7 @@ mod tests {
1141 fn test(time: git2::Time) -> Result<()> { 1141 fn test(time: git2::Time) -> Result<()> {
1142 assert_eq!( 1142 assert_eq!(
1143 extract_sig_from_patch_tags( 1143 extract_sig_from_patch_tags(
1144 &Tags::new(vec![nostr::Tag::custom( 1144 &Tags::from_list(vec![nostr::Tag::custom(
1145 nostr::TagKind::Custom("author".to_string().into()), 1145 nostr::TagKind::Custom("author".to_string().into()),
1146 prep(&time)?, 1146 prep(&time)?,
1147 )]), 1147 )]),
diff --git a/src/lib/git/nostr_url.rs b/src/lib/git/nostr_url.rs
index ae0ac5f..54be292 100644
--- a/src/lib/git/nostr_url.rs
+++ b/src/lib/git/nostr_url.rs
@@ -2,8 +2,8 @@ use core::fmt;
2use std::{collections::HashMap, str::FromStr}; 2use std::{collections::HashMap, str::FromStr};
3 3
4use anyhow::{Context, Error, Result, anyhow, bail}; 4use anyhow::{Context, Error, Result, anyhow, bail};
5use nostr::nips::{nip01::Coordinate, nip05}; 5use nostr::nips::{nip01::Coordinate, nip05, nip19::Nip19Coordinate};
6use nostr_sdk::{PublicKey, RelayUrl, ToBech32, Url}; 6use nostr_sdk::{FromBech32, PublicKey, RelayUrl, ToBech32, Url};
7 7
8use super::{Repo, get_git_config_item, save_git_config_item}; 8use super::{Repo, get_git_config_item, save_git_config_item};
9 9
@@ -58,7 +58,7 @@ impl FromStr for ServerProtocol {
58#[derive(Debug, PartialEq, Clone)] 58#[derive(Debug, PartialEq, Clone)]
59pub struct NostrUrlDecoded { 59pub struct NostrUrlDecoded {
60 pub original_string: String, 60 pub original_string: String,
61 pub coordinate: Coordinate, 61 pub coordinate: Nip19Coordinate,
62 pub protocol: Option<ServerProtocol>, 62 pub protocol: Option<ServerProtocol>,
63 pub user: Option<String>, 63 pub user: Option<String>,
64 pub nip05: Option<String>, 64 pub nip05: Option<String>,
@@ -166,7 +166,7 @@ impl NostrUrlDecoded {
166 // extract naddr npub/<optional-relays>/identifer 166 // extract naddr npub/<optional-relays>/identifer
167 let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; 167 let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?;
168 // naddr used 168 // naddr used
169 let coordinate = if let Ok(coordinate) = Coordinate::parse(part) { 169 let coordinate = if let Ok(coordinate) = Nip19Coordinate::from_bech32(part) {
170 if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { 170 if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) {
171 coordinate 171 coordinate
172 } else { 172 } else {
@@ -225,10 +225,12 @@ impl NostrUrlDecoded {
225 } 225 }
226 } 226 }
227 }; 227 };
228 Coordinate { 228 Nip19Coordinate {
229 identifier, 229 coordinate: Coordinate {
230 public_key, 230 identifier,
231 kind: nostr_sdk::Kind::GitRepoAnnouncement, 231 public_key,
232 kind: nostr_sdk::Kind::GitRepoAnnouncement,
233 },
232 relays, 234 relays,
233 } 235 }
234 }; 236 };
@@ -959,7 +961,7 @@ mod tests {
959 } 961 }
960 } 962 }
961 mod nostr_git_url_format { 963 mod nostr_git_url_format {
962 use nostr::nips::nip01::Coordinate; 964 use nostr::nips::nip19::Nip19Coordinate;
963 use nostr_sdk::PublicKey; 965 use nostr_sdk::PublicKey;
964 966
965 use super::*; 967 use super::*;
@@ -970,13 +972,15 @@ mod tests {
970 assert_eq!( 972 assert_eq!(
971 format!("{}", NostrUrlDecoded { 973 format!("{}", NostrUrlDecoded {
972 original_string: String::new(), 974 original_string: String::new(),
973 coordinate: Coordinate { 975 coordinate: Nip19Coordinate {
974 identifier: "ngit".to_string(), 976 coordinate: Coordinate {
975 public_key: PublicKey::parse( 977 identifier: "ngit".to_string(),
976 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 978 public_key: PublicKey::parse(
977 ) 979 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
978 .unwrap(), 980 )
979 kind: nostr_sdk::Kind::GitRepoAnnouncement, 981 .unwrap(),
982 kind: nostr_sdk::Kind::GitRepoAnnouncement,
983 },
980 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], 984 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()],
981 }, 985 },
982 protocol: None, 986 protocol: None,
@@ -993,13 +997,15 @@ mod tests {
993 assert_eq!( 997 assert_eq!(
994 format!("{}", NostrUrlDecoded { 998 format!("{}", NostrUrlDecoded {
995 original_string: String::new(), 999 original_string: String::new(),
996 coordinate: Coordinate { 1000 coordinate: Nip19Coordinate {
997 identifier: "ngit".to_string(), 1001 coordinate: Coordinate {
998 public_key: PublicKey::parse( 1002 identifier: "ngit".to_string(),
999 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1003 public_key: PublicKey::parse(
1000 ) 1004 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1001 .unwrap(), 1005 )
1002 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1006 .unwrap(),
1007 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1008 },
1003 relays: vec![], 1009 relays: vec![],
1004 }, 1010 },
1005 protocol: None, 1011 protocol: None,
@@ -1016,13 +1022,15 @@ mod tests {
1016 assert_eq!( 1022 assert_eq!(
1017 format!("{}", NostrUrlDecoded { 1023 format!("{}", NostrUrlDecoded {
1018 original_string: String::new(), 1024 original_string: String::new(),
1019 coordinate: Coordinate { 1025 coordinate: Nip19Coordinate {
1020 identifier: "ngit".to_string(), 1026 coordinate: Coordinate {
1021 public_key: PublicKey::parse( 1027 identifier: "ngit".to_string(),
1022 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1028 public_key: PublicKey::parse(
1023 ) 1029 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1024 .unwrap(), 1030 )
1025 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1031 .unwrap(),
1032 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1033 },
1026 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], 1034 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()],
1027 }, 1035 },
1028 protocol: Some(ServerProtocol::Ssh), 1036 protocol: Some(ServerProtocol::Ssh),
@@ -1039,13 +1047,15 @@ mod tests {
1039 assert_eq!( 1047 assert_eq!(
1040 format!("{}", NostrUrlDecoded { 1048 format!("{}", NostrUrlDecoded {
1041 original_string: String::new(), 1049 original_string: String::new(),
1042 coordinate: Coordinate { 1050 coordinate: Nip19Coordinate {
1043 identifier: "ngit".to_string(), 1051 coordinate: Coordinate {
1044 public_key: PublicKey::parse( 1052 identifier: "ngit".to_string(),
1045 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1053 public_key: PublicKey::parse(
1046 ) 1054 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1047 .unwrap(), 1055 )
1048 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1056 .unwrap(),
1057 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1058 },
1049 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], 1059 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()],
1050 }, 1060 },
1051 protocol: Some(ServerProtocol::Ssh), 1061 protocol: Some(ServerProtocol::Ssh),
@@ -1061,14 +1071,16 @@ mod tests {
1061 mod nostr_url_decoded_paramemters_from_str { 1071 mod nostr_url_decoded_paramemters_from_str {
1062 use super::*; 1072 use super::*;
1063 1073
1064 fn get_model_coordinate(relays: bool) -> Coordinate { 1074 fn get_model_coordinate(relays: bool) -> Nip19Coordinate {
1065 Coordinate { 1075 Nip19Coordinate {
1066 identifier: "ngit".to_string(), 1076 coordinate: Coordinate {
1067 public_key: PublicKey::parse( 1077 identifier: "ngit".to_string(),
1068 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1078 public_key: PublicKey::parse(
1069 ) 1079 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1070 .unwrap(), 1080 )
1071 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1081 .unwrap(),
1082 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1083 },
1072 relays: if relays { 1084 relays: if relays {
1073 vec![RelayUrl::parse("wss://nos.lol").unwrap()] 1085 vec![RelayUrl::parse("wss://nos.lol").unwrap()]
1074 } else { 1086 } else {
@@ -1084,13 +1096,15 @@ mod tests {
1084 NostrUrlDecoded::parse_and_resolve(&url, &None).await?, 1096 NostrUrlDecoded::parse_and_resolve(&url, &None).await?,
1085 NostrUrlDecoded { 1097 NostrUrlDecoded {
1086 original_string: url.clone(), 1098 original_string: url.clone(),
1087 coordinate: Coordinate { 1099 coordinate: Nip19Coordinate {
1088 identifier: "ngit".to_string(), 1100 coordinate: Coordinate {
1089 public_key: PublicKey::parse( 1101 identifier: "ngit".to_string(),
1090 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1102 public_key: PublicKey::parse(
1091 ) 1103 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1092 .unwrap(), 1104 )
1093 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1105 .unwrap(),
1106 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1107 },
1094 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], /* wont add the 1108 relays: vec![RelayUrl::parse("wss://nos.lol").unwrap()], /* wont add the
1095 * slash */ 1109 * slash */
1096 }, 1110 },
@@ -1172,13 +1186,15 @@ mod tests {
1172 NostrUrlDecoded::parse_and_resolve(&url, &None).await?, 1186 NostrUrlDecoded::parse_and_resolve(&url, &None).await?,
1173 NostrUrlDecoded { 1187 NostrUrlDecoded {
1174 original_string: url.clone(), 1188 original_string: url.clone(),
1175 coordinate: Coordinate { 1189 coordinate: Nip19Coordinate {
1176 identifier: "ngit".to_string(), 1190 coordinate: Coordinate {
1177 public_key: PublicKey::parse( 1191 identifier: "ngit".to_string(),
1178 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1192 public_key: PublicKey::parse(
1179 ) 1193 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1180 .unwrap(), 1194 )
1181 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1195 .unwrap(),
1196 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1197 },
1182 relays: vec![ 1198 relays: vec![
1183 RelayUrl::parse("wss://nos.lol/").unwrap(), 1199 RelayUrl::parse("wss://nos.lol/").unwrap(),
1184 RelayUrl::parse("wss://relay.damus.io/").unwrap(), 1200 RelayUrl::parse("wss://relay.damus.io/").unwrap(),
@@ -1274,13 +1290,15 @@ mod tests {
1274 NostrUrlDecoded::parse_and_resolve(&url, &None).await?, 1290 NostrUrlDecoded::parse_and_resolve(&url, &None).await?,
1275 NostrUrlDecoded { 1291 NostrUrlDecoded {
1276 original_string: url.clone(), 1292 original_string: url.clone(),
1277 coordinate: Coordinate { 1293 coordinate: Nip19Coordinate {
1278 identifier: "ngit".to_string(), 1294 coordinate: Coordinate {
1279 public_key: PublicKey::parse( 1295 identifier: "ngit".to_string(),
1280 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr", 1296 public_key: PublicKey::parse(
1281 ) 1297 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
1282 .unwrap(), 1298 )
1283 kind: nostr_sdk::Kind::GitRepoAnnouncement, 1299 .unwrap(),
1300 kind: nostr_sdk::Kind::GitRepoAnnouncement,
1301 },
1284 relays: vec![ 1302 relays: vec![
1285 RelayUrl::parse("wss://nos.lol/").unwrap(), 1303 RelayUrl::parse("wss://nos.lol/").unwrap(),
1286 RelayUrl::parse("wss://relay.damus.io/").unwrap(), 1304 RelayUrl::parse("wss://relay.damus.io/").unwrap(),
diff --git a/src/lib/git_events.rs b/src/lib/git_events.rs
index 559155a..2b3df42 100644
--- a/src/lib/git_events.rs
+++ b/src/lib/git_events.rs
@@ -3,7 +3,7 @@ use std::{str::FromStr, sync::Arc};
3use anyhow::{Context, Result, bail}; 3use anyhow::{Context, Result, bail};
4use nostr::nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19}; 4use nostr::nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19};
5use nostr_sdk::{ 5use nostr_sdk::{
6 Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagKind, 6 Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, PublicKey, Tag, TagKind,
7 TagStandard, hashes::sha1::Hash as Sha1Hash, 7 TagStandard, hashes::sha1::Hash as Sha1Hash,
8}; 8};
9 9
@@ -115,11 +115,14 @@ pub async fn generate_patch_event(
115 .maintainers 115 .maintainers
116 .iter() 116 .iter()
117 .map(|m| { 117 .map(|m| {
118 Tag::coordinate(Coordinate { 118 Tag::from_standardized(TagStandard::Coordinate {
119 kind: nostr::Kind::GitRepoAnnouncement, 119 coordinate: Coordinate {
120 public_key: *m, 120 kind: nostr::Kind::GitRepoAnnouncement,
121 identifier: repo_ref.identifier.to_string(), 121 public_key: *m,
122 relays: repo_ref.relays.clone(), 122 identifier: repo_ref.identifier.to_string(),
123 },
124 relay_url: repo_ref.relays.first().cloned(),
125 uppercase: false,
123 }) 126 })
124 }) 127 })
125 .collect::<Vec<Tag>>(), 128 .collect::<Vec<Tag>>(),
@@ -257,12 +260,12 @@ pub fn event_tag_from_nip19_or_hex(
257 PromptInputParms::default().with_prompt(format!("{reference_name} reference")), 260 PromptInputParms::default().with_prompt(format!("{reference_name} reference")),
258 )?; 261 )?;
259 } 262 }
260 if let Ok(nip19) = Nip19::from_bech32(bech32.clone()) { 263 if let Ok(nip19) = Nip19::from_bech32(&bech32) {
261 match nip19 { 264 match nip19 {
262 Nip19::Event(n) => { 265 Nip19::Event(n) => {
263 break Ok(Tag::from_standardized(nostr_sdk::TagStandard::Event { 266 break Ok(Tag::from_standardized(nostr_sdk::TagStandard::Event {
264 event_id: n.event_id, 267 event_id: n.event_id,
265 relay_url: n.relays.first().and_then(|url| RelayUrl::parse(url).ok()), 268 relay_url: n.relays.first().cloned(),
266 marker: Some(marker), 269 marker: Some(marker),
267 public_key: None, 270 public_key: None,
268 uppercase: false, 271 uppercase: false,
@@ -278,7 +281,11 @@ pub fn event_tag_from_nip19_or_hex(
278 })); 281 }));
279 } 282 }
280 Nip19::Coordinate(coordinate) => { 283 Nip19::Coordinate(coordinate) => {
281 break Ok(Tag::coordinate(coordinate)); 284 break Ok(Tag::from_standardized(TagStandard::Coordinate {
285 coordinate: coordinate.coordinate,
286 relay_url: coordinate.relays.first().cloned(),
287 uppercase: false,
288 }));
282 } 289 }
283 Nip19::Profile(profile) => { 290 Nip19::Profile(profile) => {
284 if allow_npub_reference { 291 if allow_npub_reference {
@@ -338,12 +345,17 @@ pub async fn generate_cover_letter_and_patch_events(
338 )) 345 ))
339 .tags( 346 .tags(
340 [ 347 [
341 repo_ref.maintainers.iter().map(|m| Tag::coordinate(Coordinate { 348 repo_ref.maintainers.iter().map(|m|
342 kind: nostr::Kind::GitRepoAnnouncement, 349 Tag::from_standardized(TagStandard::Coordinate {
343 public_key: *m, 350 coordinate: Coordinate {
344 identifier: repo_ref.identifier.to_string(), 351 kind: nostr::Kind::GitRepoAnnouncement,
345 relays: repo_ref.relays.clone(), 352 public_key: *m,
346 })).collect::<Vec<Tag>>(), 353 identifier: repo_ref.identifier.to_string(),
354 },
355 relay_url: repo_ref.relays.first().cloned(),
356 uppercase: false,
357 })
358 ).collect::<Vec<Tag>>(),
347 vec![ 359 vec![
348 Tag::from_standardized(TagStandard::Reference(format!("{root_commit}"))), 360 Tag::from_standardized(TagStandard::Reference(format!("{root_commit}"))),
349 Tag::hashtag("cover-letter"), 361 Tag::hashtag("cover-letter"),
diff --git a/src/lib/login/existing.rs b/src/lib/login/existing.rs
index efe187e..e60621d 100644
--- a/src/lib/login/existing.rs
+++ b/src/lib/login/existing.rs
@@ -208,7 +208,7 @@ async fn get_signer(
208 Duration::from_secs(10 * 60), 208 Duration::from_secs(10 * 60),
209 None, 209 None,
210 )?; 210 )?;
211 if let Some(public_key) = npub.clone().and_then(|npub| PublicKey::parse(npub).ok()) { 211 if let Some(public_key) = npub.clone().and_then(|npub| PublicKey::parse(&npub).ok()) {
212 s.non_secure_set_user_public_key(public_key)?; 212 s.non_secure_set_user_public_key(public_key)?;
213 let signer: Arc<dyn NostrSigner> = Arc::new(s); 213 let signer: Arc<dyn NostrSigner> = Arc::new(s);
214 Ok((signer, public_key)) 214 Ok((signer, public_key))
diff --git a/src/lib/login/fresh.rs b/src/lib/login/fresh.rs
index 635c0b3..76998ff 100644
--- a/src/lib/login/fresh.rs
+++ b/src/lib/login/fresh.rs
@@ -372,7 +372,7 @@ pub fn generate_nostr_connect_app(
372 client 372 client
373 .get_fallback_signer_relays() 373 .get_fallback_signer_relays()
374 .iter() 374 .iter()
375 .flat_map(RelayUrl::parse) 375 .flat_map(|s| RelayUrl::parse(s))
376 .collect::<Vec<RelayUrl>>() 376 .collect::<Vec<RelayUrl>>()
377 } else { 377 } else {
378 vec![] 378 vec![]
diff --git a/src/lib/login/key_encryption.rs b/src/lib/login/key_encryption.rs
index efb38d1..d57b3b5 100644
--- a/src/lib/login/key_encryption.rs
+++ b/src/lib/login/key_encryption.rs
@@ -7,7 +7,7 @@ pub fn decrypt_key(encrypted_key: &str, password: &str) -> Result<nostr::Keys> {
7 if encrypted_key.log_n() > 14 { 7 if encrypted_key.log_n() > 14 {
8 println!("this may take a few seconds..."); 8 println!("this may take a few seconds...");
9 } 9 }
10 Ok(nostr::Keys::new(encrypted_key.to_secret_key(password)?)) 10 Ok(nostr::Keys::new(encrypted_key.decrypt(password)?))
11} 11}
12 12
13#[cfg(test)] 13#[cfg(test)]
diff --git a/src/lib/login/mod.rs b/src/lib/login/mod.rs
index a1c45d5..c37375f 100644
--- a/src/lib/login/mod.rs
+++ b/src/lib/login/mod.rs
@@ -93,7 +93,7 @@ pub async fn get_likely_logged_in_user(git_repo_path: &Path) -> Result<Option<Pu
93 let git_repo = Repo::from_path(&git_repo_path.to_path_buf())?; 93 let git_repo = Repo::from_path(&git_repo_path.to_path_buf())?;
94 Ok( 94 Ok(
95 if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { 95 if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? {
96 if let Ok(pubic_key) = PublicKey::parse(npub) { 96 if let Ok(pubic_key) = PublicKey::parse(&npub) {
97 Some(pubic_key) 97 Some(pubic_key)
98 } else { 98 } else {
99 None 99 None
@@ -107,7 +107,7 @@ pub async fn get_likely_logged_in_user(git_repo_path: &Path) -> Result<Option<Pu
107pub fn get_curent_user(git_repo: &Repo) -> Result<Option<PublicKey>> { 107pub fn get_curent_user(git_repo: &Repo) -> Result<Option<PublicKey>> {
108 Ok( 108 Ok(
109 if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? { 109 if let Some(npub) = git_repo.get_git_config_item("nostr.npub", None)? {
110 if let Ok(public_key) = PublicKey::parse(npub) { 110 if let Ok(public_key) = PublicKey::parse(&npub) {
111 Some(public_key) 111 Some(public_key)
112 } else { 112 } else {
113 None 113 None
diff --git a/src/lib/repo_ref.rs b/src/lib/repo_ref.rs
index 38f6774..b21a911 100644
--- a/src/lib/repo_ref.rs
+++ b/src/lib/repo_ref.rs
@@ -8,7 +8,10 @@ use std::{
8 8
9use anyhow::{Context, Result, bail}; 9use anyhow::{Context, Result, bail};
10use console::Style; 10use console::Style;
11use nostr::{FromBech32, PublicKey, Tag, TagStandard, ToBech32, nips::nip01::Coordinate}; 11use nostr::{
12 FromBech32, PublicKey, Tag, TagStandard, ToBech32,
13 nips::{nip01::Coordinate, nip19::Nip19Coordinate},
14};
12use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp}; 15use nostr_sdk::{Kind, NostrSigner, RelayUrl, Timestamp};
13use serde::{Deserialize, Serialize}; 16use serde::{Deserialize, Serialize};
14 17
@@ -37,7 +40,7 @@ pub struct RepoRef {
37 pub relays: Vec<RelayUrl>, 40 pub relays: Vec<RelayUrl>,
38 pub maintainers: Vec<PublicKey>, 41 pub maintainers: Vec<PublicKey>,
39 pub trusted_maintainer: PublicKey, 42 pub trusted_maintainer: PublicKey,
40 pub events: HashMap<Coordinate, nostr::Event>, 43 pub events: HashMap<Nip19Coordinate, nostr::Event>,
41 pub nostr_git_url: Option<NostrUrlDecoded>, 44 pub nostr_git_url: Option<NostrUrlDecoded>,
42} 45}
43 46
@@ -119,10 +122,12 @@ impl TryFrom<(nostr::Event, Option<PublicKey>)> for RepoRef {
119 } 122 }
120 r.events = HashMap::new(); 123 r.events = HashMap::new();
121 r.events.insert( 124 r.events.insert(
122 Coordinate { 125 Nip19Coordinate {
123 kind: event.kind, 126 coordinate: Coordinate {
124 identifier: event.tags.identifier().unwrap().to_string(), 127 kind: event.kind,
125 public_key: event.pubkey, 128 identifier: event.tags.identifier().unwrap().to_string(),
129 public_key: event.pubkey,
130 },
126 relays: vec![], 131 relays: vec![],
127 }, 132 },
128 event, 133 event,
@@ -195,20 +200,24 @@ impl RepoRef {
195 .context("failed to create repository reference event") 200 .context("failed to create repository reference event")
196 } 201 }
197 /// coordinates without relay hints 202 /// coordinates without relay hints
198 pub fn coordinates(&self) -> HashSet<Coordinate> { 203 pub fn coordinates(&self) -> HashSet<Nip19Coordinate> {
199 let mut res = HashSet::new(); 204 let mut res = HashSet::new();
200 res.insert(Coordinate { 205 res.insert(Nip19Coordinate {
201 kind: Kind::GitRepoAnnouncement, 206 coordinate: Coordinate {
202 public_key: self.trusted_maintainer, 207 kind: Kind::GitRepoAnnouncement,
203 identifier: self.identifier.clone(), 208 public_key: self.trusted_maintainer,
209 identifier: self.identifier.clone(),
210 },
204 relays: vec![], 211 relays: vec![],
205 }); 212 });
206 213
207 for m in &self.maintainers { 214 for m in &self.maintainers {
208 res.insert(Coordinate { 215 res.insert(Nip19Coordinate {
209 kind: Kind::GitRepoAnnouncement, 216 coordinate: Coordinate {
210 public_key: *m, 217 kind: Kind::GitRepoAnnouncement,
211 identifier: self.identifier.clone(), 218 public_key: *m,
219 identifier: self.identifier.clone(),
220 },
212 relays: vec![], 221 relays: vec![],
213 }); 222 });
214 } 223 }
@@ -216,11 +225,13 @@ impl RepoRef {
216 } 225 }
217 226
218 /// coordinates without relay hints 227 /// coordinates without relay hints
219 pub fn coordinate_with_hint(&self) -> Coordinate { 228 pub fn coordinate_with_hint(&self) -> Nip19Coordinate {
220 Coordinate { 229 Nip19Coordinate {
221 kind: Kind::GitRepoAnnouncement, 230 coordinate: Coordinate {
222 public_key: self.trusted_maintainer, 231 kind: Kind::GitRepoAnnouncement,
223 identifier: self.identifier.clone(), 232 public_key: self.trusted_maintainer,
233 identifier: self.identifier.clone(),
234 },
224 relays: if let Some(relay) = self.relays.first() { 235 relays: if let Some(relay) = self.relays.first() {
225 vec![relay.clone()] 236 vec![relay.clone()]
226 } else { 237 } else {
@@ -230,11 +241,11 @@ impl RepoRef {
230 } 241 }
231 242
232 /// coordinates without relay hints 243 /// coordinates without relay hints
233 pub fn coordinates_with_timestamps(&self) -> Vec<(Coordinate, Option<Timestamp>)> { 244 pub fn coordinates_with_timestamps(&self) -> Vec<(Nip19Coordinate, Option<Timestamp>)> {
234 self.coordinates() 245 self.coordinates()
235 .iter() 246 .iter()
236 .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at))) 247 .map(|c| (c.clone(), self.events.get(c).map(|e| e.created_at)))
237 .collect::<Vec<(Coordinate, Option<Timestamp>)>>() 248 .collect::<Vec<(Nip19Coordinate, Option<Timestamp>)>>()
238 } 249 }
239 250
240 pub fn set_nostr_git_url(&mut self, nostr_git_url: NostrUrlDecoded) { 251 pub fn set_nostr_git_url(&mut self, nostr_git_url: NostrUrlDecoded) {
@@ -264,7 +275,7 @@ pub async fn get_repo_coordinates_when_remote_unknown(
264 git_repo: &Repo, 275 git_repo: &Repo,
265 #[cfg(test)] client: &crate::client::MockConnect, 276 #[cfg(test)] client: &crate::client::MockConnect,
266 #[cfg(not(test))] client: &Client, 277 #[cfg(not(test))] client: &Client,
267) -> Result<Coordinate> { 278) -> Result<Nip19Coordinate> {
268 if let Ok(c) = try_and_get_repo_coordinates_when_remote_unknown(git_repo).await { 279 if let Ok(c) = try_and_get_repo_coordinates_when_remote_unknown(git_repo).await {
269 Ok(c) 280 Ok(c)
270 } else { 281 } else {
@@ -274,7 +285,7 @@ pub async fn get_repo_coordinates_when_remote_unknown(
274 285
275pub async fn try_and_get_repo_coordinates_when_remote_unknown( 286pub async fn try_and_get_repo_coordinates_when_remote_unknown(
276 git_repo: &Repo, 287 git_repo: &Repo,
277) -> Result<Coordinate> { 288) -> Result<Nip19Coordinate> {
278 let remote_coordinates = get_repo_coordinates_from_nostr_remotes(git_repo).await?; 289 let remote_coordinates = get_repo_coordinates_from_nostr_remotes(git_repo).await?;
279 if remote_coordinates.is_empty() { 290 if remote_coordinates.is_empty() {
280 if let Ok(c) = get_repo_coordinates_from_git_config(git_repo) { 291 if let Ok(c) = get_repo_coordinates_from_git_config(git_repo) {
@@ -318,7 +329,7 @@ pub async fn try_and_get_repo_coordinates_when_remote_unknown(
318 329
319async fn get_nostr_git_remote_selection_labels( 330async fn get_nostr_git_remote_selection_labels(
320 git_repo: &Repo, 331 git_repo: &Repo,
321 remote_coordinates: &HashMap<String, Coordinate>, 332 remote_coordinates: &HashMap<String, Nip19Coordinate>,
322) -> Result<Vec<String>> { 333) -> Result<Vec<String>> {
323 let mut res = vec![]; 334 let mut res = vec![];
324 for (remote, c) in remote_coordinates { 335 for (remote, c) in remote_coordinates {
@@ -334,9 +345,9 @@ async fn get_nostr_git_remote_selection_labels(
334 Ok(res) 345 Ok(res)
335} 346}
336 347
337fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Coordinate> { 348fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Nip19Coordinate> {
338 Coordinate::parse( 349 Nip19Coordinate::from_bech32(
339 git_repo 350 &git_repo
340 .get_git_config_item("nostr.repo", Some(false))? 351 .get_git_config_item("nostr.repo", Some(false))?
341 .context("git config item \"nostr.repo\" is not set in local repository")?, 352 .context("git config item \"nostr.repo\" is not set in local repository")?,
342 ) 353 )
@@ -345,7 +356,7 @@ fn get_repo_coordinates_from_git_config(git_repo: &Repo) -> Result<Coordinate> {
345 356
346async fn get_repo_coordinates_from_nostr_remotes( 357async fn get_repo_coordinates_from_nostr_remotes(
347 git_repo: &Repo, 358 git_repo: &Repo,
348) -> Result<HashMap<String, Coordinate>> { 359) -> Result<HashMap<String, Nip19Coordinate>> {
349 let mut repo_coordinates = HashMap::new(); 360 let mut repo_coordinates = HashMap::new();
350 for remote_name in git_repo.git_repo.remotes()?.iter().flatten() { 361 for remote_name in git_repo.git_repo.remotes()?.iter().flatten() {
351 if let Some(remote_url) = git_repo.git_repo.find_remote(remote_name)?.url() { 362 if let Some(remote_url) = git_repo.git_repo.find_remote(remote_name)?.url() {
@@ -359,21 +370,23 @@ async fn get_repo_coordinates_from_nostr_remotes(
359 Ok(repo_coordinates) 370 Ok(repo_coordinates)
360} 371}
361 372
362async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result<Coordinate> { 373async fn get_repo_coordinates_from_maintainers_yaml(git_repo: &Repo) -> Result<Nip19Coordinate> {
363 let repo_config = get_repo_config_from_yaml(git_repo)?; 374 let repo_config = get_repo_config_from_yaml(git_repo)?;
364 375
365 Ok(Coordinate { 376 Ok(Nip19Coordinate {
366 identifier: repo_config 377 coordinate: Coordinate {
367 .identifier 378 identifier: repo_config
368 .context("maintainers.yaml doesnt list the identifier")?, 379 .identifier
369 kind: Kind::GitRepoAnnouncement, 380 .context("maintainers.yaml doesnt list the identifier")?,
370 public_key: PublicKey::from_bech32( 381 kind: Kind::GitRepoAnnouncement,
371 repo_config 382 public_key: PublicKey::from_bech32(
372 .maintainers 383 repo_config
373 .first() 384 .maintainers
374 .context("maintainers.yaml doesnt list any maintainers")?, 385 .first()
375 ) 386 .context("maintainers.yaml doesnt list any maintainers")?,
376 .context("maintainers.yaml doesn't list the first maintainer using a valid npub")?, 387 )
388 .context("maintainers.yaml doesn't list the first maintainer using a valid npub")?,
389 },
377 relays: repo_config 390 relays: repo_config
378 .relays 391 .relays
379 .iter() 392 .iter()
@@ -386,7 +399,7 @@ async fn get_repo_coordinate_from_user_prompt(
386 git_repo: &Repo, 399 git_repo: &Repo,
387 #[cfg(test)] client: &crate::client::MockConnect, 400 #[cfg(test)] client: &crate::client::MockConnect,
388 #[cfg(not(test))] client: &Client, 401 #[cfg(not(test))] client: &Client,
389) -> Result<Coordinate> { 402) -> Result<Nip19Coordinate> {
390 // TODO: present list of events filter by root_commit 403 // TODO: present list of events filter by root_commit
391 // TODO: fallback to search based on identifier 404 // TODO: fallback to search based on identifier
392 let dim = Style::new().color256(247); 405 let dim = Style::new().color256(247);
@@ -401,7 +414,7 @@ async fn get_repo_coordinate_from_user_prompt(
401 loop { 414 loop {
402 let input = Interactor::default() 415 let input = Interactor::default()
403 .input(PromptInputParms::default().with_prompt("nostr repository"))?; 416 .input(PromptInputParms::default().with_prompt("nostr repository"))?;
404 let coordinate = if let Ok(c) = Coordinate::parse(&input) { 417 let coordinate = if let Ok(c) = Nip19Coordinate::from_bech32(&input) {
405 c 418 c
406 } else if let Ok(nostr_url) = 419 } else if let Ok(nostr_url) =
407 NostrUrlDecoded::parse_and_resolve(&input, &Some(git_repo)).await 420 NostrUrlDecoded::parse_and_resolve(&input, &Some(git_repo)).await
@@ -491,7 +504,7 @@ pub fn extract_pks(pk_strings: Vec<String>) -> Result<Vec<PublicKey>> {
491 let mut pks: Vec<PublicKey> = vec![]; 504 let mut pks: Vec<PublicKey> = vec![];
492 for s in pk_strings { 505 for s in pk_strings {
493 pks.push( 506 pks.push(
494 nostr_sdk::prelude::PublicKey::from_bech32(s.clone()).context(format!( 507 nostr_sdk::prelude::PublicKey::from_bech32(&s).context(format!(
495 "failed to convert {s} into a valid nostr public key" 508 "failed to convert {s} into a valid nostr public key"
496 ))?, 509 ))?,
497 ); 510 );