diff options
Diffstat (limited to 'src/git.rs')
| -rw-r--r-- | src/git.rs | 145 |
1 files changed, 109 insertions, 36 deletions
| @@ -835,55 +835,128 @@ fn extract_sig_from_patch_tags<'a>( | |||
| 835 | .context("failed to create git signature") | 835 | .context("failed to create git signature") |
| 836 | } | 836 | } |
| 837 | 837 | ||
| 838 | pub fn nostr_git_url_to_repo_coordinates(url: &str) -> Result<HashSet<Coordinate>> { | 838 | #[derive(Debug, PartialEq)] |
| 839 | let mut repo_coordinattes = HashSet::new(); | 839 | pub enum ServerProtocol { |
| 840 | let url = Url::parse(url)?; | 840 | Ssh, |
| 841 | Https, | ||
| 842 | Http, | ||
| 843 | Git, | ||
| 844 | } | ||
| 841 | 845 | ||
| 842 | if url.scheme().ne("nostr") { | 846 | #[derive(Debug, PartialEq)] |
| 843 | bail!("nostr git url must start with nostr://") | 847 | pub struct NostrUrlDecoded { |
| 844 | } | 848 | pub coordinates: HashSet<Coordinate>, |
| 849 | pub protocol: Option<ServerProtocol>, | ||
| 850 | pub user: Option<String>, | ||
| 851 | } | ||
| 845 | 852 | ||
| 846 | if let Ok(coordinate) = Coordinate::parse(url.domain().context("no naddr")?) { | 853 | 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"; |
| 847 | if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { | 854 | |
| 848 | repo_coordinattes.insert(coordinate); | 855 | impl NostrUrlDecoded { |
| 849 | return Ok(repo_coordinattes); | 856 | pub fn from_str(url: &str) -> Result<Self> { |
| 857 | let mut coordinates = HashSet::new(); | ||
| 858 | let mut protocol = None; | ||
| 859 | let mut user = None; | ||
| 860 | let mut relays = vec![]; | ||
| 861 | |||
| 862 | if !url.starts_with("nostr://") { | ||
| 863 | bail!("nostr git url must start with nostr://"); | ||
| 864 | } | ||
| 865 | // process get url parameters if present | ||
| 866 | for (name, value) in Url::parse(url)?.query_pairs() { | ||
| 867 | if name.contains("relay") { | ||
| 868 | let mut decoded = urlencoding::decode(&value) | ||
| 869 | .context("could not parse relays in nostr git url")? | ||
| 870 | .to_string(); | ||
| 871 | if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") { | ||
| 872 | decoded = format!("wss://{decoded}"); | ||
| 873 | } | ||
| 874 | let url = | ||
| 875 | Url::parse(&decoded).context("could not parse relays in nostr git url")?; | ||
| 876 | relays.push(url.to_string()); | ||
| 877 | } else if name == "protocol" { | ||
| 878 | protocol = match value.as_ref() { | ||
| 879 | "ssh" => Some(ServerProtocol::Ssh), | ||
| 880 | "https" => Some(ServerProtocol::Https), | ||
| 881 | "http" => Some(ServerProtocol::Http), | ||
| 882 | "git" => Some(ServerProtocol::Git), | ||
| 883 | _ => None, | ||
| 884 | }; | ||
| 885 | } else if name == "user" { | ||
| 886 | user = Some(value.to_string()); | ||
| 887 | } | ||
| 850 | } | 888 | } |
| 851 | bail!("naddr doesnt point to a git repository announcement"); | ||
| 852 | } | ||
| 853 | 889 | ||
| 854 | if let Some(domain) = url.domain() { | 890 | let mut parts: Vec<&str> = url[8..] |
| 855 | if let Ok(public_key) = PublicKey::parse(domain) { | 891 | .split('?') |
| 856 | if url.path().len() < 2 { | 892 | .next() |
| 857 | bail!( | 893 | .unwrap_or("") |
| 858 | "nostr git url should include the repo identifier eg nostr://npub123/the-repo-identifer" | 894 | .split('/') |
| 859 | ); | 895 | .collect(); |
| 896 | |||
| 897 | // extract optional protocol | ||
| 898 | if protocol.is_none() { | ||
| 899 | let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; | ||
| 900 | let protocol_str = if let Some(at_index) = part.find('@') { | ||
| 901 | user = Some(part[..at_index].to_string()); | ||
| 902 | &part[at_index + 1..] | ||
| 903 | } else { | ||
| 904 | part | ||
| 905 | }; | ||
| 906 | protocol = match protocol_str { | ||
| 907 | "ssh" => Some(ServerProtocol::Ssh), | ||
| 908 | "https" => Some(ServerProtocol::Https), | ||
| 909 | "http" => Some(ServerProtocol::Http), | ||
| 910 | "git" => Some(ServerProtocol::Git), | ||
| 911 | _ => protocol, | ||
| 912 | }; | ||
| 913 | if protocol.is_some() { | ||
| 914 | parts.remove(0); | ||
| 860 | } | 915 | } |
| 861 | let mut relays = vec![]; | 916 | } |
| 862 | for (name, value) in url.query_pairs() { | 917 | // extract naddr npub/<optional-relays>/identifer |
| 863 | if name.contains("relay") { | 918 | let part = parts.first().context(INCORRECT_NOSTR_URL_FORMAT_ERROR)?; |
| 864 | let mut decoded = urlencoding::decode(&value) | 919 | // naddr used |
| 865 | .context("could not parse relays in nostr git url")? | 920 | if let Ok(coordinate) = Coordinate::parse(part) { |
| 866 | .to_string(); | 921 | if coordinate.kind.eq(&nostr_sdk::Kind::GitRepoAnnouncement) { |
| 867 | if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") { | 922 | coordinates.insert(coordinate); |
| 868 | decoded = format!("wss://{decoded}"); | 923 | } else { |
| 869 | } | 924 | bail!("naddr doesnt point to a git repository announcement"); |
| 870 | let url = | 925 | } |
| 871 | Url::parse(&decoded).context("could not parse relays in nostr git url")?; | 926 | // npub/<optional-relays>/identifer used |
| 872 | relays.push(url.to_string()); | 927 | } else if let Ok(public_key) = PublicKey::parse(part) { |
| 928 | parts.remove(0); | ||
| 929 | let identifier = parts | ||
| 930 | .pop() | ||
| 931 | .context("nostr url must have an identifier eg. nostr://npub123/repo-identifier")? | ||
| 932 | .to_string(); | ||
| 933 | for relay in parts { | ||
| 934 | let mut decoded = urlencoding::decode(relay) | ||
| 935 | .context("could not parse relays in nostr git url")? | ||
| 936 | .to_string(); | ||
| 937 | if !decoded.starts_with("ws://") && !decoded.starts_with("wss://") { | ||
| 938 | decoded = format!("wss://{decoded}"); | ||
| 873 | } | 939 | } |
| 940 | let url = | ||
| 941 | Url::parse(&decoded).context("could not parse relays in nostr git url")?; | ||
| 942 | relays.push(url.to_string()); | ||
| 874 | } | 943 | } |
| 875 | repo_coordinattes.insert(Coordinate { | 944 | coordinates.insert(Coordinate { |
| 876 | identifier: url.path()[1..].to_string(), | 945 | identifier, |
| 877 | public_key, | 946 | public_key, |
| 878 | kind: nostr_sdk::Kind::GitRepoAnnouncement, | 947 | kind: nostr_sdk::Kind::GitRepoAnnouncement, |
| 879 | relays, | 948 | relays, |
| 880 | }); | 949 | }); |
| 881 | return Ok(repo_coordinattes); | 950 | } else { |
| 951 | bail!(INCORRECT_NOSTR_URL_FORMAT_ERROR); | ||
| 882 | } | 952 | } |
| 953 | |||
| 954 | Ok(Self { | ||
| 955 | coordinates, | ||
| 956 | protocol, | ||
| 957 | user, | ||
| 958 | }) | ||
| 883 | } | 959 | } |
| 884 | bail!( | ||
| 885 | "nostr git url must be in format nostr://naddr123 or nostr://npub123/identifer?relay=wss://relay-example.com&relay1=wss://relay-example.org" | ||
| 886 | ); | ||
| 887 | } | 960 | } |
| 888 | 961 | ||
| 889 | /** produce error when using local repo or custom protocols */ | 962 | /** produce error when using local repo or custom protocols */ |