NostrLink.swift (2415B)
1 // 2 // NostrLink.swift 3 // damus 4 // 5 // Created by William Casarin on 2022-05-05. 6 // 7 8 import Foundation 9 10 11 enum NostrLink: Equatable { 12 case ref(RefId) 13 case filter(NostrFilter) 14 case script([UInt8]) 15 } 16 17 func encode_pubkey_uri(_ pubkey: Pubkey) -> String { 18 return "p:" + pubkey.hex() 19 } 20 21 // TODO: bech32 and relay hints 22 func encode_event_id_uri(_ noteid: NoteId) -> String { 23 return "e:" + noteid.hex() 24 } 25 26 func parse_nostr_ref_uri_type(_ p: Parser) -> String? { 27 if parse_char(p, "p") { 28 return "p" 29 } 30 31 if parse_char(p, "e") { 32 return "e" 33 } 34 35 return nil 36 } 37 38 func parse_hexstr(_ p: Parser, len: Int) -> String? { 39 var i: Int = 0 40 41 if len % 2 != 0 { 42 return nil 43 } 44 45 let start = p.pos 46 47 while i < len { 48 guard parse_hex_char(p) != nil else { 49 p.pos = start 50 return nil 51 } 52 i += 1 53 } 54 55 return String(substring(p.str, start: start, end: p.pos)) 56 } 57 58 func decode_nostr_bech32_uri(_ s: String) -> NostrLink? { 59 guard let obj = Bech32Object.parse(s) else { 60 return nil 61 } 62 63 switch obj { 64 case .nsec(let privkey): 65 guard let pubkey = privkey_to_pubkey(privkey: privkey) else { return nil } 66 return .ref(.pubkey(pubkey)) 67 case .npub(let pubkey): 68 return .ref(.pubkey(pubkey)) 69 case .note(let id): 70 return .ref(.event(id)) 71 case .nscript(let data): 72 return .script(data) 73 case .naddr(let naddr): 74 return .ref(.naddr(naddr)) 75 case .nevent(let nevent): 76 return .ref(.event(nevent.noteid)) 77 case .nprofile(let nprofile): 78 return .ref(.pubkey(nprofile.author)) 79 case .nrelay(_): 80 return .none 81 } 82 } 83 84 func decode_nostr_uri(_ s: String) -> NostrLink? { 85 let uri = remove_nostr_uri_prefix(s) 86 87 let parts = uri.split(separator: ":") 88 .reduce(into: Array<String>()) { acc, str in 89 guard let decoded = str.removingPercentEncoding else { 90 return 91 } 92 acc.append(decoded) 93 return 94 } 95 96 if parts.count >= 2 && parts[0] == "t" { 97 return .filter(NostrFilter(hashtag: [parts[1].lowercased()])) 98 } 99 100 guard parts.count == 1 else { 101 return nil 102 } 103 104 let part = parts[0] 105 106 return decode_nostr_bech32_uri(part) 107 }