diff options
Diffstat (limited to 'src/lib/git')
| -rw-r--r-- | src/lib/git/nostr_url.rs | 81 |
1 files changed, 72 insertions, 9 deletions
diff --git a/src/lib/git/nostr_url.rs b/src/lib/git/nostr_url.rs index c26bb2e..ac57538 100644 --- a/src/lib/git/nostr_url.rs +++ b/src/lib/git/nostr_url.rs | |||
| @@ -2,9 +2,11 @@ use core::fmt; | |||
| 2 | use std::str::FromStr; | 2 | use std::str::FromStr; |
| 3 | 3 | ||
| 4 | use anyhow::{anyhow, bail, Context, Error, Result}; | 4 | use anyhow::{anyhow, bail, Context, Error, Result}; |
| 5 | use nostr::nips::nip01::Coordinate; | 5 | use nostr::nips::{nip01::Coordinate, nip05}; |
| 6 | use nostr_sdk::{PublicKey, RelayUrl, ToBech32, Url}; | 6 | use nostr_sdk::{PublicKey, RelayUrl, ToBech32, Url}; |
| 7 | 7 | ||
| 8 | use super::{get_git_config_item, save_git_config_item, Repo}; | ||
| 9 | |||
| 8 | #[derive(Debug, PartialEq, Default, Clone)] | 10 | #[derive(Debug, PartialEq, Default, Clone)] |
| 9 | pub enum ServerProtocol { | 11 | pub enum ServerProtocol { |
| 10 | Ssh, | 12 | Ssh, |
| @@ -59,6 +61,7 @@ pub struct NostrUrlDecoded { | |||
| 59 | pub coordinate: Coordinate, | 61 | pub coordinate: Coordinate, |
| 60 | pub protocol: Option<ServerProtocol>, | 62 | pub protocol: Option<ServerProtocol>, |
| 61 | pub user: Option<String>, | 63 | pub user: Option<String>, |
| 64 | pub nip05: Option<String>, | ||
| 62 | } | 65 | } |
| 63 | 66 | ||
| 64 | impl fmt::Display for NostrUrlDecoded { | 67 | impl fmt::Display for NostrUrlDecoded { |
| @@ -89,10 +92,8 @@ impl fmt::Display for NostrUrlDecoded { | |||
| 89 | 92 | ||
| 90 | static INCORRECT_NOSTR_URL_FORMAT_ERROR: &str = "incorrect nostr git url format. try nostr://naddr123 or nostr://npub123/my-repo or nostr://ssh/npub123/relay.damus.io/my-repo"; | 93 | static INCORRECT_NOSTR_URL_FORMAT_ERROR: &str = "incorrect nostr git url format. try nostr://naddr123 or nostr://npub123/my-repo or nostr://ssh/npub123/relay.damus.io/my-repo"; |
| 91 | 94 | ||
| 92 | impl std::str::FromStr for NostrUrlDecoded { | 95 | impl NostrUrlDecoded { |
| 93 | type Err = anyhow::Error; | 96 | pub async fn parse_and_resolve(url: &str, git_repo: &Option<&Repo>) -> Result<Self> { |
| 94 | |||
| 95 | fn from_str(url: &str) -> Result<Self> { | ||
| 96 | let mut protocol = None; | 97 | let mut protocol = None; |
| 97 | let mut user = None; | 98 | let mut user = None; |
| 98 | let mut relays = vec![]; | 99 | let mut relays = vec![]; |
| @@ -154,6 +155,7 @@ impl std::str::FromStr for NostrUrlDecoded { | |||
| 154 | } | 155 | } |
| 155 | // extract naddr npub/<optional-relays>/identifer | 156 | // extract naddr npub/<optional-relays>/identifer |
| 156 | let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; | 157 | let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; |
| 158 | let mut nip05 = None; | ||
| 157 | // naddr used | 159 | // naddr used |
| 158 | let coordinate = if let Ok(coordinate) = Coordinate::parse(part) { | 160 | let coordinate = if let Ok(coordinate) = Coordinate::parse(part) { |
| 159 | if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { | 161 | if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { |
| @@ -161,8 +163,9 @@ impl std::str::FromStr for NostrUrlDecoded { | |||
| 161 | } else { | 163 | } else { |
| 162 | bail!("naddr doesnt point to a git repository announcement"); | 164 | bail!("naddr doesnt point to a git repository announcement"); |
| 163 | } | 165 | } |
| 164 | // npub/<optional-relays>/identifer used | 166 | // <npub|nip05_address>/<optional-relays>/identifer used |
| 165 | } else if let Ok(public_key) = PublicKey::parse(part) { | 167 | } else { |
| 168 | let npub_or_nip05 = part.to_owned(); | ||
| 166 | parts.remove(0); | 169 | parts.remove(0); |
| 167 | let identifier = parts | 170 | let identifier = parts |
| 168 | .pop() | 171 | .pop() |
| @@ -179,14 +182,41 @@ impl std::str::FromStr for NostrUrlDecoded { | |||
| 179 | RelayUrl::parse(&decoded).context("could not parse relays in nostr git url")?; | 182 | RelayUrl::parse(&decoded).context("could not parse relays in nostr git url")?; |
| 180 | relays.push(url); | 183 | relays.push(url); |
| 181 | } | 184 | } |
| 185 | let public_key = match PublicKey::parse(npub_or_nip05) { | ||
| 186 | Ok(public_key) => public_key, | ||
| 187 | Err(_) => { | ||
| 188 | nip05 = Some(npub_or_nip05.to_string()); | ||
| 189 | if let Ok(public_key) = | ||
| 190 | resolve_nip05_from_git_config_cache(npub_or_nip05, git_repo) | ||
| 191 | { | ||
| 192 | public_key | ||
| 193 | } else { | ||
| 194 | // TODO eprint loading message | ||
| 195 | let res = nip05::profile(npub_or_nip05, None) | ||
| 196 | .await | ||
| 197 | .context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; | ||
| 198 | // TODO clear loading message | ||
| 199 | nip05 = Some(npub_or_nip05.to_string()); | ||
| 200 | let _ = save_nip05_to_git_config_cache( | ||
| 201 | npub_or_nip05, | ||
| 202 | &res.public_key, | ||
| 203 | git_repo, | ||
| 204 | ); | ||
| 205 | if relays.is_empty() { | ||
| 206 | for r in res.relays { | ||
| 207 | relays.push(r); | ||
| 208 | } | ||
| 209 | } | ||
| 210 | res.public_key | ||
| 211 | } | ||
| 212 | } | ||
| 213 | }; | ||
| 182 | Coordinate { | 214 | Coordinate { |
| 183 | identifier, | 215 | identifier, |
| 184 | public_key, | 216 | public_key, |
| 185 | kind: nostr_sdk::Kind::GitRepoAnnouncement, | 217 | kind: nostr_sdk::Kind::GitRepoAnnouncement, |
| 186 | relays, | 218 | relays, |
| 187 | } | 219 | } |
| 188 | } else { | ||
| 189 | bail!(INCORRECT_NOSTR_URL_FORMAT_ERROR); | ||
| 190 | }; | 220 | }; |
| 191 | 221 | ||
| 192 | Ok(Self { | 222 | Ok(Self { |
| @@ -194,10 +224,43 @@ impl std::str::FromStr for NostrUrlDecoded { | |||
| 194 | coordinate, | 224 | coordinate, |
| 195 | protocol, | 225 | protocol, |
| 196 | user, | 226 | user, |
| 227 | nip05, | ||
| 197 | }) | 228 | }) |
| 198 | } | 229 | } |
| 199 | } | 230 | } |
| 200 | 231 | ||
| 232 | fn resolve_nip05_from_git_config_cache(nip05: &str, git_repo: &Option<&Repo>) -> Result<PublicKey> { | ||
| 233 | let stored_value = get_git_config_item( | ||
| 234 | git_repo, | ||
| 235 | &format!("nostr.nip05.{}", urlencoding::encode(nip05)), | ||
| 236 | )? | ||
| 237 | .context("not in cache")?; | ||
| 238 | PublicKey::parse(stored_value) | ||
| 239 | .context("stored nip05 resolution value did not parse as public key") | ||
| 240 | } | ||
| 241 | |||
| 242 | fn save_nip05_to_git_config_cache( | ||
| 243 | nip05: &str, | ||
| 244 | public_key: &PublicKey, | ||
| 245 | git_repo: &Option<&Repo>, | ||
| 246 | ) -> Result<()> { | ||
| 247 | if save_git_config_item( | ||
| 248 | git_repo, | ||
| 249 | &format!("nostr.nip05.{}", urlencoding::encode(nip05)), | ||
| 250 | &public_key.to_bech32()?, | ||
| 251 | ) | ||
| 252 | .is_err() | ||
| 253 | { | ||
| 254 | save_git_config_item( | ||
| 255 | &None, | ||
| 256 | &format!("nostr.nip05.{}", urlencoding::encode(nip05)), | ||
| 257 | &public_key.to_bech32()?, | ||
| 258 | ) | ||
| 259 | } else { | ||
| 260 | Ok(()) | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 201 | #[derive(Debug, PartialEq, Default)] | 264 | #[derive(Debug, PartialEq, Default)] |
| 202 | pub struct CloneUrl { | 265 | pub struct CloneUrl { |
| 203 | original_string: String, | 266 | original_string: String, |