1
0
mirror of git://jb55.com/damus synced 2024-09-30 00:40:45 +00:00

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>
This commit is contained in:
kernelkind 2024-01-18 14:59:30 -05:00 committed by William Casarin
parent a4a0465605
commit 0650a62791
5 changed files with 82 additions and 35 deletions

View File

@ -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 */,

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
}
}

View File

@ -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)
}