upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/git_remote_helper.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-08-01 14:18:00 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-08-01 14:18:00 +0100
commitfa16f46e341fca66c6c1b01cf28b2c5f2700b15b (patch)
treec92036add46947fb23f0e45e7ac7659435aa2995 /src/git_remote_helper.rs
parent777a414d368b66363090a6d38beb95c821a4077b (diff)
feat(remote): add `nostr://npub/identifer`
support with optional relays as query parameter
Diffstat (limited to 'src/git_remote_helper.rs')
-rw-r--r--src/git_remote_helper.rs122
1 files changed, 113 insertions, 9 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs
index ea220de..58c3bf8 100644
--- a/src/git_remote_helper.rs
+++ b/src/git_remote_helper.rs
@@ -22,7 +22,7 @@ use client::{
22use git::RepoActions; 22use git::RepoActions;
23use git2::{Oid, Repository}; 23use git2::{Oid, Repository};
24use nostr::nips::nip01::Coordinate; 24use nostr::nips::nip01::Coordinate;
25use nostr_sdk::{EventBuilder, Tag, Url}; 25use nostr_sdk::{EventBuilder, PublicKey, Tag, Url};
26use nostr_signer::NostrSigner; 26use nostr_signer::NostrSigner;
27use repo_ref::RepoRef; 27use repo_ref::RepoRef;
28use repo_state::RepoState; 28use repo_state::RepoState;
@@ -139,13 +139,53 @@ pub(crate) fn read_line<'a>(stdin: &io::Stdin, line: &'a mut String) -> io::Resu
139 139
140fn nostr_git_url_to_repo_coordinates(url: &str) -> Result<HashSet<Coordinate>> { 140fn nostr_git_url_to_repo_coordinates(url: &str) -> Result<HashSet<Coordinate>> {
141 let mut repo_coordinattes = HashSet::new(); 141 let mut repo_coordinattes = HashSet::new();
142 let coordinate = Coordinate::parse(Url::parse(url)?.domain().context("no naddr")?)?; 142 let url = Url::parse(url)?;
143 if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { 143
144 repo_coordinattes.insert(coordinate); 144 if url.scheme().ne("nostr") {
145 } else { 145 bail!("nostr git url must start with nostr://")
146 }
147
148 if let Ok(coordinate) = Coordinate::parse(url.domain().context("no naddr")?) {
149 if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) {
150 repo_coordinattes.insert(coordinate);
151 return Ok(repo_coordinattes);
152 }
146 bail!("naddr doesnt point to a git repository announcement"); 153 bail!("naddr doesnt point to a git repository announcement");
147 } 154 }
148 Ok(repo_coordinattes) 155
156 if let Some(domain) = url.domain() {
157 if let Ok(public_key) = PublicKey::parse(domain) {
158 if url.path().is_empty() {
159 bail!(
160 "nostr git url should include the repo identifier eg nostr://npub123/the-repo-identifer"
161 );
162 }
163 let mut relays = vec![];
164 for (name, value) in url.query_pairs() {
165 if name.contains("relay") {
166 let mut decoded = urlencoding::decode(&value)
167 .context("could not parse relays in nostr git url")?
168 .to_string();
169 if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") {
170 decoded = format!("wss://{decoded}");
171 }
172 let url =
173 Url::parse(&decoded).context("could not parse relays in nostr git url")?;
174 relays.push(url.to_string());
175 }
176 }
177 repo_coordinattes.insert(Coordinate {
178 identifier: "ngit".to_string(),
179 public_key,
180 kind: nostr_sdk::Kind::GitRepoAnnouncement,
181 relays,
182 });
183 return Ok(repo_coordinattes);
184 }
185 }
186 bail!(
187 "nostr git url must be in format nostr://naddr123 or nostr://npub123/identifer?relay=wss://relay-example.com&relay1=wss://relay-example.org"
188 );
149} 189}
150 190
151async fn list(git_repo: &Repo, repo_ref: &RepoRef, for_push: bool) -> Result<()> { 191async fn list(git_repo: &Repo, repo_ref: &RepoRef, for_push: bool) -> Result<()> {
@@ -528,7 +568,7 @@ mod tests {
528 568
529 use super::*; 569 use super::*;
530 570
531 fn get_model_coordinate() -> Coordinate { 571 fn get_model_coordinate(relays: bool) -> Coordinate {
532 Coordinate { 572 Coordinate {
533 identifier: "ngit".to_string(), 573 identifier: "ngit".to_string(),
534 public_key: PublicKey::parse( 574 public_key: PublicKey::parse(
@@ -536,7 +576,11 @@ mod tests {
536 ) 576 )
537 .unwrap(), 577 .unwrap(),
538 kind: nostr_sdk::Kind::GitRepoAnnouncement, 578 kind: nostr_sdk::Kind::GitRepoAnnouncement,
539 relays: vec!["wss://nos.lol".to_string()], 579 relays: if relays {
580 vec!["wss://nos.lol/".to_string()]
581 } else {
582 vec![]
583 },
540 } 584 }
541 } 585 }
542 586
@@ -546,9 +590,69 @@ mod tests {
546 nostr_git_url_to_repo_coordinates( 590 nostr_git_url_to_repo_coordinates(
547 "nostr://naddr1qqzxuemfwsqs6amnwvaz7tmwdaejumr0dspzpgqgmmc409hm4xsdd74sf68a2uyf9pwel4g9mfdg8l5244t6x4jdqvzqqqrhnym0k2qj" 591 "nostr://naddr1qqzxuemfwsqs6amnwvaz7tmwdaejumr0dspzpgqgmmc409hm4xsdd74sf68a2uyf9pwel4g9mfdg8l5244t6x4jdqvzqqqrhnym0k2qj"
548 )?, 592 )?,
549 HashSet::from([get_model_coordinate()]), 593 HashSet::from([get_model_coordinate(true)]),
550 ); 594 );
551 Ok(()) 595 Ok(())
552 } 596 }
597 mod from_npub_slah_identifier {
598 use super::*;
599
600 #[test]
601 fn without_relay() -> Result<()> {
602 assert_eq!(
603 nostr_git_url_to_repo_coordinates(
604 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit"
605 )?,
606 HashSet::from([get_model_coordinate(false)]),
607 );
608 Ok(())
609 }
610
611 #[test]
612 fn with_relay_without_scheme_defaults_to_wss() -> Result<()> {
613 assert_eq!(
614 nostr_git_url_to_repo_coordinates(
615 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit?relay=nos.lol"
616 )?,
617 HashSet::from([get_model_coordinate(true)]),
618 );
619 Ok(())
620 }
621
622 #[test]
623 fn with_encoded_relay() -> Result<()> {
624 assert_eq!(
625 nostr_git_url_to_repo_coordinates(&format!(
626 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit?relay={}",
627 urlencoding::encode("wss://nos.lol")
628 ))?,
629 HashSet::from([get_model_coordinate(true)]),
630 );
631 Ok(())
632 }
633 #[test]
634 fn with_multiple_encoded_relays() -> Result<()> {
635 assert_eq!(
636 nostr_git_url_to_repo_coordinates(&format!(
637 "nostr://npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit?relay={}&relay1={}",
638 urlencoding::encode("wss://nos.lol"),
639 urlencoding::encode("wss://relay.damus.io"),
640 ))?,
641 HashSet::from([Coordinate {
642 identifier: "ngit".to_string(),
643 public_key: PublicKey::parse(
644 "npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr",
645 )
646 .unwrap(),
647 kind: nostr_sdk::Kind::GitRepoAnnouncement,
648 relays: vec![
649 "wss://nos.lol/".to_string(),
650 "wss://relay.damus.io/".to_string(),
651 ],
652 }]),
653 );
654 Ok(())
655 }
656 }
553 } 657 }
554} 658}