commit 0650a6279131865447d519ee1b26db9fd8a9c0ba
parent a4a046560582ac9500e8109f205373f7494cdf78
Author: kernelkind <kernelkind@gmail.com>
Date: Thu, 18 Jan 2024 14:59:30 -0500
nip19: add search functionality for naddr, nprofile & nevent
The user is able to search for naddr, nprofile & nevent bech32 entities.
Additionally, these entities and others are able to have prefixes such
as damus:nostr: and damus.io links.
Closes: https://github.com/damus-io/damus/issues/1841
Closes: https://github.com/damus-io/damus/issues/1650
Changelog-Added: Add ability to search for naddr, nprofiles, nevents
Lightning-url: LNURL1DP68GURN8GHJ7EM9W3SKCCNE9E3K7MF0D3H82UNVWQHKWUN9V4HXGCTHDC6RZVGR8SW3G
Signed-off-by: kernelkind <kernelkind@gmail.com>
Reviewed-by: William Casarin <jb55@jb55.com>
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
5 files changed, 82 insertions(+), 35 deletions(-)
diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj
@@ -614,6 +614,7 @@
D7FB10A72B0C371A00FA8D42 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C2B10272A7B0F5C008AA43E /* Log.swift */; };
D7FF94002AC7AC5300FD969D /* RelayURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7FF93FF2AC7AC5200FD969D /* RelayURL.swift */; };
E02B54182B4DFADA0077FF42 /* Bech32ObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E02B54172B4DFADA0077FF42 /* Bech32ObjectTests.swift */; };
+ E04A37C62B544F090029650D /* URIParsing.swift in Sources */ = {isa = PBXBuildFile; fileRef = E04A37C52B544F090029650D /* URIParsing.swift */; };
E4FA1C032A24BB7F00482697 /* SearchSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */; };
E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; };
E9E4ED0B295867B900DD7078 /* ThreadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E9E4ED0A295867B900DD7078 /* ThreadView.swift */; };
@@ -1377,6 +1378,7 @@
D7EDED322B12ACAE0018B19C /* DamusUserDefaults.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DamusUserDefaults.swift; sourceTree = "<group>"; };
D7FF93FF2AC7AC5200FD969D /* RelayURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayURL.swift; sourceTree = "<group>"; };
E02B54172B4DFADA0077FF42 /* Bech32ObjectTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Bech32ObjectTests.swift; sourceTree = "<group>"; };
+ E04A37C52B544F090029650D /* URIParsing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URIParsing.swift; sourceTree = "<group>"; };
E4FA1C022A24BB7F00482697 /* SearchSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsView.swift; sourceTree = "<group>"; };
E990020E2955F837003BBC5A /* EditMetadataView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditMetadataView.swift; sourceTree = "<group>"; };
E9E4ED0A295867B900DD7078 /* ThreadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadView.swift; sourceTree = "<group>"; };
@@ -2055,6 +2057,7 @@
4C7FF7D628233637009601DB /* Util */ = {
isa = PBXGroup;
children = (
+ E04A37C52B544F090029650D /* URIParsing.swift */,
4C1D4FB02A7958E60024F453 /* VersionInfo.swift */,
4C7D09612A098D0E00943473 /* WalletConnect.swift */,
4C198DF329F88D23004C165C /* Images */,
@@ -3297,6 +3300,7 @@
50B5685329F97CB400A23243 /* CredentialHandler.swift in Sources */,
643EA5C8296B764E005081BB /* RelayFilterView.swift in Sources */,
F71694EC2A662292001F4053 /* SuggestedUsersViewModel.swift in Sources */,
+ E04A37C62B544F090029650D /* URIParsing.swift in Sources */,
4C3EA67D28FFBBA300C48A62 /* InvoicesView.swift in Sources */,
4C363A8E28236FE4006E126D /* NoteContentView.swift in Sources */,
4C2B10282A7B0F5C008AA43E /* Log.swift in Sources */,
diff --git a/damus/Nostr/NostrLink.swift b/damus/Nostr/NostrLink.swift
@@ -55,14 +55,6 @@ func parse_hexstr(_ p: Parser, len: Int) -> String? {
return String(substring(p.str, start: start, end: p.pos))
}
-func decode_universal_link(_ s: String) -> NostrLink? {
- var uri = s.replacingOccurrences(of: "https://damus.io/r/", with: "")
- uri = uri.replacingOccurrences(of: "https://damus.io/", with: "")
- uri = uri.replacingOccurrences(of: "/", with: "")
-
- return decode_nostr_bech32_uri(uri)
-}
-
func decode_nostr_bech32_uri(_ s: String) -> NostrLink? {
guard let obj = Bech32Object.parse(s) else {
return nil
@@ -90,19 +82,7 @@ func decode_nostr_bech32_uri(_ s: String) -> NostrLink? {
}
func decode_nostr_uri(_ s: String) -> NostrLink? {
- if s.starts(with: "https://damus.io/") {
- return decode_universal_link(s)
- }
-
- var uri = s
- uri = uri.replacingOccurrences(of: "nostr://", with: "")
- uri = uri.replacingOccurrences(of: "nostr:", with: "")
-
- // Fix for non-latin characters resulting in second colon being encoded
- uri = uri.replacingOccurrences(of: "damus:t%3A", with: "t:")
-
- uri = uri.replacingOccurrences(of: "damus://", with: "")
- uri = uri.replacingOccurrences(of: "damus:", with: "")
+ let uri = remove_nostr_uri_prefix(s)
let parts = uri.split(separator: ":")
.reduce(into: Array<String>()) { acc, str in
diff --git a/damus/Util/URIParsing.swift b/damus/Util/URIParsing.swift
@@ -0,0 +1,34 @@
+//
+// URIParsing.swift
+// damus
+//
+// Created by KernelKind on 1/13/24.
+//
+
+import Foundation
+
+private func remove_damus_uri_prefix(_ s: String) -> String {
+ var uri = s.replacingOccurrences(of: "https://damus.io/r/", with: "")
+ uri = uri.replacingOccurrences(of: "https://damus.io/", with: "")
+ uri = uri.replacingOccurrences(of: "/", with: "")
+
+ return uri
+}
+
+func remove_nostr_uri_prefix(_ s: String) -> String {
+ if s.starts(with: "https://damus.io/") {
+ return remove_damus_uri_prefix(s)
+ }
+
+ var uri = s
+ uri = uri.replacingOccurrences(of: "nostr://", with: "")
+ uri = uri.replacingOccurrences(of: "nostr:", with: "")
+
+ // Fix for non-latin characters resulting in second colon being encoded
+ uri = uri.replacingOccurrences(of: "damus:t%3A", with: "t:")
+
+ uri = uri.replacingOccurrences(of: "damus://", with: "")
+ uri = uri.replacingOccurrences(of: "damus:", with: "")
+
+ return uri
+}
diff --git a/damus/Views/Search/SearchingEventView.swift b/damus/Views/Search/SearchingEventView.swift
@@ -18,6 +18,7 @@ enum SearchType: Equatable {
case event(NoteId)
case profile(Pubkey)
case nip05(String)
+ case naddr(NAddr)
}
@MainActor
@@ -35,6 +36,8 @@ struct SearchingEventView: View {
return "Profile"
case .event:
return "Note"
+ case .naddr:
+ return "Naddr"
}
}
@@ -89,6 +92,14 @@ struct SearchingEventView: View {
}
self.search_state = .found_profile(pubkey)
}
+ case .naddr(let naddr):
+ naddrLookup(damus_state: state, naddr: naddr) { res in
+ guard let res = res else {
+ self.search_state = .not_found
+ return
+ }
+ self.search_state = .found(res)
+ }
}
}
diff --git a/damus/Views/SearchResultsView.swift b/damus/Views/SearchResultsView.swift
@@ -20,6 +20,9 @@ enum Search: Identifiable {
case nip05(String)
case hex(Data)
case multi(MultiSearch)
+ case nevent(NEvent)
+ case naddr(NAddr)
+ case nprofile(NProfile)
var id: String {
switch self {
@@ -30,6 +33,9 @@ enum Search: Identifiable {
case .nip05: return "nip05"
case .hex: return "hex"
case .multi: return "multi"
+ case .nevent: return "nevent"
+ case .naddr: return "naddr"
+ case .nprofile: return "nprofile"
}
}
}
@@ -62,27 +68,25 @@ struct InnerSearchResults: View {
switch search {
case .profiles(let results):
ProfilesSearch(results)
-
case .hashtag(let ht):
HashtagSearch(ht)
-
case .nip05(let addr):
SearchingEventView(state: damus_state, search_type: .nip05(addr))
-
case .profile(let pubkey):
SearchingEventView(state: damus_state, search_type: .profile(pubkey))
-
case .hex(let h):
-
VStack(spacing: 10) {
SearchingEventView(state: damus_state, search_type: .event(NoteId(h)))
-
SearchingEventView(state: damus_state, search_type: .profile(Pubkey(h)))
- }
-
+ }
case .note(let nid):
SearchingEventView(state: damus_state, search_type: .event(nid))
-
+ case .nevent(let nevent):
+ SearchingEventView(state: damus_state, search_type: .event(nevent.noteid))
+ case .nprofile(let nprofile):
+ SearchingEventView(state: damus_state, search_type: .profile(nprofile.author))
+ case .naddr(let naddr):
+ SearchingEventView(state: damus_state, search_type: .naddr(naddr))
case .multi(let multi):
VStack {
HashtagSearch(multi.hashtag)
@@ -142,21 +146,35 @@ func search_for_string<Y>(profiles: Profiles, search new: String, txn: NdbTxn<Y>
return .hashtag(make_hashtagable(new))
}
- if let new = hex_decode_id(new) {
+ let searchQuery = remove_nostr_uri_prefix(new)
+
+ if let new = hex_decode_id(searchQuery) {
return .hex(new)
}
- if new.starts(with: "npub") {
- if let decoded = bech32_pubkey_decode(new) {
+ if searchQuery.starts(with: "npub") {
+ if let decoded = bech32_pubkey_decode(searchQuery) {
return .profile(decoded)
}
}
- if new.starts(with: "note"), let decoded = try? bech32_decode(new) {
+ if searchQuery.starts(with: "note"), let decoded = try? bech32_decode(searchQuery) {
return .note(NoteId(decoded.data))
}
- let multisearch = MultiSearch(hashtag: make_hashtagable(new), profiles: search_profiles(profiles: profiles, search: new, txn: txn))
+ if searchQuery.starts(with: "nevent"), case let .nevent(nevent) = Bech32Object.parse(searchQuery) {
+ return .nevent(nevent)
+ }
+
+ if searchQuery.starts(with: "nprofile"), case let .nprofile(nprofile) = Bech32Object.parse(searchQuery) {
+ return .nprofile(nprofile)
+ }
+
+ if searchQuery.starts(with: "naddr"), case let .naddr(naddr) = Bech32Object.parse(searchQuery) {
+ return .naddr(naddr)
+ }
+
+ let multisearch = MultiSearch(hashtag: make_hashtagable(searchQuery), profiles: search_profiles(profiles: profiles, search: new, txn: txn))
return .multi(multisearch)
}