upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-01-10 02:40:16 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-10 02:42:38 +0000
commit6dbe167a1c8f9a59538e76f6322424eee93994df (patch)
treee0491f8be02da3f48c3c03482b942e773d2365a4 /src
parent1b6b669b9b82d1f81b887a32055f19c53d3bb8bf (diff)
fix: normalize URLs with trailing slashes in announcement validation
Announcements were being rejected when clone URLs or relay URLs had trailing slashes that didn't match. Added URL normalization to strip trailing slashes before comparison, allowing announcements to be accepted regardless of trailing slash presence. - Add normalize_url_for_comparison() helper - Update has_clone_url() and has_relay() to normalize before matching - Add comprehensive tests for trailing slash scenarios Fixes issue in work/active-issues/clone-relays-mismatch-validation.md
Diffstat (limited to 'src')
-rw-r--r--src/nostr/events.rs113
1 files changed, 111 insertions, 2 deletions
diff --git a/src/nostr/events.rs b/src/nostr/events.rs
index 66808cc..9d43ca3 100644
--- a/src/nostr/events.rs
+++ b/src/nostr/events.rs
@@ -143,14 +143,29 @@ impl RepositoryAnnouncement {
143 }) 143 })
144 } 144 }
145 145
146 /// Normalize a URL by removing trailing slashes for consistent comparison
147 ///
148 /// See test_validate_announcement_with_trailing_slash_in_relay for why we need this
149 fn normalize_url_for_comparison(url: &str) -> &str {
150 url.trim_end_matches('/')
151 }
152
146 /// Check if this announcement lists the given domain in clone URLs 153 /// Check if this announcement lists the given domain in clone URLs
147 pub fn has_clone_url(&self, domain: &str) -> bool { 154 pub fn has_clone_url(&self, domain: &str) -> bool {
148 self.clone_urls.iter().any(|url| url.contains(domain)) 155 let normalized_domain = Self::normalize_url_for_comparison(domain);
156 self.clone_urls.iter().any(|url| {
157 let normalized_url = Self::normalize_url_for_comparison(url);
158 normalized_url.contains(normalized_domain)
159 })
149 } 160 }
150 161
151 /// Check if this announcement lists the given relay 162 /// Check if this announcement lists the given relay
152 pub fn has_relay(&self, relay: &str) -> bool { 163 pub fn has_relay(&self, relay: &str) -> bool {
153 self.relays.iter().any(|r| r.contains(relay)) 164 let normalized_relay = Self::normalize_url_for_comparison(relay);
165 self.relays.iter().any(|r| {
166 let normalized_r = Self::normalize_url_for_comparison(r);
167 normalized_r.contains(normalized_relay)
168 })
154 } 169 }
155 170
156 /// Check if this announcement lists the service (both clone and relay) 171 /// Check if this announcement lists the service (both clone and relay)
@@ -787,4 +802,98 @@ mod tests {
787 // HEAD points to develop but only main branch exists in state 802 // HEAD points to develop but only main branch exists in state
788 assert!(!state.head_commit_available()); 803 assert!(!state.head_commit_available());
789 } 804 }
805
806 #[test]
807 fn test_validate_announcement_with_trailing_slash_in_relay() {
808 let keys = create_test_keys();
809 let event = create_announcement_event(
810 &keys,
811 "test-repo",
812 vec!["https://git.shakespeare.diy/alice/test-repo.git"],
813 vec!["wss://git.shakespeare.diy/"], // Trailing slash in relay
814 );
815
816 // Should accept despite trailing slash mismatch
817 let result = validate_announcement(&event, "git.shakespeare.diy");
818 assert!(result.is_ok());
819 }
820
821 #[test]
822 fn test_validate_announcement_with_trailing_slash_in_clone_url() {
823 let keys = create_test_keys();
824 let event = create_announcement_event(
825 &keys,
826 "test-repo",
827 vec!["https://git.shakespeare.diy/"], // Trailing slash in clone URL
828 vec!["wss://git.shakespeare.diy"],
829 );
830
831 // Should accept despite trailing slash mismatch
832 let result = validate_announcement(&event, "git.shakespeare.diy");
833 assert!(result.is_ok());
834 }
835
836 #[test]
837 fn test_validate_announcement_with_trailing_slash_in_both() {
838 let keys = create_test_keys();
839 let event = create_announcement_event(
840 &keys,
841 "test-repo",
842 vec!["https://git.shakespeare.diy/alice/test-repo.git/"], // Trailing slash
843 vec!["wss://git.shakespeare.diy/"], // Trailing slash
844 );
845
846 // Should accept with trailing slashes in both
847 let result = validate_announcement(&event, "git.shakespeare.diy");
848 assert!(result.is_ok());
849 }
850
851 #[test]
852 fn test_validate_announcement_domain_with_trailing_slash() {
853 let keys = create_test_keys();
854 let event = create_announcement_event(
855 &keys,
856 "test-repo",
857 vec!["https://gitnostr.com/alice/test-repo.git"],
858 vec!["wss://gitnostr.com"],
859 );
860
861 // Should accept even when domain parameter has trailing slash
862 let result = validate_announcement(&event, "gitnostr.com/");
863 assert!(result.is_ok());
864 }
865
866 #[test]
867 fn test_has_clone_url_with_trailing_slashes() {
868 let keys = create_test_keys();
869 let event = create_announcement_event(
870 &keys,
871 "test-repo",
872 vec!["https://example.com/repo.git/"],
873 vec!["wss://example.com"],
874 );
875
876 let announcement = RepositoryAnnouncement::from_event(event).unwrap();
877
878 // Should match with or without trailing slash
879 assert!(announcement.has_clone_url("example.com"));
880 assert!(announcement.has_clone_url("example.com/"));
881 }
882
883 #[test]
884 fn test_has_relay_with_trailing_slashes() {
885 let keys = create_test_keys();
886 let event = create_announcement_event(
887 &keys,
888 "test-repo",
889 vec!["https://example.com/repo.git"],
890 vec!["wss://example.com/"],
891 );
892
893 let announcement = RepositoryAnnouncement::from_event(event).unwrap();
894
895 // Should match with or without trailing slash
896 assert!(announcement.has_relay("example.com"));
897 assert!(announcement.has_relay("example.com/"));
898 }
790} 899}