damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

commit 704023560506dddeed81e828d3f0a0a3424f1188
parent f9d21ef901f91544fa91e27a01141b9a4c1d2f1a
Author: William Casarin <jb55@jb55.com>
Date:   Mon, 31 Jul 2023 03:57:26 -0700

refactor: add Pubkey, Privkey, NoteId string aliases

This is a non-behavioral change in preparation for the actual switchover
from Strings to Ids. The purpose of this kit is to reduce the size of
the switchover commit which is going to be very large.

Diffstat:
Mdamus/Components/ImageCarousel.swift | 4++--
Mdamus/Components/InvoiceView.swift | 4++--
Mdamus/Components/InvoicesView.swift | 4++--
Mdamus/Components/NIP05Badge.swift | 8++++----
Mdamus/Components/Reposted.swift | 2+-
Mdamus/Components/TranslateView.swift | 2+-
Mdamus/Components/UserView.swift | 8++++----
Mdamus/ContentView.swift | 45++++++++++++++++++++++++---------------------
Mdamus/Models/ActionBarModel.swift | 2+-
Mdamus/Models/BookmarksManager.swift | 12++++++------
Mdamus/Models/Contacts.swift | 36++++++++++++++++++------------------
Mdamus/Models/CreateAccountModel.swift | 4++--
Mdamus/Models/DamusState.swift | 2+-
Mdamus/Models/DirectMessageModel.swift | 10+++++-----
Mdamus/Models/DirectMessagesModel.swift | 14+++++++-------
Mdamus/Models/EventsModel.swift | 4++--
Mdamus/Models/FollowersModel.swift | 15+++++++--------
Mdamus/Models/FollowingModel.swift | 8++++----
Mdamus/Models/HomeModel.swift | 31++++++++++++++++---------------
Mdamus/Models/LikeCounter.swift | 14+++++++-------
Mdamus/Models/Liked.swift | 2+-
Mdamus/Models/MutedThreadsManager.swift | 14+++++++-------
Mdamus/Models/Notifications/ZapGroup.swift | 4++--
Mdamus/Models/NotificationsModel.swift | 24++++++++++++------------
Mdamus/Models/ProfileModel.swift | 8++++----
Mdamus/Models/ProfileUpdate.swift | 2+-
Mdamus/Models/ReactionsModel.swift | 2+-
Mdamus/Models/Reply.swift | 4++--
Mdamus/Models/ReplyMap.swift | 10+++++-----
Mdamus/Models/Report.swift | 11++++++-----
Mdamus/Models/RepostsModel.swift | 2+-
Mdamus/Models/SearchHomeModel.swift | 14+++++++-------
Mdamus/Models/ThreadModel.swift | 2+-
Mdamus/Models/UserSearchCache.swift | 10+++++-----
Mdamus/Models/UserSettingsStore.swift | 10+++++-----
Mdamus/Nostr/Nostr.swift | 2+-
Mdamus/Nostr/NostrEvent.swift | 25+++++++++++++------------
Mdamus/Nostr/NostrFilter.swift | 10+++++-----
Mdamus/Nostr/NostrResponse.swift | 2+-
Mdamus/Nostr/ProfileDatabase.swift | 18+++++++++---------
Mdamus/Nostr/Profiles.swift | 31+++++++++++++++----------------
Mdamus/Nostr/Relay.swift | 2+-
Mdamus/Nostr/RelayPool.swift | 2+-
Mdamus/Util/Bech32Object.swift | 6+++---
Mdamus/Util/DisplayName.swift | 2+-
Mdamus/Util/EventCache.swift | 14+++++++-------
Mdamus/Util/Keys.swift | 34+++++++++++++++++++---------------
Mdamus/Util/LNUrls.swift | 6+++---
Mdamus/Util/NIP05.swift | 4++--
Mdamus/Util/PostBox.swift | 8++++----
Mdamus/Util/PreviewCache.swift | 4++--
Mdamus/Util/Relays/RelayBootstrap.swift | 6+++---
Mdamus/Util/Relays/RelayFilters.swift | 10+++++-----
Mdamus/Util/ReplyCounter.swift | 16++++++++--------
Mdamus/Util/Router.swift | 6+++---
Mdamus/Util/WalletConnect.swift | 12++++++------
Mdamus/Util/Zap.swift | 20++++++++++----------
Mdamus/Util/Zaps.swift | 16++++++++--------
Mdamus/Views/ActionBar/EventDetailBar.swift | 10+++++-----
Mdamus/Views/BannerImageView.swift | 12+++++-------
Mdamus/Views/CreateAccountView.swift | 4++--
Mdamus/Views/DMChatView.swift | 10+++++-----
Mdamus/Views/EventView.swift | 10+++++-----
Mdamus/Views/Events/BuilderEventView.swift | 4++--
Mdamus/Views/Events/Components/EventTop.swift | 4++--
Mdamus/Views/Events/Components/ReplyPart.swift | 2+-
Mdamus/Views/Events/EventMenu.swift | 6+++---
Mdamus/Views/Events/EventProfile.swift | 2+-
Mdamus/Views/Events/EventShell.swift | 4++--
Mdamus/Views/Events/SelectedEventView.swift | 2+-
Mdamus/Views/Events/TextEvent.swift | 4++--
Mdamus/Views/FollowingView.swift | 2+-
Mdamus/Views/ImagePicker.swift | 2+-
Mdamus/Views/Images/ProfilePicImageView.swift | 8+++-----
Mdamus/Views/LoginView.swift | 8++++----
Mdamus/Views/Muting/MutelistView.swift | 4++--
Mdamus/Views/NoteContentView.swift | 4++--
Mdamus/Views/Notifications/EventGroupView.swift | 16++++++++--------
Mdamus/Views/Notifications/NotificationsView.swift | 2+-
Mdamus/Views/Notifications/ProfilePicturesView.swift | 4++--
Mdamus/Views/Onboarding/SuggestedUserView.swift | 6+++---
Mdamus/Views/Onboarding/SuggestedUsersViewModel.swift | 15+++++++--------
Mdamus/Views/PostView.swift | 2+-
Mdamus/Views/Posting/UserSearch.swift | 8++++----
Mdamus/Views/Profile/CondensedProfilePicturesView.swift | 6+++---
Mdamus/Views/Profile/EditPictureControl.swift | 5++---
Mdamus/Views/Profile/EventProfileName.swift | 4++--
Mdamus/Views/Profile/MaybeAnonPfpView.swift | 4++--
Mdamus/Views/Profile/ProfileName.swift | 6+++---
Mdamus/Views/Profile/ProfileNameView.swift | 2+-
Mdamus/Views/Profile/ProfilePicView.swift | 8++++----
Mdamus/Views/Profile/ProfilePictureSelector.swift | 3+--
Mdamus/Views/Profile/ProfileView.swift | 8++++----
Mdamus/Views/QRCodeView.swift | 4++--
Mdamus/Views/Search/SearchingEventView.swift | 2+-
Mdamus/Views/SearchResultsView.swift | 6+++---
Mdamus/Views/SelectWalletView.swift | 4++--
Mdamus/Views/Zaps/ZapTypePicker.swift | 6+++---
Mdamus/Views/Zaps/ZapUserView.swift | 4++--
MdamusTests/UserSearchCacheTests.swift | 4++--
Mnostrdb/NdbNote.swift | 18+++++++++---------
101 files changed, 427 insertions(+), 426 deletions(-)

diff --git a/damus/Components/ImageCarousel.swift b/damus/Components/ImageCarousel.swift @@ -57,7 +57,7 @@ enum ImageShape { struct ImageCarousel: View { var urls: [MediaUrl] - let evid: String + let evid: NoteId let state: DamusState @@ -72,7 +72,7 @@ struct ImageCarousel: View { @State private var selectedIndex = 0 @State private var video_size: CGSize? = nil - init(state: DamusState, evid: String, urls: [MediaUrl]) { + init(state: DamusState, evid: NoteId, urls: [MediaUrl]) { _open_sheet = State(initialValue: false) _current_url = State(initialValue: nil) let media_model = state.events.get_cache_data(evid).media_metadata_model diff --git a/damus/Components/InvoiceView.swift b/damus/Components/InvoiceView.swift @@ -9,7 +9,7 @@ import SwiftUI struct InvoiceView: View { @Environment(\.colorScheme) var colorScheme - let our_pubkey: String + let our_pubkey: Pubkey let invoice: Invoice @State var showing_select_wallet: Bool = false @State var copied = false @@ -108,7 +108,7 @@ let test_invoice = Invoice(description: .description("this is a description"), a struct InvoiceView_Previews: PreviewProvider { static var previews: some View { - InvoiceView(our_pubkey: "", invoice: test_invoice, settings: test_damus_state().settings) + InvoiceView(our_pubkey: .empty, invoice: test_invoice, settings: test_damus_state().settings) .frame(width: 300, height: 200) } } diff --git a/damus/Components/InvoicesView.swift b/damus/Components/InvoicesView.swift @@ -8,7 +8,7 @@ import SwiftUI struct InvoicesView: View { - let our_pubkey: String + let our_pubkey: Pubkey var invoices: [Invoice] let settings: UserSettingsStore @@ -29,7 +29,7 @@ struct InvoicesView: View { struct InvoicesView_Previews: PreviewProvider { static var previews: some View { - InvoicesView(our_pubkey: "", invoices: [Invoice.init(description: .description("description"), amount: .specific(10000), string: "invstr", expiry: 100000, payment_hash: Data(), created_at: 1000000)], settings: test_damus_state().settings) + InvoicesView(our_pubkey: test_note.pubkey, invoices: [Invoice.init(description: .description("description"), amount: .specific(10000), string: "invstr", expiry: 100000, payment_hash: Data(), created_at: 1000000)], settings: test_damus_state().settings) .frame(width: 300) } } diff --git a/damus/Components/NIP05Badge.swift b/damus/Components/NIP05Badge.swift @@ -9,14 +9,14 @@ import SwiftUI struct NIP05Badge: View { let nip05: NIP05 - let pubkey: String + let pubkey: Pubkey let contacts: Contacts let show_domain: Bool let profiles: Profiles @Environment(\.openURL) var openURL - init(nip05: NIP05, pubkey: String, contacts: Contacts, show_domain: Bool, profiles: Profiles) { + init(nip05: NIP05, pubkey: Pubkey, contacts: Contacts, show_domain: Bool, profiles: Profiles) { self.nip05 = nip05 self.pubkey = pubkey self.contacts = contacts @@ -91,7 +91,7 @@ extension View { } } -func use_nip05_color(pubkey: String, contacts: Contacts) -> Bool { +func use_nip05_color(pubkey: Pubkey, contacts: Contacts) -> Bool { return contacts.is_friend_or_self(pubkey) ? true : false } @@ -105,7 +105,7 @@ struct NIP05Badge_Previews: PreviewProvider { NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: test_state.contacts, show_domain: true, profiles: test_state.profiles) - NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: Contacts(our_pubkey: "sdkfjsdf"), show_domain: true, profiles: test_state.profiles) + NIP05Badge(nip05: NIP05(username: "jb55", host: "jb55.com"), pubkey: test_state.pubkey, contacts: Contacts(our_pubkey: test_pubkey), show_domain: true, profiles: test_state.profiles) } } } diff --git a/damus/Components/Reposted.swift b/damus/Components/Reposted.swift @@ -9,7 +9,7 @@ import SwiftUI struct Reposted: View { let damus: DamusState - let pubkey: String + let pubkey: Pubkey let profile: Profile? var body: some View { diff --git a/damus/Components/TranslateView.swift b/damus/Components/TranslateView.swift @@ -125,7 +125,7 @@ struct TranslateView_Previews: PreviewProvider { } } -func translate_note(profiles: Profiles, privkey: String?, event: NostrEvent, settings: UserSettingsStore, note_lang: String) async -> TranslateStatus { +func translate_note(profiles: Profiles, privkey: Privkey?, event: NostrEvent, settings: UserSettingsStore, note_lang: String) async -> TranslateStatus { // If the note language is different from our preferred languages, send a translation request. let translator = Translator(settings) diff --git a/damus/Components/UserView.swift b/damus/Components/UserView.swift @@ -9,8 +9,8 @@ import SwiftUI struct UserViewRow: View { let damus_state: DamusState - let pubkey: String - + let pubkey: Pubkey + var body: some View { UserView(damus_state: damus_state, pubkey: pubkey) .contentShape(Rectangle()) @@ -20,12 +20,12 @@ struct UserViewRow: View { struct UserView: View { let damus_state: DamusState - let pubkey: String + let pubkey: Pubkey let spacer: Bool @State var about_text: Text? = nil - init(damus_state: DamusState, pubkey: String, spacer: Bool = true) { + init(damus_state: DamusState, pubkey: Pubkey, spacer: Bool = true) { self.damus_state = damus_state self.pubkey = pubkey self.spacer = spacer diff --git a/damus/ContentView.swift b/damus/ContentView.swift @@ -70,11 +70,11 @@ enum FilterState : Int { struct ContentView: View { let keypair: Keypair - var pubkey: String { + var pubkey: Pubkey { return keypair.pubkey } - var privkey: String? { + var privkey: Privkey? { return keypair.privkey } @@ -83,7 +83,7 @@ struct ContentView: View { @State var active_sheet: Sheets? = nil @State var damus_state: DamusState? = nil @SceneStorage("ContentView.selected_timeline") var selected_timeline: Timeline = .home - @State var muting: String? = nil + @State var muting: Pubkey? = nil @State var confirm_mute: Bool = false @State var user_muted_confirm: Bool = false @State var confirm_overwrite_mutelist: Bool = false @@ -231,9 +231,9 @@ struct ContentView: View { navigationCoordinator.push(route: Route.Script(script: model)) } - func open_profile(id: String) { - let profile_model = ProfileModel(pubkey: id, damus: damus_state!) - let followers = FollowersModel(damus_state: damus_state!, target: id) + func open_profile(pubkey: Pubkey) { + let profile_model = ProfileModel(pubkey: pubkey, damus: damus_state!) + let followers = FollowersModel(damus_state: damus_state!, target: pubkey) navigationCoordinator.push(route: Route.Profile(profile: profile_model, followers: followers)) } @@ -342,7 +342,7 @@ struct ContentView: View { switch res { case .filter(let filt): self.open_search(filt: filt) - case .profile(let id): self.open_profile(id: id) + case .profile(let pk): self.open_profile(pubkey: pk) case .event(let ev): self.open_event(ev: ev) case .wallet_connect(let nwc): self.open_wallet(nwc: nwc) case .script(let data): self.open_script(data) @@ -470,7 +470,7 @@ struct ContentView: View { guard let damus_state else { return } if local.type == .profile_zap { - open_profile(id: local.event_id) + open_profile(pubkey: local.event_id) return } @@ -656,7 +656,7 @@ struct ContentView: View { struct ContentView_Previews: PreviewProvider { static var previews: some View { - ContentView(keypair: Keypair(pubkey: "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681", privkey: nil)) + ContentView(keypair: Keypair(pubkey: test_pubkey, privkey: nil)) } } @@ -680,7 +680,7 @@ extension UINavigationController: UIGestureRecognizerDelegate { } struct LastNotification { - let id: String + let id: NoteId let created_at: Int64 } @@ -689,17 +689,20 @@ func get_last_event(_ timeline: Timeline) -> LastNotification? { let last = UserDefaults.standard.string(forKey: "last_\(str)") let last_created = UserDefaults.standard.string(forKey: "last_\(str)_time") .flatMap { Int64($0) } - - return last.flatMap { id in - last_created.map { created in - return LastNotification(id: id, created_at: created) - } + + guard let last, + let note_id = NoteId(hex: last), + let last_created + else { + return nil } + + return LastNotification(id: note_id, created_at: last_created) } func save_last_event(_ ev: NostrEvent, timeline: Timeline) { let str = timeline.rawValue - UserDefaults.standard.set(ev.id, forKey: "last_\(str)") + UserDefaults.standard.set(ev.id.hex(), forKey: "last_\(str)") UserDefaults.standard.set(String(ev.created_at), forKey: "last_\(str)_time") } @@ -757,18 +760,18 @@ struct FindEvent { let type: FindEventType let find_from: [String]? - static func profile(pubkey: String, find_from: [String]? = nil) -> FindEvent { + static func profile(pubkey: Pubkey, find_from: [String]? = nil) -> FindEvent { return FindEvent(type: .profile(pubkey), find_from: find_from) } - static func event(evid: String, find_from: [String]? = nil) -> FindEvent { + static func event(evid: NoteId, find_from: [String]? = nil) -> FindEvent { return FindEvent(type: .event(evid), find_from: find_from) } } enum FindEventType { - case profile(String) - case event(String) + case profile(Pubkey) + case event(NoteId) } enum FoundEvent { @@ -961,7 +964,7 @@ func handle_post_notification(keypair: FullKeypair, postbox: PostBox, events: Ev enum OpenResult { - case profile(String) + case profile(Pubkey) case filter(NostrFilter) case event(NostrEvent) case wallet_connect(WalletConnectURL) diff --git a/damus/Models/ActionBarModel.swift b/damus/Models/ActionBarModel.swift @@ -40,7 +40,7 @@ class ActionBarModel: ObservableObject { self.our_reply = our_reply } - func update(damus: DamusState, evid: String) { + func update(damus: DamusState, evid: NoteId) { self.likes = damus.likes.counts[evid] ?? 0 self.boosts = damus.boosts.counts[evid] ?? 0 self.zaps = damus.zaps.event_counts[evid] ?? 0 diff --git a/damus/Models/BookmarksManager.swift b/damus/Models/BookmarksManager.swift @@ -7,18 +7,18 @@ import Foundation -fileprivate func get_bookmarks_key(pubkey: String) -> String { +fileprivate func get_bookmarks_key(pubkey: Pubkey) -> String { pk_setting_key(pubkey, key: "bookmarks") } -func load_bookmarks(pubkey: String) -> [NostrEvent] { +func load_bookmarks(pubkey: Pubkey) -> [NostrEvent] { let key = get_bookmarks_key(pubkey: pubkey) return (UserDefaults.standard.stringArray(forKey: key) ?? []).compactMap { event_from_json(dat: $0) } } -func save_bookmarks(pubkey: String, current_value: [NostrEvent], value: [NostrEvent]) -> Bool { +func save_bookmarks(pubkey: Pubkey, current_value: [NostrEvent], value: [NostrEvent]) -> Bool { let uniq_bookmarks = uniq(value) if uniq_bookmarks != current_value { @@ -32,8 +32,8 @@ func save_bookmarks(pubkey: String, current_value: [NostrEvent], value: [NostrEv class BookmarksManager: ObservableObject { - private let pubkey: String - + private let pubkey: Pubkey + private var _bookmarks: [NostrEvent] var bookmarks: [NostrEvent] { get { @@ -47,7 +47,7 @@ class BookmarksManager: ObservableObject { } } - init(pubkey: String) { + init(pubkey: Pubkey) { self._bookmarks = load_bookmarks(pubkey: pubkey) self.pubkey = pubkey } diff --git a/damus/Models/Contacts.swift b/damus/Models/Contacts.swift @@ -9,21 +9,21 @@ import Foundation class Contacts { - private var friends: Set<String> = Set() - private var friend_of_friends: Set<String> = Set() + private var friends: Set<Pubkey> = Set() + private var friend_of_friends: Set<Pubkey> = Set() /// Tracks which friends are friends of a given pubkey. - private var pubkey_to_our_friends = [String : Set<String>]() - private var muted: Set<String> = Set() - - let our_pubkey: String + private var pubkey_to_our_friends = [Pubkey : Set<Pubkey>]() + private var muted: Set<Pubkey> = Set() + + let our_pubkey: Pubkey var event: NostrEvent? var mutelist: NostrEvent? - init(our_pubkey: String) { + init(our_pubkey: Pubkey) { self.our_pubkey = our_pubkey } - func is_muted(_ pk: String) -> Bool { + func is_muted(_ pk: Pubkey) -> Bool { return muted.contains(pk) } @@ -58,7 +58,7 @@ class Contacts { } } - func remove_friend(_ pubkey: String) { + func remove_friend(_ pubkey: Pubkey) { friends.remove(pubkey) pubkey_to_our_friends.forEach { @@ -66,7 +66,7 @@ class Contacts { } } - func get_friend_list() -> Set<String> { + func get_friend_list() -> Set<Pubkey> { return friends } @@ -75,7 +75,7 @@ class Contacts { return Set(ev.referenced_hashtags.map({ $0.ref_id.string() })) } - func add_friend_pubkey(_ pubkey: String) { + func add_friend_pubkey(_ pubkey: Pubkey) { friends.insert(pubkey) } @@ -88,7 +88,7 @@ class Contacts { // Exclude themself and us. if contact.pubkey != our_pubkey && contact.pubkey != pk { if pubkey_to_our_friends[pk] == nil { - pubkey_to_our_friends[pk] = Set<String>() + pubkey_to_our_friends[pk] = Set<Pubkey>() } pubkey_to_our_friends[pk]?.insert(contact.pubkey) @@ -96,28 +96,28 @@ class Contacts { } } - func is_friend_of_friend(_ pubkey: String) -> Bool { + func is_friend_of_friend(_ pubkey: Pubkey) -> Bool { return friend_of_friends.contains(pubkey) } - func is_in_friendosphere(_ pubkey: String) -> Bool { + func is_in_friendosphere(_ pubkey: Pubkey) -> Bool { return friends.contains(pubkey) || friend_of_friends.contains(pubkey) } - func is_friend(_ pubkey: String) -> Bool { + func is_friend(_ pubkey: Pubkey) -> Bool { return friends.contains(pubkey) } - func is_friend_or_self(_ pubkey: String) -> Bool { + func is_friend_or_self(_ pubkey: Pubkey) -> Bool { return pubkey == our_pubkey || is_friend(pubkey) } - func follow_state(_ pubkey: String) -> FollowState { + func follow_state(_ pubkey: Pubkey) -> FollowState { return is_friend(pubkey) ? .follows : .unfollows } /// Gets the list of pubkeys of our friends who follow the given pubkey. - func get_friended_followers(_ pubkey: String) -> [String] { + func get_friended_followers(_ pubkey: Pubkey) -> [Pubkey] { return Array((pubkey_to_our_friends[pubkey] ?? Set())) } } diff --git a/damus/Models/CreateAccountModel.swift b/damus/Models/CreateAccountModel.swift @@ -12,8 +12,8 @@ class CreateAccountModel: ObservableObject { @Published var real_name: String = "" @Published var nick_name: String = "" @Published var about: String = "" - @Published var pubkey: String = "" - @Published var privkey: String = "" + @Published var pubkey: Pubkey = .empty + @Published var privkey: Privkey = .empty @Published var profile_image: URL? = nil var pubkey_bech32: String { diff --git a/damus/Models/DamusState.swift b/damus/Models/DamusState.swift @@ -50,7 +50,7 @@ struct DamusState { return stored } - var pubkey: String { + var pubkey: Pubkey { return keypair.pubkey } diff --git a/damus/Models/DirectMessageModel.swift b/damus/Models/DirectMessageModel.swift @@ -16,11 +16,11 @@ class DirectMessageModel: ObservableObject { @Published var draft: String = "" - let pubkey: String - + let pubkey: Pubkey + var is_request = false - var our_pubkey: String - + var our_pubkey: Pubkey + func determine_is_request() -> Bool { for event in events { if event.pubkey == our_pubkey { @@ -31,7 +31,7 @@ class DirectMessageModel: ObservableObject { return true } - init(events: [NostrEvent] = [], our_pubkey: String, pubkey: String) { + init(events: [NostrEvent] = [], our_pubkey: Pubkey, pubkey: Pubkey) { self.events = events self.our_pubkey = our_pubkey self.pubkey = pubkey diff --git a/damus/Models/DirectMessagesModel.swift b/damus/Models/DirectMessagesModel.swift @@ -11,10 +11,10 @@ class DirectMessagesModel: ObservableObject { @Published var dms: [DirectMessageModel] = [] @Published var loading: Bool = false @Published var open_dm: Bool = false - @Published private(set) var active_model: DirectMessageModel = DirectMessageModel(our_pubkey: "", pubkey: "") - let our_pubkey: String - - init(our_pubkey: String) { + @Published private(set) var active_model: DirectMessageModel = DirectMessageModel(our_pubkey: .empty, pubkey: .empty) + let our_pubkey: Pubkey + + init(our_pubkey: Pubkey) { self.our_pubkey = our_pubkey } @@ -30,14 +30,14 @@ class DirectMessagesModel: ObservableObject { self.active_model = model } - func set_active_dm(_ pubkey: String) { + func set_active_dm(_ pubkey: Pubkey) { for model in self.dms where model.pubkey == pubkey { self.set_active_dm_model(model) break } } - func lookup_or_create(_ pubkey: String) -> DirectMessageModel { + func lookup_or_create(_ pubkey: Pubkey) -> DirectMessageModel { if let dm = lookup(pubkey) { return dm } @@ -47,7 +47,7 @@ class DirectMessagesModel: ObservableObject { return new } - func lookup(_ pubkey: String) -> DirectMessageModel? { + func lookup(_ pubkey: Pubkey) -> DirectMessageModel? { for dm in dms { if pubkey == dm.pubkey { return dm diff --git a/damus/Models/EventsModel.swift b/damus/Models/EventsModel.swift @@ -10,14 +10,14 @@ import Foundation class EventsModel: ObservableObject { let state: DamusState - let target: String + let target: NoteId let kind: NostrKind let sub_id = UUID().uuidString let profiles_id = UUID().uuidString @Published var events: [NostrEvent] = [] - init(state: DamusState, target: String, kind: NostrKind) { + init(state: DamusState, target: NoteId, kind: NostrKind) { self.state = state self.target = target self.kind = kind diff --git a/damus/Models/FollowersModel.swift b/damus/Models/FollowersModel.swift @@ -9,11 +9,11 @@ import Foundation class FollowersModel: ObservableObject { let damus_state: DamusState - let target: String - - @Published var contacts: [String]? = nil - var has_contact: Set<String> = Set() - + let target: Pubkey + + @Published var contacts: [Pubkey]? = nil + var has_contact: Set<Pubkey> = Set() + let sub_id: String = UUID().description let profiles_id: String = UUID().description @@ -24,14 +24,13 @@ class FollowersModel: ObservableObject { return contacts.count } - init(damus_state: DamusState, target: String) { + init(damus_state: DamusState, target: Pubkey) { self.damus_state = damus_state self.target = target } func get_filter() -> NostrFilter { - NostrFilter(kinds: [.contacts], - pubkeys: [target]) + NostrFilter(kinds: [.contacts], pubkeys: [target]) } func subscribe() { diff --git a/damus/Models/FollowingModel.swift b/damus/Models/FollowingModel.swift @@ -11,18 +11,18 @@ class FollowingModel { let damus_state: DamusState var needs_sub: Bool = true - let contacts: [String] - + let contacts: [Pubkey] + let sub_id: String = UUID().description - init(damus_state: DamusState, contacts: [String]) { + init(damus_state: DamusState, contacts: [Pubkey]) { self.damus_state = damus_state self.contacts = contacts } func get_filter() -> NostrFilter { var f = NostrFilter(kinds: [.metadata]) - f.authors = self.contacts.reduce(into: Array<String>()) { acc, pk in + f.authors = self.contacts.reduce(into: Array<Pubkey>()) { acc, pk in // don't fetch profiles we already have if damus_state.profiles.has_fresh_profile(id: pk) { return diff --git a/damus/Models/HomeModel.swift b/damus/Models/HomeModel.swift @@ -29,7 +29,7 @@ enum Resubscribe { } enum HomeResubFilter { - case pubkey(String) + case pubkey(Pubkey) case hashtag(String) init?(from: ReferencedId) { @@ -63,9 +63,10 @@ class HomeModel { var damus_state: DamusState - var has_event: [String: Set<String>] = [:] - var deleted_events: Set<String> = Set() var channels: [String: NostrEvent] = [:] + // NDBTODO: let's get rid of this entirely, let nostrdb handle it + var has_event: [String: Set<NoteId>] = [:] + var deleted_events: Set<NoteId> = Set() var last_event_of_kind: [String: [UInt32: NostrEvent]] = [:] var done_init: Bool = false var incoming_dms: [NostrEvent] = [] @@ -109,7 +110,7 @@ class HomeModel { return damus_state.dms } - func has_sub_id_event(sub_id: String, ev_id: String) -> Bool { + func has_sub_id_event(sub_id: String, ev_id: NoteId) -> Bool { if !has_event.keys.contains(sub_id) { has_event[sub_id] = Set() return false @@ -502,13 +503,13 @@ class HomeModel { pool.send(.unsubscribe(home_subid)) } - func get_friends() -> [String] { + func get_friends() -> [Pubkey] { var friends = damus_state.contacts.get_friend_list() friends.insert(damus_state.pubkey) return Array(friends) } - func subscribe_to_home_filters(friends fs: [String]? = nil, relay_id: String? = nil) { + func subscribe_to_home_filters(friends fs: [Pubkey]? = nil, relay_id: String? = nil) { // TODO: separate likes? var home_filter_kinds: [NostrKind] = [ .text, .longform, .boost @@ -782,7 +783,7 @@ func print_filters(relay_id: String?, filters groups: [[NostrFilter]]) { print("-----") } -func process_metadata_profile(our_pubkey: String, profiles: Profiles, profile: Profile, ev: NostrEvent) { +func process_metadata_profile(our_pubkey: Pubkey, profiles: Profiles, profile: Profile, ev: NostrEvent) { var old_nip05: String? = nil let mprof = profiles.lookup_with_timestamp(id: ev.pubkey) @@ -847,7 +848,7 @@ func guard_valid_event(events: EventCache, ev: NostrEvent, callback: @escaping ( } } -func process_metadata_event(events: EventCache, our_pubkey: String, profiles: Profiles, ev: NostrEvent, completion: ((Profile?) -> Void)? = nil) { +func process_metadata_event(events: EventCache, our_pubkey: Pubkey, profiles: Profiles, ev: NostrEvent, completion: ((Profile?) -> Void)? = nil) { guard_valid_event(events: events, ev: ev) { DispatchQueue.global(qos: .background).async { guard let profile: Profile = decode_data(Data(ev.content.utf8)) else { @@ -865,8 +866,8 @@ func process_metadata_event(events: EventCache, our_pubkey: String, profiles: Pr } } -func robohash(_ pk: String) -> String { - return "https://robohash.org/" + pk +func robohash(_ pk: Pubkey) -> String { + return "https://robohash.org/" + pk.hex() } func load_our_stuff(state: DamusState, ev: NostrEvent) { @@ -1171,7 +1172,7 @@ func zap_notification_body(profiles: Profiles, zap: Zap, locale: Locale = Locale } } -func create_in_app_profile_zap_notification(profiles: Profiles, zap: Zap, locale: Locale = Locale.current, profile_id: String) { +func create_in_app_profile_zap_notification(profiles: Profiles, zap: Zap, locale: Locale = Locale.current, profile_id: Pubkey) { let content = UNMutableNotificationContent() content.title = zap_notification_title(zap) @@ -1192,7 +1193,7 @@ func create_in_app_profile_zap_notification(profiles: Profiles, zap: Zap, locale } } -func create_in_app_event_zap_notification(profiles: Profiles, zap: Zap, locale: Locale = Locale.current, evId: String) { +func create_in_app_event_zap_notification(profiles: Profiles, zap: Zap, locale: Locale = Locale.current, evId: NoteId) { let content = UNMutableNotificationContent() content.title = zap_notification_title(zap) @@ -1213,7 +1214,7 @@ func create_in_app_event_zap_notification(profiles: Profiles, zap: Zap, locale: } } -func render_notification_content_preview(cache: EventCache, ev: NostrEvent, profiles: Profiles, privkey: String?) -> String { +func render_notification_content_preview(cache: EventCache, ev: NostrEvent, profiles: Profiles, privkey: Privkey?) -> String { let prefix_len = 50 let artifacts = cache.get_cache_data(ev.id).artifacts.artifacts ?? render_note_content(ev: ev, profiles: profiles, privkey: privkey) @@ -1329,7 +1330,7 @@ enum ProcessZapResult { // securely get the zap target's pubkey. this can be faked so we need to be // careful -func get_zap_target_pubkey(ev: NostrEvent, events: EventCache) -> String? { +func get_zap_target_pubkey(ev: NostrEvent, events: EventCache) -> Pubkey? { let etags = ev.referenced_ids guard let etag = etags.first else { @@ -1409,7 +1410,7 @@ func process_zap_event(damus_state: DamusState, ev: NostrEvent, completion: @esc } -fileprivate func process_zap_event_with_zapper(damus_state: DamusState, ev: NostrEvent, zapper: String) -> Zap? { +fileprivate func process_zap_event_with_zapper(damus_state: DamusState, ev: NostrEvent, zapper: Pubkey) -> Zap? { let our_keypair = damus_state.keypair guard let zap = Zap.from_zap_event(zap_ev: ev, zapper: zapper, our_privkey: our_keypair.privkey) else { diff --git a/damus/Models/LikeCounter.swift b/damus/Models/LikeCounter.swift @@ -13,16 +13,16 @@ enum CountResult { } class EventCounter { - var counts: [String: Int] = [:] - var user_events: [String: Set<String>] = [:] - var our_events: [String: NostrEvent] = [:] - var our_pubkey: String - - init(our_pubkey: String) { + var counts: [NoteId: Int] = [:] + var user_events: [Pubkey: Set<NoteId>] = [:] + var our_events: [NoteId: NostrEvent] = [:] + var our_pubkey: Pubkey + + init(our_pubkey: Pubkey) { self.our_pubkey = our_pubkey } - func add_event(_ ev: NostrEvent, target: String) -> CountResult { + func add_event(_ ev: NostrEvent, target: NoteId) -> CountResult { let pubkey = ev.pubkey if self.user_events[pubkey] == nil { diff --git a/damus/Models/Liked.swift b/damus/Models/Liked.swift @@ -9,6 +9,6 @@ import Foundation struct Counted { let event: NostrEvent - let id: String + let id: NoteId let total: Int } diff --git a/damus/Models/MutedThreadsManager.swift b/damus/Models/MutedThreadsManager.swift @@ -7,16 +7,16 @@ import Foundation -fileprivate func getMutedThreadsKey(pubkey: String) -> String { +fileprivate func getMutedThreadsKey(pubkey: Pubkey) -> String { pk_setting_key(pubkey, key: "muted_threads") } -func loadMutedThreads(pubkey: String) -> [String] { +func loadMutedThreads(pubkey: Pubkey) -> [NoteId] { let key = getMutedThreadsKey(pubkey: pubkey) return UserDefaults.standard.stringArray(forKey: key) ?? [] } -func saveMutedThreads(pubkey: String, currentValue: [String], value: [String]) -> Bool { +func saveMutedThreads(pubkey: Pubkey, currentValue: [NoteId], value: [NoteId]) -> Bool { let uniqueMutedThreads = Array(Set(value)) if uniqueMutedThreads != currentValue { @@ -31,9 +31,9 @@ class MutedThreadsManager: ObservableObject { private let keypair: Keypair - private var _mutedThreadsSet: Set<String> - private var _mutedThreads: [String] - var mutedThreads: [String] { + private var _mutedThreadsSet: Set<NoteId> + private var _mutedThreads: [NoteId] + var mutedThreads: [NoteId] { get { return _mutedThreads } @@ -51,7 +51,7 @@ class MutedThreadsManager: ObservableObject { self.keypair = keypair } - func isMutedThread(_ ev: NostrEvent, privkey: String?) -> Bool { + func isMutedThread(_ ev: NostrEvent, privkey: Privkey?) -> Bool { return _mutedThreadsSet.contains(ev.thread_id(privkey: privkey)) } diff --git a/damus/Models/Notifications/ZapGroup.swift b/damus/Models/Notifications/ZapGroup.swift @@ -10,8 +10,8 @@ import Foundation class ZapGroup { var zaps: [Zapping] = [] var msat_total: Int64 = 0 - var zappers = Set<String>() - + var zappers = Set<Pubkey>() + var last_event_at: UInt32 { guard let first = zaps.first else { return 0 diff --git a/damus/Models/NotificationsModel.swift b/damus/Models/NotificationsModel.swift @@ -8,10 +8,10 @@ import Foundation enum NotificationItem { - case repost(String, EventGroup) - case reaction(String, EventGroup) + case repost(NoteId, EventGroup) + case reaction(NoteId, EventGroup) case profile_zap(ZapGroup) - case event_zap(String, ZapGroup) + case event_zap(NoteId, ZapGroup) case reply(NostrEvent) var is_reply: NostrEvent? { @@ -104,23 +104,23 @@ class NotificationsModel: ObservableObject, ScrollQueue { var should_queue: Bool = true // mappings from events to - var zaps: [String: ZapGroup] = [:] + var zaps: [NoteId: ZapGroup] = [:] var profile_zaps = ZapGroup() - var reactions: [String: EventGroup] = [:] - var reposts: [String: EventGroup] = [:] + var reactions: [NoteId: EventGroup] = [:] + var reposts: [NoteId: EventGroup] = [:] var replies: [NostrEvent] = [] - var has_reply = Set<String>() - var has_ev = Set<String>() - + var has_reply = Set<NoteId>() + var has_ev = Set<NoteId>() + @Published var notifications: [NotificationItem] = [] func set_should_queue(_ val: Bool) { self.should_queue = val } - func uniq_pubkeys() -> [String] { - var pks = Set<String>() - + func uniq_pubkeys() -> [Pubkey] { + var pks = Set<Pubkey>() + for ev in incoming_events { pks.insert(ev.pubkey) } diff --git a/damus/Models/ProfileModel.swift b/damus/Models/ProfileModel.swift @@ -14,14 +14,14 @@ class ProfileModel: ObservableObject, Equatable { @Published var progress: Int = 0 var events: EventHolder - let pubkey: String + let pubkey: Pubkey let damus: DamusState - var seen_event: Set<String> = Set() + var seen_event: Set<NoteId> = Set() var sub_id = UUID().description var prof_subid = UUID().description - init(pubkey: String, damus: DamusState) { + init(pubkey: Pubkey, damus: DamusState) { self.pubkey = pubkey self.damus = damus self.events = EventHolder(on_queue: { ev in @@ -29,7 +29,7 @@ class ProfileModel: ObservableObject, Equatable { }) } - func follows(pubkey: String) -> Bool { + func follows(pubkey: Pubkey) -> Bool { guard let contacts = self.contacts else { return false } diff --git a/damus/Models/ProfileUpdate.swift b/damus/Models/ProfileUpdate.swift @@ -9,6 +9,6 @@ import Foundation struct ProfileUpdate { - let pubkey: String + let pubkey: Pubkey let profile: Profile } diff --git a/damus/Models/ReactionsModel.swift b/damus/Models/ReactionsModel.swift @@ -10,7 +10,7 @@ import Foundation final class ReactionsModel: EventsModel { - init(state: DamusState, target: String) { + init(state: DamusState, target: NoteId) { super.init(state: state, target: target, kind: .like) } } diff --git a/damus/Models/Reply.swift b/damus/Models/Reply.swift @@ -8,13 +8,13 @@ import Foundation struct ReplyDesc { - let pubkeys: [String] + let pubkeys: [Pubkey] let others: Int } func make_reply_description(_ tags: [[String]]) -> ReplyDesc { var c = 0 - var ns: [String] = [] + var ns: [Pubkey] = [] var i = tags.count - 1 while i >= 0 { diff --git a/damus/Models/ReplyMap.swift b/damus/Models/ReplyMap.swift @@ -8,20 +8,20 @@ import Foundation class ReplyMap { - var replies: [String: Set<String>] = [:] - - func lookup(_ id: String) -> Set<String>? { + var replies: [NoteId: Set<NoteId>] = [:] + + func lookup(_ id: NoteId) -> Set<NoteId>? { return replies[id] } - private func ensure_set(id: String) { + private func ensure_set(id: NoteId) { if replies[id] == nil { replies[id] = Set() } } @discardableResult - func add(id: String, reply_id: String) -> Bool { + func add(id: NoteId, reply_id: NoteId) -> Bool { ensure_set(id: id) if (replies[id]!).contains(reply_id) { return false diff --git a/damus/Models/Report.swift b/damus/Models/Report.swift @@ -31,12 +31,12 @@ enum ReportType: String, CustomStringConvertible, CaseIterable { } struct ReportNoteTarget { - let pubkey: String - let note_id: String + let pubkey: Pubkey + let note_id: NoteId } enum ReportTarget { - case user(String) + case user(Pubkey) case note(ReportNoteTarget) static func note(pubkey: Pubkey, note_id: NoteId) -> ReportTarget { @@ -54,9 +54,10 @@ struct Report { func create_report_tags(target: ReportTarget, type: ReportType) -> [[String]] { switch target { case .user(let pubkey): - return [["p", pubkey, type.rawValue]] + return [["p", pubkey.hex(), type.rawValue]] case .note(let notet): - return [["e", notet.note_id, type.rawValue], ["p", notet.pubkey]] + return [["e", notet.note_id.hex(), type.rawValue], + ["p", notet.pubkey.hex()]] } } diff --git a/damus/Models/RepostsModel.swift b/damus/Models/RepostsModel.swift @@ -9,7 +9,7 @@ import Foundation final class RepostsModel: EventsModel { - init(state: DamusState, target: String) { + init(state: DamusState, target: NoteId) { super.init(state: state, target: target, kind: .boost) } } diff --git a/damus/Models/SearchHomeModel.swift b/damus/Models/SearchHomeModel.swift @@ -13,7 +13,7 @@ class SearchHomeModel: ObservableObject { var events: EventHolder @Published var loading: Bool = false - var seen_pubkey: Set<String> = Set() + var seen_pubkey: Set<Pubkey> = Set() let damus_state: DamusState let base_subid = UUID().description let profiles_subid = UUID().description @@ -91,7 +91,7 @@ class SearchHomeModel: ObservableObject { } } -func find_profiles_to_fetch(profiles: Profiles, load: PubkeysToLoad, cache: EventCache) -> [String] { +func find_profiles_to_fetch(profiles: Profiles, load: PubkeysToLoad, cache: EventCache) -> [Pubkey] { switch load { case .from_events(let events): return find_profiles_to_fetch_from_events(profiles: profiles, events: events, cache: cache) @@ -100,13 +100,13 @@ func find_profiles_to_fetch(profiles: Profiles, load: PubkeysToLoad, cache: Even } } -func find_profiles_to_fetch_from_keys(profiles: Profiles, pks: [String]) -> [String] { +func find_profiles_to_fetch_from_keys(profiles: Profiles, pks: [Pubkey]) -> [Pubkey] { Array(Set(pks.filter { pk in !profiles.has_fresh_profile(id: pk) })) } -func find_profiles_to_fetch_from_events(profiles: Profiles, events: [NostrEvent], cache: EventCache) -> [String] { - var pubkeys = Set<String>() - +func find_profiles_to_fetch_from_events(profiles: Profiles, events: [NostrEvent], cache: EventCache) -> [Pubkey] { + var pubkeys = Set<Pubkey>() + for ev in events { // lookup profiles from boosted events if ev.known_kind == .boost, let bev = ev.get_inner_event(cache: cache), !profiles.has_fresh_profile(id: bev.pubkey) { @@ -123,7 +123,7 @@ func find_profiles_to_fetch_from_events(profiles: Profiles, events: [NostrEvent] enum PubkeysToLoad { case from_events([NostrEvent]) - case from_keys([String]) + case from_keys([Pubkey]) } func load_profiles(profiles_subid: String, relay_id: String, load: PubkeysToLoad, damus_state: DamusState) { diff --git a/damus/Models/ThreadModel.swift b/damus/Models/ThreadModel.swift @@ -128,7 +128,7 @@ class ThreadModel: ObservableObject { } -func get_top_zap(events: EventCache, evid: String) -> Zapping? { +func get_top_zap(events: EventCache, evid: NoteId) -> Zapping? { return events.get_cache_data(evid).zaps_model.zaps.first(where: { zap in !zap.request.marked_hidden }) diff --git a/damus/Models/UserSearchCache.swift b/damus/Models/UserSearchCache.swift @@ -11,15 +11,15 @@ import Foundation /// Optimized for fast searches of substrings by using a Trie. /// Optimal for performing user searches that could be initiated by typing quickly on a keyboard into a text input field. class UserSearchCache { - private let trie = Trie<String>() + private let trie = Trie<Pubkey>() - func search(key: String) -> [String] { + func search(key: String) -> [Pubkey] { let results = trie.find(key: key) return results } /// Computes the differences between an old profile, if it exists, and a new profile, and updates the user search cache accordingly. - func updateProfile(id: String, profiles: Profiles, oldProfile: Profile?, newProfile: Profile) { + func updateProfile(id: Pubkey, profiles: Profiles, oldProfile: Profile?, newProfile: Profile) { // Remove searchable keys tied to the old profile if they differ from the new profile // to keep the trie clean without empty nodes while avoiding excessive graph searching. if let oldProfile { @@ -38,7 +38,7 @@ class UserSearchCache { } /// Adds a profile to the user search cache. - private func addProfile(id: String, profiles: Profiles, profile: Profile) { + private func addProfile(id: Pubkey, profiles: Profiles, profile: Profile) { // Searchable by name. if let name = profile.name { trie.insert(key: name.lowercased(), value: id) @@ -56,7 +56,7 @@ class UserSearchCache { } /// Computes the diffences between an old contacts event and a new contacts event for our own user, and updates the search cache accordingly. - func updateOwnContactsPetnames(id: String, oldEvent: NostrEvent?, newEvent: NostrEvent) { + func updateOwnContactsPetnames(id: Pubkey, oldEvent: NostrEvent?, newEvent: NostrEvent) { guard newEvent.known_kind == .contacts && newEvent.pubkey == id else { return } diff --git a/damus/Models/UserSettingsStore.swift b/damus/Models/UserSettingsStore.swift @@ -11,7 +11,7 @@ import UIKit let fallback_zap_amount = 1000 func setting_property_key(key: String) -> String { - return pk_setting_key(UserSettingsStore.pubkey ?? "", key: key) + return pk_setting_key(UserSettingsStore.pubkey ?? .empty, key: key) } func setting_get_property_value<T>(key: String, scoped_key: String, default_value: T) -> T { @@ -63,7 +63,7 @@ func setting_set_property_value<T: Equatable>(scoped_key: String, old_value: T, private var value: T init(key: String, default_value: T) { - self.key = pk_setting_key(UserSettingsStore.pubkey ?? "", key: key) + self.key = pk_setting_key(UserSettingsStore.pubkey ?? .empty, key: key) if let loaded = UserDefaults.standard.string(forKey: self.key), let val = T.init(from: loaded) { self.value = val } else if let loaded = UserDefaults.standard.string(forKey: key), let val = T.init(from: loaded) { @@ -91,7 +91,7 @@ func setting_set_property_value<T: Equatable>(scoped_key: String, old_value: T, } class UserSettingsStore: ObservableObject { - static var pubkey: String? = nil + static var pubkey: Pubkey? = nil static var shared: UserSettingsStore? = nil static var bool_options = Set<String>() @@ -261,6 +261,6 @@ class UserSettingsStore: ObservableObject { } } -func pk_setting_key(_ pubkey: String, key: String) -> String { - return "\(pubkey)_\(key)" +func pk_setting_key(_ pubkey: Pubkey, key: String) -> String { + return "\(pubkey.hex())_\(key)" } diff --git a/damus/Nostr/Nostr.swift b/damus/Nostr/Nostr.swift @@ -201,7 +201,7 @@ class Profile: Codable { try container.encode(value) } - static func displayName(profile: Profile?, pubkey: String) -> DisplayName { + static func displayName(profile: Profile?, pubkey: Pubkey) -> DisplayName { return parse_display_name(profile: profile, pubkey: pubkey) } } diff --git a/damus/Nostr/NostrEvent.swift b/damus/Nostr/NostrEvent.swift @@ -379,7 +379,7 @@ func decode_data<T: Decodable>(_ data: Data) -> T? { return nil } -func event_commitment(pubkey: String, created_at: UInt32, kind: UInt32, tags: [[String]], content: String) -> String { +func event_commitment(pubkey: Pubkey, created_at: UInt32, kind: UInt32, tags: [[String]], content: String) -> String { let encoder = JSONEncoder() encoder.outputFormatting = .withoutEscapingSlashes let str_data = try! encoder.encode(content) @@ -393,12 +393,12 @@ func event_commitment(pubkey: String, created_at: UInt32, kind: UInt32, tags: [[ return "[0,\"\(pubkey)\",\(created_at),\(kind),\(tags),\(content)]" } -func calculate_event_commitment(pubkey: String, created_at: UInt32, kind: UInt32, tags: [[String]], content: String) -> Data { +func calculate_event_commitment(pubkey: Pubkey, created_at: UInt32, kind: UInt32, tags: [[String]], content: String) -> Data { let target = event_commitment(pubkey: pubkey, created_at: created_at, kind: kind, tags: tags, content: content) return target.data(using: .utf8)! } -func calculate_event_id(pubkey: String, created_at: UInt32, kind: UInt32, tags: [[String]], content: String) -> Data { +func calculate_event_id(pubkey: Pubkey, created_at: UInt32, kind: UInt32, tags: [[String]], content: String) -> Data { let commitment = calculate_event_commitment(pubkey: pubkey, created_at: created_at, kind: kind, tags: tags, content: content) return sha256(commitment) } @@ -497,7 +497,7 @@ func make_first_contact_event(keypair: Keypair) -> NostrEvent? { let damus_pubkey = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681" let tags = [ ["p", damus_pubkey], - ["p", keypair.pubkey] // you're a friend of yourself! + ["p", keypair.pubkey.hex()] // you're a friend of yourself! ] return NostrEvent(content: relay_json, keypair: keypair, kind: NostrKind.contacts.rawValue, tags: tags) } @@ -514,24 +514,25 @@ func make_boost_event(keypair: FullKeypair, boosted: NostrEvent) -> NostrEvent? var tags: [[String]] = boosted.tags.filter { tag in tag.count >= 2 && (tag[0] == "e" || tag[0] == "p") } tags.append(["e", boosted.id, "", "root"]) - tags.append(["p", boosted.pubkey]) + tags.append(["p", boosted.pubkey.hex()]) return NostrEvent(content: event_to_json(ev: boosted), keypair: keypair.to_keypair(), kind: 6, tags: tags) } func make_like_event(keypair: FullKeypair, liked: NostrEvent, content: String = "🤙") -> NostrEvent? { var tags: [[String]] = liked.tags.filter { tag in tag.count >= 2 && (tag[0] == "e" || tag[0] == "p") } - tags.append(["e", liked.id]) - tags.append(["p", liked.pubkey]) + tags.append(["e", liked.id.hex()]) + tags.append(["p", liked.pubkey.hex()]) return NostrEvent(content: content, keypair: keypair.to_keypair(), kind: 7, tags: tags) } func zap_target_to_tags(_ target: ZapTarget) -> [[String]] { switch target { case .profile(let pk): - return [["p", pk]] + return [["p", pk.hex()]] case .note(let note_target): - return [["e", note_target.note_id], ["p", note_target.author]] + return [["e", note_target.note_id.hex()], + ["p", note_target.author.hex()]] } } @@ -554,7 +555,7 @@ func make_private_zap_request_event(identity: FullKeypair, enc_key: FullKeypair, return PrivateZapRequest(req: ZapRequest(ev: note), enc: enc) } -func decrypt_private_zap(our_privkey: String, zapreq: NostrEvent, target: ZapTarget) -> NostrEvent? { +func decrypt_private_zap(our_privkey: Privkey, zapreq: NostrEvent, target: ZapTarget) -> NostrEvent? { guard let anon_tag = zapreq.tags.first(where: { t in t.count >= 2 && t[0] == "anon" }) else { return nil } @@ -732,7 +733,7 @@ func event_to_json(ev: NostrEvent) -> String { return str } -func decrypt_dm(_ privkey: String?, pubkey: String, content: String, encoding: EncEncoding) -> String? { +func decrypt_dm(_ privkey: Privkey?, pubkey: Pubkey, content: String, encoding: EncEncoding) -> String? { guard let privkey = privkey else { return nil } @@ -748,7 +749,7 @@ func decrypt_dm(_ privkey: String?, pubkey: String, content: String, encoding: E return String(data: dat, encoding: .utf8) } -func decrypt_note(our_privkey: String, their_pubkey: String, enc_note: String, encoding: EncEncoding) -> NostrEvent? { +func decrypt_note(our_privkey: Privkey, their_pubkey: Pubkey, enc_note: String, encoding: EncEncoding) -> NostrEvent? { guard let dec = decrypt_dm(our_privkey, pubkey: their_pubkey, content: enc_note, encoding: encoding) else { return nil } diff --git a/damus/Nostr/NostrFilter.swift b/damus/Nostr/NostrFilter.swift @@ -8,14 +8,14 @@ import Foundation struct NostrFilter: Codable, Equatable { - var ids: [String]? + var ids: [NoteId]? var kinds: [NostrKind]? - var referenced_ids: [String]? - var pubkeys: [String]? + var referenced_ids: [NoteId]? + var pubkeys: [Pubkey]? var since: UInt32? var until: UInt32? var limit: UInt32? - var authors: [String]? + var authors: [Pubkey]? var hashtag: [String]? var parameter: [String]? @@ -32,7 +32,7 @@ struct NostrFilter: Codable, Equatable { case limit } - init(ids: [String]? = nil, kinds: [NostrKind]? = nil, referenced_ids: [String]? = nil, pubkeys: [String]? = nil, since: UInt32? = nil, until: UInt32? = nil, limit: UInt32? = nil, authors: [String]? = nil, hashtag: [String]? = nil) { + init(ids: [NoteId]? = nil, kinds: [NostrKind]? = nil, referenced_ids: [NoteId]? = nil, pubkeys: [Pubkey]? = nil, since: UInt32? = nil, until: UInt32? = nil, limit: UInt32? = nil, authors: [Pubkey]? = nil, hashtag: [String]? = nil) { self.ids = ids self.kinds = kinds self.referenced_ids = referenced_ids diff --git a/damus/Nostr/NostrResponse.swift b/damus/Nostr/NostrResponse.swift @@ -8,7 +8,7 @@ import Foundation struct CommandResult { - let event_id: String + let event_id: NoteId let ok: Bool let msg: String } diff --git a/damus/Nostr/ProfileDatabase.swift b/damus/Nostr/ProfileDatabase.swift @@ -25,8 +25,8 @@ final class ProfileDatabase { private var queue = DispatchQueue(label: "io.damus.profile_db", qos: .userInteractive, attributes: .concurrent) - private var network_pull_date_cache = [String: Date]() - + private var network_pull_date_cache = [Pubkey: Date]() + init(cache_url: URL = ProfileDatabase.profile_cache_url) { self.cache_url = cache_url set_up() @@ -73,14 +73,14 @@ final class ProfileDatabase { background_context?.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType) } - private func get_persisted(id: String, context: NSManagedObjectContext) -> PersistedProfile? { + private func get_persisted(id: Pubkey, context: NSManagedObjectContext) -> PersistedProfile? { let request = NSFetchRequest<PersistedProfile>(entityName: entity_name) - request.predicate = NSPredicate(format: "id == %@", id) + request.predicate = NSPredicate(format: "id == %@", id.hex()) request.fetchLimit = 1 return try? context.fetch(request).first } - func get_network_pull_date(id: String) -> Date? { + func get_network_pull_date(id: Pubkey) -> Date? { var pull_date: Date? queue.sync { pull_date = network_pull_date_cache[id] @@ -90,7 +90,7 @@ final class ProfileDatabase { } let request = NSFetchRequest<PersistedProfile>(entityName: entity_name) - request.predicate = NSPredicate(format: "id == %@", id) + request.predicate = NSPredicate(format: "id == %@", id.hex()) request.fetchLimit = 1 request.propertiesToFetch = ["network_pull_date"] guard let profile = try? persistent_container?.viewContext.fetch(request).first else { @@ -111,7 +111,7 @@ final class ProfileDatabase { /// - id: Profile id (pubkey) /// - profile: Profile object to be stored /// - last_update: Date that the Profile was updated - func upsert(id: String, profile: Profile, last_update: Date) async throws { + func upsert(id: Pubkey, profile: Profile, last_update: Date) async throws { guard let context = background_context else { throw ProfileDatabaseError.missing_context } @@ -126,7 +126,7 @@ final class ProfileDatabase { } } else { persisted_profile = NSEntityDescription.insertNewObject(forEntityName: self.entity_name, into: context) as? PersistedProfile - persisted_profile?.id = id + persisted_profile?.id = id.hex() } persisted_profile?.copyValues(from: profile) persisted_profile?.last_update = last_update @@ -141,7 +141,7 @@ final class ProfileDatabase { } } - func get(id: String) -> Profile? { + func get(id: Pubkey) -> Profile? { guard let container = persistent_container, let profile = get_persisted(id: id, context: container.viewContext) else { return nil diff --git a/damus/Nostr/Profiles.swift b/damus/Nostr/Profiles.swift @@ -21,11 +21,11 @@ class Profiles { qos: .userInteractive, attributes: .concurrent) - private var profiles: [String: TimestampedProfile] = [:] - private var validated: [String: NIP05] = [:] - var nip05_pubkey: [String: String] = [:] - var zappers: [String: String] = [:] - + private var profiles: [Pubkey: TimestampedProfile] = [:] + private var validated: [Pubkey: NIP05] = [:] + var nip05_pubkey: [String: Pubkey] = [:] + var zappers: [Pubkey: Pubkey] = [:] + private let database = ProfileDatabase() let user_search_cache: UserSearchCache @@ -34,35 +34,35 @@ class Profiles { self.user_search_cache = user_search_cache } - func is_validated(_ pk: String) -> NIP05? { + func is_validated(_ pk: Pubkey) -> NIP05? { validated_queue.sync { validated[pk] } } - func invalidate_nip05(_ pk: String) { + func invalidate_nip05(_ pk: Pubkey) { validated_queue.async(flags: .barrier) { self.validated.removeValue(forKey: pk) } } - func set_validated(_ pk: String, nip05: NIP05?) { + func set_validated(_ pk: Pubkey, nip05: NIP05?) { validated_queue.async(flags: .barrier) { self.validated[pk] = nip05 } } - func enumerated() -> EnumeratedSequence<[String: TimestampedProfile]> { + func enumerated() -> EnumeratedSequence<[Pubkey: TimestampedProfile]> { return profiles_queue.sync { return profiles.enumerated() } } - func lookup_zapper(pubkey: String) -> String? { + func lookup_zapper(pubkey: Pubkey) -> Pubkey? { zappers[pubkey] } - func add(id: String, profile: TimestampedProfile) { + func add(id: Pubkey, profile: TimestampedProfile) { profiles_queue.async(flags: .barrier) { let old_timestamped_profile = self.profiles[id] self.profiles[id] = profile @@ -78,7 +78,7 @@ class Profiles { } } - func lookup(id: String) -> Profile? { + func lookup(id: Pubkey) -> Profile? { var profile: Profile? profiles_queue.sync { profile = profiles[id]?.profile @@ -86,14 +86,13 @@ class Profiles { return profile ?? database.get(id: id) } - func lookup_with_timestamp(id: String) -> TimestampedProfile? { + func lookup_with_timestamp(id: Pubkey) -> TimestampedProfile? { profiles_queue.sync { return profiles[id] } } - func has_fresh_profile(id: String) -> Bool { - // check memory first + func has_fresh_profile(id: Pubkey) -> Bool { var profile: Profile? profiles_queue.sync { profile = profiles[id]?.profile @@ -111,7 +110,7 @@ class Profiles { } -func invalidate_zapper_cache(pubkey: String, profiles: Profiles, lnurl: LNUrls) { +func invalidate_zapper_cache(pubkey: Pubkey, profiles: Profiles, lnurl: LNUrls) { profiles.zappers.removeValue(forKey: pubkey) lnurl.endpoints.removeValue(forKey: pubkey) } diff --git a/damus/Nostr/Relay.swift b/damus/Nostr/Relay.swift @@ -68,7 +68,7 @@ struct Limitations: Codable { struct RelayMetadata: Codable { let name: String? let description: String? - let pubkey: String? + let pubkey: Pubkey? let contact: String? let supported_nips: [Int]? let software: String? diff --git a/damus/Nostr/RelayPool.swift b/damus/Nostr/RelayPool.swift @@ -21,7 +21,7 @@ struct QueuedRequest { struct SeenEvent: Hashable { let relay_id: String - let evid: String + let evid: NoteId } class RelayPool { diff --git a/damus/Util/Bech32Object.swift b/damus/Util/Bech32Object.swift @@ -9,9 +9,9 @@ import Foundation enum Bech32Object { - case nsec(String) - case npub(String) - case note(String) + case nsec(Privkey) + case npub(Pubkey) + case note(NoteId) case nscript([UInt8]) static func parse(_ str: String) -> Bech32Object? { diff --git a/damus/Util/DisplayName.swift b/damus/Util/DisplayName.swift @@ -37,7 +37,7 @@ enum DisplayName { } -func parse_display_name(profile: Profile?, pubkey: String) -> DisplayName { +func parse_display_name(profile: Profile?, pubkey: Pubkey) -> DisplayName { if pubkey == ANON_PUBKEY { return .one(NSLocalizedString("Anonymous", comment: "Placeholder display name of anonymous user.")) } diff --git a/damus/Util/EventCache.swift b/damus/Util/EventCache.swift @@ -61,7 +61,7 @@ class ZapsDataModel: ObservableObject { self.zaps = zaps } - func confirm_nwc(reqid: String) { + func confirm_nwc(reqid: NoteId) { guard let zap = zaps.first(where: { z in z.request.ev.id == reqid }), case .pending(let pzap) = zap else { @@ -82,7 +82,7 @@ class ZapsDataModel: ObservableObject { zaps.reduce(0) { total, zap in total + zap.amount } } - func from(_ pubkey: String) -> [Zapping] { + func from(_ pubkey: Pubkey) -> [Zapping] { return self.zaps.filter { z in z.request.ev.pubkey == pubkey } } @@ -137,7 +137,7 @@ class EventData { } class EventCache { - private var events: [String: NostrEvent] = [:] + private var events: [NoteId: NostrEvent] = [:] private var replies = ReplyMap() private var cancellable: AnyCancellable? private var image_metadata: [String: ImageMetadataState] = [:] @@ -154,7 +154,7 @@ class EventCache { } } - func get_cache_data(_ evid: String) -> EventData { + func get_cache_data(_ evid: NoteId) -> EventData { guard let data = event_data[evid] else { let data = EventData() event_data[evid] = data @@ -164,11 +164,11 @@ class EventCache { return data } - func is_event_valid(_ evid: String) -> ValidationResult { + func is_event_valid(_ evid: NoteId) -> ValidationResult { return get_cache_data(evid).validated } - func store_event_validation(evid: String, validated: ValidationResult) { + func store_event_validation(evid: NoteId, validated: ValidationResult) { get_cache_data(evid).validated = validated } @@ -278,7 +278,7 @@ class EventCache { return ev } - func lookup(_ evid: String) -> NostrEvent? { + func lookup(_ evid: NoteId) -> NostrEvent? { return events[evid] } diff --git a/damus/Util/Keys.swift b/damus/Util/Keys.swift @@ -12,8 +12,8 @@ let PUBKEY_HRP = "npub" let ANON_PUBKEY = "anon" struct FullKeypair: Equatable { - let pubkey: String - let privkey: String + let pubkey: Pubkey + let privkey: Privkey func to_keypair() -> Keypair { return Keypair(pubkey: pubkey, privkey: privkey) @@ -21,11 +21,11 @@ struct FullKeypair: Equatable { } struct Keypair { - let pubkey: String - let privkey: String? + let pubkey: Pubkey + let privkey: Privkey? let pubkey_bech32: String let privkey_bech32: String? - + func to_full() -> FullKeypair? { guard let privkey = self.privkey else { return nil @@ -33,8 +33,12 @@ struct Keypair { return FullKeypair(pubkey: pubkey, privkey: privkey) } - - init(pubkey: String, privkey: String?) { + + static func just_pubkey(_ pk: Pubkey) -> Keypair { + return .init(pubkey: pk, privkey: nil) + } + + init(pubkey: Pubkey, privkey: Privkey?) { self.pubkey = pubkey self.privkey = privkey self.pubkey_bech32 = bech32_pubkey(pubkey) ?? pubkey @@ -43,8 +47,8 @@ struct Keypair { } enum Bech32Key { - case pub(String) - case sec(String) + case pub(Pubkey) + case sec(Privkey) } func decode_bech32_key(_ key: String) -> Bech32Key? { @@ -105,7 +109,7 @@ func generate_new_keypair() -> Keypair { return Keypair(pubkey: pubkey, privkey: privkey) } -func privkey_to_pubkey_raw(sec: [UInt8]) -> String? { +func privkey_to_pubkey_raw(sec: [UInt8]) -> Pubkey? { guard let key = try? secp256k1.Signing.PrivateKey(rawRepresentation: sec) else { return nil } @@ -117,8 +121,8 @@ func privkey_to_pubkey(privkey: String) -> String? { return privkey_to_pubkey_raw(sec: sec) } -func save_pubkey(pubkey: String) { - UserDefaults.standard.set(pubkey, forKey: "pubkey") +func save_pubkey(pubkey: Pubkey) { + UserDefaults.standard.set(pubkey.hex(), forKey: "pubkey") } enum Keys { @@ -126,8 +130,8 @@ enum Keys { static var privkey: String? } -func save_privkey(privkey: String) throws { - Keys.privkey = privkey +func save_privkey(privkey: Privkey) throws { + Keys.privkey = privkey.hex() } func clear_saved_privkey() throws { @@ -138,7 +142,7 @@ func clear_saved_pubkey() { UserDefaults.standard.removeObject(forKey: "pubkey") } -func save_keypair(pubkey: String, privkey: String) throws { +func save_keypair(pubkey: Pubkey, privkey: Privkey) throws { save_pubkey(pubkey: pubkey) try save_privkey(privkey: privkey) } diff --git a/damus/Util/LNUrls.swift b/damus/Util/LNUrls.swift @@ -15,14 +15,14 @@ enum LNUrlState { } class LNUrls { - var endpoints: [String: LNUrlState] + var endpoints: [Pubkey: LNUrlState] init() { self.endpoints = [:] } @MainActor - func lookup_or_fetch(pubkey: String, lnurl: String) async -> LNUrlPayRequest? { + func lookup_or_fetch(pubkey: Pubkey, lnurl: String) async -> LNUrlPayRequest? { switch lookup(pubkey: pubkey) { case .failed(let tries): print("lnurls.lookup_or_fetch failed \(tries) \(lnurl)") @@ -57,7 +57,7 @@ class LNUrls { return v } - func lookup(pubkey: String) -> LNUrlState { + func lookup(pubkey: Pubkey) -> LNUrlState { return self.endpoints[pubkey] ?? .not_fetched } } diff --git a/damus/Util/NIP05.swift b/damus/Util/NIP05.swift @@ -30,7 +30,7 @@ struct NIP05 { struct NIP05Response: Decodable { - let names: [String: String] + let names: [String: Pubkey] } func fetch_nip05(nip05: NIP05) async -> NIP05Response? { @@ -51,7 +51,7 @@ func fetch_nip05(nip05: NIP05) async -> NIP05Response? { return decoded } -func validate_nip05(pubkey: String, nip05_str: String) async -> NIP05? { +func validate_nip05(pubkey: Pubkey, nip05_str: String) async -> NIP05? { guard let nip05 = NIP05.parse(nip05_str) else { return nil } diff --git a/damus/Util/PostBox.swift b/damus/Util/PostBox.swift @@ -55,8 +55,8 @@ enum CancelSendErr { class PostBox { let pool: RelayPool - var events: [String: PostedEvent] - + var events: [NoteId: PostedEvent] + init(pool: RelayPool) { self.pool = pool self.events = [:] @@ -64,7 +64,7 @@ class PostBox { } // only works reliably on delay-sent events - func cancel_send(evid: String) -> CancelSendErr? { + func cancel_send(evid: NoteId) -> CancelSendErr? { guard let ev = events[evid] else { return .nothing_to_cancel } @@ -114,7 +114,7 @@ class PostBox { } @discardableResult - func remove_relayer(relay_id: String, event_id: String) -> Bool { + func remove_relayer(relay_id: String, event_id: NoteId) -> Bool { guard let ev = self.events[event_id] else { return false } diff --git a/damus/Util/PreviewCache.swift b/damus/Util/PreviewCache.swift @@ -65,9 +65,9 @@ enum PreviewState { } class PreviewCache { - private var previews: [String: Preview] = [:] + private var previews: [NoteId: Preview] = [:] - func lookup(_ evid: String) -> Preview? { + func lookup(_ evid: NoteId) -> Preview? { return previews[evid] } } diff --git a/damus/Util/Relays/RelayBootstrap.swift b/damus/Util/Relays/RelayBootstrap.swift @@ -14,17 +14,17 @@ let BOOTSTRAP_RELAYS = [ "wss://nos.lol", ] -func bootstrap_relays_setting_key(pubkey: String) -> String { +func bootstrap_relays_setting_key(pubkey: Pubkey) -> String { return pk_setting_key(pubkey, key: "bootstrap_relays") } -func save_bootstrap_relays(pubkey: String, relays: [String]) { +func save_bootstrap_relays(pubkey: Pubkey, relays: [String]) { let key = bootstrap_relays_setting_key(pubkey: pubkey) UserDefaults.standard.set(relays, forKey: key) } -func load_bootstrap_relays(pubkey: String) -> [String] { +func load_bootstrap_relays(pubkey: Pubkey) -> [String] { let key = bootstrap_relays_setting_key(pubkey: pubkey) guard let relays = UserDefaults.standard.stringArray(forKey: key) else { diff --git a/damus/Util/Relays/RelayFilters.swift b/damus/Util/Relays/RelayFilters.swift @@ -18,7 +18,7 @@ struct RelayFilter: Hashable { } class RelayFilters { - private let our_pubkey: String + private let our_pubkey: Pubkey private var disabled: Set<RelayFilter> func is_filtered(timeline: Timeline, relay_id: String) -> Bool { @@ -47,23 +47,23 @@ class RelayFilters { save_relay_filters(our_pubkey, filters: disabled) } - init(our_pubkey: String) { + init(our_pubkey: Pubkey) { self.our_pubkey = our_pubkey disabled = load_relay_filters(our_pubkey) ?? Set() } } -func save_relay_filters(_ pubkey: String, filters: Set<RelayFilter>) { +func save_relay_filters(_ pubkey: Pubkey, filters: Set<RelayFilter>) { let key = pk_setting_key(pubkey, key: "relay_filters") let arr = Array(filters.map { filter in "\(filter.timeline)\t\(filter.relay_id)" }) UserDefaults.standard.set(arr, forKey: key) } -func relay_filter_setting_key(_ pubkey: String) -> String { +func relay_filter_setting_key(_ pubkey: Pubkey) -> String { return pk_setting_key(pubkey, key: "relay_filters") } -func load_relay_filters(_ pubkey: String) -> Set<RelayFilter>? { +func load_relay_filters(_ pubkey: Pubkey) -> Set<RelayFilter>? { let key = relay_filter_setting_key(pubkey) guard let filters = UserDefaults.standard.stringArray(forKey: key) else { return nil diff --git a/damus/Util/ReplyCounter.swift b/damus/Util/ReplyCounter.swift @@ -8,23 +8,23 @@ import Foundation class ReplyCounter { - private var replies: [String: Int] - private var counted: Set<String> - private var our_replies: [String: NostrEvent] - private let our_pubkey: String - - init(our_pubkey: String) { + private var replies: [NoteId: Int] + private var counted: Set<NoteId> + private var our_replies: [NoteId: NostrEvent] + private let our_pubkey: Pubkey + + init(our_pubkey: Pubkey) { self.our_pubkey = our_pubkey replies = [:] counted = Set() our_replies = [:] } - func our_reply(_ evid: String) -> NostrEvent? { + func our_reply(_ evid: NoteId) -> NostrEvent? { return our_replies[evid] } - func get_replies(_ evid: String) -> Int { + func get_replies(_ evid: NoteId) -> Int { return replies[evid] ?? 0 } diff --git a/damus/Util/Router.swift b/damus/Util/Router.swift @@ -8,13 +8,13 @@ import SwiftUI enum Route: Hashable { - case ProfileByKey(pubkey: String) + case ProfileByKey(pubkey: Pubkey) case Profile(profile: ProfileModel, followers: FollowersModel) case Followers(followers: FollowersModel) case Relay(relay: String, showActionButtons: Binding<Bool>) case RelayDetail(relay: String, metadata: RelayMetadata?) case Following(following: FollowingModel) - case MuteList(users: [String]) + case MuteList(users: [Pubkey]) case RelayConfig case Script(script: ScriptModel) case Bookmarks @@ -41,7 +41,7 @@ enum Route: Hashable { case SaveKeys(account: CreateAccountModel) case Wallet(wallet: WalletModel) case WalletScanner(result: Binding<WalletScanResult>) - case FollowersYouKnow(friendedFollowers: [String], followers: FollowersModel) + case FollowersYouKnow(friendedFollowers: [Pubkey], followers: FollowersModel) @ViewBuilder func view(navigationCoordinator: NavigationCoordinator, damusState: DamusState) -> some View { diff --git a/damus/Util/WalletConnect.swift b/damus/Util/WalletConnect.swift @@ -16,16 +16,16 @@ struct WalletConnectURL: Equatable { let relay: RelayURL let keypair: FullKeypair - let pubkey: String + let pubkey: Pubkey let lud16: String? func to_url() -> URL { var urlComponents = URLComponents() urlComponents.scheme = "nostrwalletconnect" - urlComponents.host = pubkey + urlComponents.host = pubkey.hex() urlComponents.queryItems = [ URLQueryItem(name: "relay", value: relay.id), - URLQueryItem(name: "secret", value: keypair.privkey) + URLQueryItem(name: "secret", value: keypair.privkey.hex()) ] if let lud16 { @@ -55,7 +55,7 @@ struct WalletConnectURL: Equatable { self = WalletConnectURL(pubkey: pk, relay: relay_url, keypair: keypair, lud16: lud16) } - init(pubkey: String, relay: RelayURL, keypair: FullKeypair, lud16: String?) { + init(pubkey: Pubkey, relay: RelayURL, keypair: FullKeypair, lud16: String?) { self.pubkey = pubkey self.relay = relay self.keypair = keypair @@ -86,7 +86,7 @@ enum WalletResponseResult { } struct FullWalletResponse { - let req_id: String + let req_id: NoteId let response: WalletResponse init?(from: NostrEvent, nwc: WalletConnectURL) async { @@ -165,7 +165,7 @@ struct PayInvoiceRequest: Codable { let invoice: String } -func make_wallet_connect_request<T>(req: WalletRequest<T>, to_pk: String, keypair: FullKeypair) -> NostrEvent? { +func make_wallet_connect_request<T>(req: WalletRequest<T>, to_pk: Pubkey, keypair: FullKeypair) -> NostrEvent? { let tags = [["p", to_pk]] let created_at = UInt32(Date().timeIntervalSince1970) guard let content = encode_json(req) else { diff --git a/damus/Util/Zap.swift b/damus/Util/Zap.swift @@ -7,20 +7,20 @@ import Foundation -public struct NoteZapTarget: Equatable, Hashable { - public let note_id: String - public let author: String +struct NoteZapTarget: Equatable, Hashable { + public let note_id: NoteId + public let author: Pubkey } -public enum ZapTarget: Equatable { - case profile(String) +enum ZapTarget: Equatable, Hashable { + case profile(Pubkey) case note(NoteZapTarget) - public static func note(id: String, author: String) -> ZapTarget { + static func note(id: NoteId, author: Pubkey) -> ZapTarget { return .note(NoteZapTarget(note_id: id, author: author)) } - - var pubkey: String { + + var pubkey: Pubkey { switch self { case .profile(let pk): return pk @@ -258,7 +258,7 @@ enum Zapping { struct Zap { public let event: NostrEvent public let invoice: ZapInvoice - public let zapper: String /// zap authorizer + public let zapper: Pubkey /// zap authorizer public let target: ZapTarget public let raw_request: ZapRequest public let is_anon: Bool @@ -268,7 +268,7 @@ struct Zap { return private_request ?? self.raw_request } - public static func from_zap_event(zap_ev: NostrEvent, zapper: String, our_privkey: String?) -> Zap? { + public static func from_zap_event(zap_ev: NostrEvent, zapper: Pubkey, our_privkey: Privkey?) -> Zap? { /// Make sure that we only create a zap event if it is authorized by the profile or event guard zapper == zap_ev.pubkey else { return nil diff --git a/damus/Util/Zaps.swift b/damus/Util/Zaps.swift @@ -8,14 +8,14 @@ import Foundation class Zaps { - private(set) var zaps: [String: Zapping] - let our_pubkey: String - var our_zaps: [String: [Zapping]] + private(set) var zaps: [NoteId: Zapping] + let our_pubkey: Pubkey + var our_zaps: [NoteId: [Zapping]] - private(set) var event_counts: [String: Int] - private(set) var event_totals: [String: Int64] - - init(our_pubkey: String) { + private(set) var event_counts: [NoteId: Int] + private(set) var event_totals: [NoteId: Int64] + + init(our_pubkey: Pubkey) { self.zaps = [:] self.our_pubkey = our_pubkey self.our_zaps = [:] @@ -23,7 +23,7 @@ class Zaps { self.event_totals = [:] } - func remove_zap(reqid: String) -> Zapping? { + func remove_zap(reqid: NoteId) -> Zapping? { var res: Zapping? = nil for kv in our_zaps { let ours = kv.value diff --git a/damus/Views/ActionBar/EventDetailBar.swift b/damus/Views/ActionBar/EventDetailBar.swift @@ -9,12 +9,12 @@ import SwiftUI struct EventDetailBar: View { let state: DamusState - let target: String - let target_pk: String - + let target: NoteId + let target_pk: Pubkey + @ObservedObject var bar: ActionBarModel - init(state: DamusState, target: String, target_pk: String) { + init(state: DamusState, target: NoteId, target_pk: Pubkey) { self.state = state self.target = target self.target_pk = target_pk @@ -56,6 +56,6 @@ struct EventDetailBar: View { struct EventDetailBar_Previews: PreviewProvider { static var previews: some View { - EventDetailBar(state: test_damus_state(), target: "", target_pk: "") + EventDetailBar(state: test_damus_state(), target: .empty, target_pk: .empty) } } diff --git a/damus/Views/BannerImageView.swift b/damus/Views/BannerImageView.swift @@ -63,12 +63,12 @@ struct InnerBannerImageView: View { struct BannerImageView: View { let disable_animation: Bool - let pubkey: String + let pubkey: Pubkey let profiles: Profiles @State var banner: String? - init(pubkey: String, profiles: Profiles, disable_animation: Bool, banner: String? = nil) { + init(pubkey: Pubkey, profiles: Profiles, disable_animation: Bool, banner: String? = nil) { self.pubkey = pubkey self.profiles = profiles self._banner = State(initialValue: banner) @@ -89,7 +89,7 @@ struct BannerImageView: View { } } -func get_banner_url(banner: String?, pubkey: String, profiles: Profiles) -> URL? { +func get_banner_url(banner: String?, pubkey: Pubkey, profiles: Profiles) -> URL? { let bannerUrlString = banner ?? profiles.lookup(id: pubkey)?.banner ?? "" if let url = URL(string: bannerUrlString) { return url @@ -98,12 +98,10 @@ func get_banner_url(banner: String?, pubkey: String, profiles: Profiles) -> URL? } struct BannerImageView_Previews: PreviewProvider { - static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846" - static var previews: some View { BannerImageView( - pubkey: pubkey, - profiles: make_preview_profiles(pubkey), + pubkey: test_pubkey, + profiles: make_preview_profiles(test_pubkey), disable_animation: false ) } diff --git a/damus/Views/CreateAccountView.swift b/damus/Views/CreateAccountView.swift @@ -134,8 +134,8 @@ struct CreateAccountView_Previews: PreviewProvider { } } -func KeyText(_ text: Binding<String>) -> some View { - let decoded = hex_decode(text.wrappedValue)! +func KeyText(_ pubkey: Binding<Pubkey>) -> some View { + let decoded = hex_decode(pubkey.wrappedValue)! let bechkey = bech32_encode(hrp: PUBKEY_HRP, decoded) return Text(bechkey) .textSelection(.enabled) diff --git a/damus/Views/DMChatView.swift b/damus/Views/DMChatView.swift @@ -13,7 +13,7 @@ struct DMChatView: View, KeyboardReadable { @ObservedObject var dms: DirectMessageModel @State var showPrivateKeyWarning: Bool = false - var pubkey: String { + var pubkey: Pubkey { dms.pubkey } @@ -128,7 +128,7 @@ struct DMChatView: View, KeyboardReadable { } func send_message() { - let tags = [["p", pubkey]] + let tags = [["p", pubkey.hex()]] let post_blocks = parse_post_blocks(content: dms.draft) let content = render_blocks(blocks: post_blocks) @@ -190,7 +190,7 @@ enum EncEncoding { case bech32 } -func encrypt_message(message: String, privkey: String, to_pk: String, encoding: EncEncoding = .base64) -> String? { +func encrypt_message(message: String, privkey: Privkey, to_pk: Pubkey, encoding: EncEncoding = .base64) -> String? { let iv = random_bytes(count: 16).bytes guard let shared_sec = get_shared_secret(privkey: privkey, pubkey: to_pk) else { return nil @@ -209,7 +209,7 @@ func encrypt_message(message: String, privkey: String, to_pk: String, encoding: } -func create_encrypted_event(_ message: String, to_pk: String, tags: [[String]], keypair: FullKeypair, created_at: UInt32, kind: UInt32) -> NostrEvent? { +func create_encrypted_event(_ message: String, to_pk: Pubkey, tags: [[String]], keypair: FullKeypair, created_at: UInt32, kind: UInt32) -> NostrEvent? { let privkey = keypair.privkey guard let enc_content = encrypt_message(message: message, privkey: privkey, to_pk: to_pk) else { @@ -219,7 +219,7 @@ func create_encrypted_event(_ message: String, to_pk: String, tags: [[String]], return NostrEvent(content: enc_content, keypair: keypair.to_keypair(), kind: kind, tags: tags, createdAt: created_at) } -func create_dm(_ message: String, to_pk: String, tags: [[String]], keypair: Keypair, created_at: UInt32? = nil) -> NostrEvent? +func create_dm(_ message: String, to_pk: Pubkey, tags: [[String]], keypair: Keypair, created_at: UInt32? = nil) -> NostrEvent? { let created = created_at ?? UInt32(Date().timeIntervalSince1970) diff --git a/damus/Views/EventView.swift b/damus/Views/EventView.swift @@ -20,9 +20,9 @@ struct EventView: View { let event: NostrEvent let options: EventViewOptions let damus: DamusState - let pubkey: String + let pubkey: Pubkey - init(damus: DamusState, event: NostrEvent, pubkey: String? = nil, options: EventViewOptions = []) { + init(damus: DamusState, event: NostrEvent, pubkey: Pubkey? = nil, options: EventViewOptions = []) { self.event = event self.options = options self.damus = damus @@ -54,7 +54,7 @@ struct EventView: View { } // blame the porn bots for this code -func should_show_images(settings: UserSettingsStore, contacts: Contacts, ev: NostrEvent, our_pubkey: String, booster_pubkey: String? = nil) -> Bool { +func should_show_images(settings: UserSettingsStore, contacts: Contacts, ev: NostrEvent, our_pubkey: Pubkey, booster_pubkey: Pubkey? = nil) -> Bool { if settings.always_show_images { return true } @@ -72,7 +72,7 @@ func should_show_images(settings: UserSettingsStore, contacts: Contacts, ev: Nos } extension View { - func pubkey_context_menu(bech32_pubkey: String) -> some View { + func pubkey_context_menu(bech32_pubkey: Pubkey) -> some View { return self.contextMenu { Button { UIPasteboard.general.string = bech32_pubkey @@ -96,7 +96,7 @@ func format_date(_ created_at: UInt32) -> String { return dateFormatter.string(from: date) } -func make_actionbar_model(ev: String, damus: DamusState) -> ActionBarModel { +func make_actionbar_model(ev: NoteId, damus: DamusState) -> ActionBarModel { let model = ActionBarModel.empty() model.update(damus: damus, evid: ev) return model diff --git a/damus/Views/Events/BuilderEventView.swift b/damus/Views/Events/BuilderEventView.swift @@ -9,7 +9,7 @@ import SwiftUI struct BuilderEventView: View { let damus: DamusState - let event_id: String + let event_id: NoteId @State var event: NostrEvent? @State var subscription_uuid: String = UUID().description @@ -19,7 +19,7 @@ struct BuilderEventView: View { self.event_id = event.id } - init(damus: DamusState, event_id: String) { + init(damus: DamusState, event_id: NoteId) { let event = damus.events.lookup(event_id) self.event_id = event_id self.damus = damus diff --git a/damus/Views/Events/Components/EventTop.swift b/damus/Views/Events/Components/EventTop.swift @@ -10,10 +10,10 @@ import SwiftUI struct EventTop: View { let state: DamusState let event: NostrEvent - let pubkey: String + let pubkey: Pubkey let is_anon: Bool - init(state: DamusState, event: NostrEvent, pubkey: String, is_anon: Bool) { + init(state: DamusState, event: NostrEvent, pubkey: Pubkey, is_anon: Bool) { self.state = state self.event = event self.pubkey = pubkey diff --git a/damus/Views/Events/Components/ReplyPart.swift b/damus/Views/Events/Components/ReplyPart.swift @@ -9,7 +9,7 @@ import SwiftUI struct ReplyPart: View { let event: NostrEvent - let privkey: String? + let privkey: Privkey? let profiles: Profiles var body: some View { diff --git a/damus/Views/Events/EventMenu.swift b/damus/Views/Events/EventMenu.swift @@ -10,7 +10,7 @@ import SwiftUI struct EventMenuContext: View { let event: NostrEvent let keypair: Keypair - let target_pubkey: String + let target_pubkey: Pubkey let bookmarks: BookmarksManager let muted_threads: MutedThreadsManager @ObservedObject var settings: UserSettingsStore @@ -44,7 +44,7 @@ struct EventMenuContext: View { struct MenuItems: View { let event: NostrEvent let keypair: Keypair - let target_pubkey: String + let target_pubkey: Pubkey let bookmarks: BookmarksManager let muted_threads: MutedThreadsManager @ObservedObject var settings: UserSettingsStore @@ -52,7 +52,7 @@ struct MenuItems: View { @State private var isBookmarked: Bool = false @State private var isMutedThread: Bool = false - init(event: NostrEvent, keypair: Keypair, target_pubkey: String, bookmarks: BookmarksManager, muted_threads: MutedThreadsManager, settings: UserSettingsStore) { + init(event: NostrEvent, keypair: Keypair, target_pubkey: Pubkey, bookmarks: BookmarksManager, muted_threads: MutedThreadsManager, settings: UserSettingsStore) { let bookmarked = bookmarks.isBookmarked(event) self._isBookmarked = State(initialValue: bookmarked) diff --git a/damus/Views/Events/EventProfile.swift b/damus/Views/Events/EventProfile.swift @@ -24,7 +24,7 @@ func eventview_pfp_size(_ size: EventViewKind) -> CGFloat { struct EventProfile: View { let damus_state: DamusState - let pubkey: String + let pubkey: Pubkey let profile: Profile? let size: EventViewKind diff --git a/damus/Views/Events/EventShell.swift b/damus/Views/Events/EventShell.swift @@ -10,11 +10,11 @@ import SwiftUI struct EventShell<Content: View>: View { let state: DamusState let event: NostrEvent - let pubkey: String + let pubkey: Pubkey let options: EventViewOptions let content: Content - init(state: DamusState, event: NostrEvent, pubkey: String, options: EventViewOptions, @ViewBuilder content: () -> Content) { + init(state: DamusState, event: NostrEvent, pubkey: Pubkey, options: EventViewOptions, @ViewBuilder content: () -> Content) { self.state = state self.event = event self.options = options diff --git a/damus/Views/Events/SelectedEventView.swift b/damus/Views/Events/SelectedEventView.swift @@ -12,7 +12,7 @@ struct SelectedEventView: View { let event: NostrEvent let size: EventViewKind - var pubkey: String { + var pubkey: Pubkey { event.pubkey } diff --git a/damus/Views/Events/TextEvent.swift b/damus/Views/Events/TextEvent.swift @@ -26,11 +26,11 @@ struct EventViewOptions: OptionSet { struct TextEvent: View { let damus: DamusState let event: NostrEvent - let pubkey: String + let pubkey: Pubkey let options: EventViewOptions let evdata: EventData - init(damus: DamusState, event: NostrEvent, pubkey: String, options: EventViewOptions) { + init(damus: DamusState, event: NostrEvent, pubkey: Pubkey, options: EventViewOptions) { self.damus = damus self.event = event self.pubkey = pubkey diff --git a/damus/Views/FollowingView.swift b/damus/Views/FollowingView.swift @@ -26,7 +26,7 @@ struct FollowUserView: View { struct FollowersYouKnowView: View { let damus_state: DamusState - let friended_followers: [String] + let friended_followers: [Pubkey] @ObservedObject var followers: FollowersModel var body: some View { diff --git a/damus/Views/ImagePicker.swift b/damus/Views/ImagePicker.swift @@ -15,7 +15,7 @@ struct ImagePicker: UIViewControllerRepresentable { let uploader: MediaUploader let sourceType: UIImagePickerController.SourceType - let pubkey: String + let pubkey: Pubkey @Binding var image_upload_confirm: Bool var imagesOnly: Bool = false let onImagePicked: (URL) -> Void diff --git a/damus/Views/Images/ProfilePicImageView.swift b/damus/Views/Images/ProfilePicImageView.swift @@ -62,7 +62,7 @@ struct NavDismissBarView: View { } struct ProfilePicImageView: View { - let pubkey: String + let pubkey: Pubkey let profiles: Profiles let disable_animation: Bool @@ -90,12 +90,10 @@ struct ProfilePicImageView: View { } struct ProfileZoomView_Previews: PreviewProvider { - static let pubkey = "ca48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846" - static var previews: some View { ProfilePicImageView( - pubkey: pubkey, - profiles: make_preview_profiles(pubkey), + pubkey: test_pubkey, + profiles: make_preview_profiles(test_pubkey), disable_animation: false ) } diff --git a/damus/Views/LoginView.swift b/damus/Views/LoginView.swift @@ -8,8 +8,8 @@ import SwiftUI enum ParsedKey { - case pub(String) - case priv(String) + case pub(Pubkey) + case priv(Privkey) case hex(String) case nip05(String) @@ -203,7 +203,7 @@ func process_login(_ key: ParsedKey, is_pubkey: Bool) async throws { } } - func handle_privkey(_ privkey: String) throws { + func handle_privkey(_ privkey: Privkey) throws { try save_privkey(privkey: privkey) guard let pk = privkey_to_pubkey(privkey: privkey) else { @@ -231,7 +231,7 @@ struct NIP05Result: Decodable { } struct NIP05User { - let pubkey: String + let pubkey: Pubkey let relays: [String] } diff --git a/damus/Views/Muting/MutelistView.swift b/damus/Views/Muting/MutelistView.swift @@ -9,9 +9,9 @@ import SwiftUI struct MutelistView: View { let damus_state: DamusState - @State var users: [String] + @State var users: [Pubkey] - func RemoveAction(pubkey: String) -> some View { + func RemoveAction(pubkey: Pubkey) -> some View { Button { guard let mutelist = damus_state.contacts.mutelist else { return diff --git a/damus/Views/NoteContentView.swift b/damus/Views/NoteContentView.swift @@ -392,7 +392,7 @@ func note_artifact_is_separated(kind: NostrKind?) -> Bool { return kind != .longform } -func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: String?) -> NoteArtifacts { +func render_note_content(ev: NostrEvent, profiles: Profiles, privkey: Privkey?) -> NoteArtifacts { let blocks = ev.blocks(privkey) if ev.known_kind == .longform { @@ -574,7 +574,7 @@ func classify_url(_ url: URL) -> UrlType { return .link(url) } -func lookup_cached_preview_size(previews: PreviewCache, evid: String) -> CGFloat? { +func lookup_cached_preview_size(previews: PreviewCache, evid: NoteId) -> CGFloat? { guard case .value(let cached) = previews.lookup(evid) else { return nil } diff --git a/damus/Views/Notifications/EventGroupView.swift b/damus/Views/Notifications/EventGroupView.swift @@ -56,7 +56,7 @@ enum ReactingTo { case your_profile } -func determine_reacting_to(our_pubkey: String, ev: NostrEvent?) -> ReactingTo { +func determine_reacting_to(our_pubkey: Pubkey, ev: NostrEvent?) -> ReactingTo { guard let ev else { return .your_profile } @@ -68,21 +68,21 @@ func determine_reacting_to(our_pubkey: String, ev: NostrEvent?) -> ReactingTo { return .tagged_in } -func event_author_name(profiles: Profiles, pubkey: String) -> String { +func event_author_name(profiles: Profiles, pubkey: Pubkey) -> String { let alice_prof = profiles.lookup(id: pubkey) return Profile.displayName(profile: alice_prof, pubkey: pubkey).username.truncate(maxLength: 50) } -func event_group_unique_pubkeys(profiles: Profiles, group: EventGroupType) -> [String] { - var seen = Set<String>() - var sorted = [String]() +func event_group_unique_pubkeys(profiles: Profiles, group: EventGroupType) -> [Pubkey] { + var seen = Set<Pubkey>() + var sorted = [Pubkey]() if let zapgrp = group.zap_group { let zaps = zapgrp.zaps for i in 0..<zaps.count { let zap = zapgrp.zaps[i] - let pubkey: String + let pubkey: Pubkey if zap.is_anon { pubkey = ANON_PUBKEY @@ -148,7 +148,7 @@ func event_group_unique_pubkeys(profiles: Profiles, group: EventGroupType) -> [S "zapped_your_profile_2" - returned when 2 zaps occurred to the current user's profile "zapped_your_profile_3" - returned when 3 or more zaps occurred to the current user's profile */ -func reacting_to_text(profiles: Profiles, our_pubkey: String, group: EventGroupType, ev: NostrEvent?, pubkeys: [String], locale: Locale? = nil) -> String { +func reacting_to_text(profiles: Profiles, our_pubkey: Pubkey, group: EventGroupType, ev: NostrEvent?, pubkeys: [Pubkey], locale: Locale? = nil) -> String { if group.events.count == 0 { return "??" } @@ -192,7 +192,7 @@ struct EventGroupView: View { let event: NostrEvent? let group: EventGroupType - func GroupDescription(_ pubkeys: [String]) -> some View { + func GroupDescription(_ pubkeys: [Pubkey]) -> some View { Text(verbatim: "\(reacting_to_text(profiles: state.profiles, our_pubkey: state.pubkey, group: group, ev: event, pubkeys: pubkeys))") } diff --git a/damus/Views/Notifications/NotificationsView.swift b/damus/Views/Notifications/NotificationsView.swift @@ -23,7 +23,7 @@ enum FriendFilter: String, StringCodable { self.rawValue } - func filter(contacts: Contacts, pubkey: String) -> Bool { + func filter(contacts: Contacts, pubkey: Pubkey) -> Bool { switch self { case .all: return true diff --git a/damus/Views/Notifications/ProfilePicturesView.swift b/damus/Views/Notifications/ProfilePicturesView.swift @@ -9,8 +9,8 @@ import SwiftUI struct ProfilePicturesView: View { let state: DamusState - let pubkeys: [String] - + let pubkeys: [Pubkey] + var body: some View { HStack { ForEach(pubkeys.prefix(8), id: \.self) { pubkey in diff --git a/damus/Views/Onboarding/SuggestedUserView.swift b/damus/Views/Onboarding/SuggestedUserView.swift @@ -8,13 +8,13 @@ import SwiftUI struct SuggestedUser: Codable { - let pubkey: String + let pubkey: Pubkey let name: String let about: String let pfp: URL let profile: Profile - init?(profile: Profile, pubkey: String) { + init?(profile: Profile, pubkey: Pubkey) { guard let name = profile.name, let about = profile.about, @@ -64,7 +64,7 @@ struct SuggestedUserView_Previews: PreviewProvider { static var previews: some View { let profile = Profile(name: "klabo", about: "A person who likes nostr a lot and I like to tell people about myself in very long-winded ways that push the limits of UI and almost break things", picture: "https://primal.b-cdn.net/media-cache?s=m&a=1&u=https%3A%2F%2Fpbs.twimg.com%2Fprofile_images%2F1599994711430742017%2F33zLk9Wi_400x400.jpg") - let user = SuggestedUser(profile: profile, pubkey: "abcd")! + let user = SuggestedUser(profile: profile, pubkey: test_pubkey)! List { SuggestedUserView(user: user, damus_state: test_damus_state()) } diff --git a/damus/Views/Onboarding/SuggestedUsersViewModel.swift b/damus/Views/Onboarding/SuggestedUsersViewModel.swift @@ -11,7 +11,7 @@ import Combine struct SuggestedUserGroup: Identifiable, Codable { let id = UUID() let title: String - let users: [String] + let users: [Pubkey] enum CodingKeys: String, CodingKey { case title, users @@ -34,7 +34,7 @@ class SuggestedUsersViewModel: ObservableObject { subscribeToSuggestedProfiles(pubkeys: pubkeys) } - func suggestedUser(pubkey: String) -> SuggestedUser? { + func suggestedUser(pubkey: Pubkey) -> SuggestedUser? { if let profile = damus_state.profiles.lookup(id: pubkey), let user = SuggestedUser(profile: profile, pubkey: pubkey) { return user @@ -42,7 +42,7 @@ class SuggestedUsersViewModel: ObservableObject { return nil } - func follow(pubkeys: [String]) { + func follow(pubkeys: [Pubkey]) { for pubkey in pubkeys { notify(.follow(.pubkey(pubkey))) } @@ -66,17 +66,16 @@ class SuggestedUsersViewModel: ObservableObject { } } - private func getPubkeys(groups: [SuggestedUserGroup]) -> [String] { - var pubkeys: [String] = [] + private func getPubkeys(groups: [SuggestedUserGroup]) -> [Pubkey] { + var pubkeys: [Pubkey] = [] for group in groups { pubkeys.append(contentsOf: group.users) } return pubkeys } - private func subscribeToSuggestedProfiles(pubkeys: [String]) { - let filter = NostrFilter(kinds: [.metadata], - authors: pubkeys) + private func subscribeToSuggestedProfiles(pubkeys: [Pubkey]) { + let filter = NostrFilter(kinds: [.metadata], authors: pubkeys) damus_state.pool.subscribe(sub_id: sub_id, filters: [filter], handler: handle_event) } diff --git a/damus/Views/PostView.swift b/damus/Views/PostView.swift @@ -21,7 +21,7 @@ class TagModel: ObservableObject { enum PostTarget { case none - case user(String) + case user(Pubkey) } enum PostAction { diff --git a/damus/Views/Posting/UserSearch.swift b/damus/Views/Posting/UserSearch.swift @@ -9,9 +9,9 @@ import SwiftUI struct SearchedUser: Identifiable { let profile: Profile? - let pubkey: String - - var id: String { + let pubkey: Pubkey + + var id: Pubkey { return pubkey } } @@ -151,7 +151,7 @@ func append_user_tag(tag: NSAttributedString, post: NSMutableAttributedString, w } /// Generate a mention attributed string, including the internal damus:nostr: link -func user_tag_attr_string(profile: Profile?, pubkey: String) -> NSMutableAttributedString { +func user_tag_attr_string(profile: Profile?, pubkey: Pubkey) -> NSMutableAttributedString { let display_name = Profile.displayName(profile: profile, pubkey: pubkey) let name = display_name.username.truncate(maxLength: 50) let tagString = "@\(name)" diff --git a/damus/Views/Profile/CondensedProfilePicturesView.swift b/damus/Views/Profile/CondensedProfilePicturesView.swift @@ -9,10 +9,10 @@ import SwiftUI struct CondensedProfilePicturesView: View { let state: DamusState - let pubkeys: [String] + let pubkeys: [Pubkey] let maxPictures: Int - init(state: DamusState, pubkeys: [String], maxPictures: Int) { + init(state: DamusState, pubkeys: [Pubkey], maxPictures: Int) { self.state = state self.pubkeys = pubkeys self.maxPictures = min(maxPictures, pubkeys.count) @@ -33,6 +33,6 @@ struct CondensedProfilePicturesView: View { struct CondensedProfilePicturesView_Previews: PreviewProvider { static var previews: some View { - CondensedProfilePicturesView(state: test_damus_state(), pubkeys: ["a", "b", "c", "d"], maxPictures: 3) + CondensedProfilePicturesView(state: test_damus_state(), pubkeys: [test_pubkey, test_pubkey, test_pubkey, test_pubkey], maxPictures: 3) } } diff --git a/damus/Views/Profile/EditPictureControl.swift b/damus/Views/Profile/EditPictureControl.swift @@ -13,7 +13,7 @@ class ImageUploadingObserver: ObservableObject { struct EditPictureControl: View { let uploader: MediaUploader - let pubkey: String + let pubkey: Pubkey @Binding var image_url: URL? @ObservedObject var uploadObserver: ImageUploadingObserver let callback: (URL?) -> Void @@ -120,12 +120,11 @@ struct EditPictureControl: View { struct EditPictureControl_Previews: PreviewProvider { static var previews: some View { - let pubkey = "123" let url = Binding<URL?>.constant(URL(string: "https://damus.io")!) let observer = ImageUploadingObserver() ZStack { Color.gray - EditPictureControl(uploader: .nostrBuild, pubkey: pubkey, image_url: url, uploadObserver: observer) { _ in + EditPictureControl(uploader: .nostrBuild, pubkey: test_pubkey, image_url: url, uploadObserver: observer) { _ in // } } diff --git a/damus/Views/Profile/EventProfileName.swift b/damus/Views/Profile/EventProfileName.swift @@ -10,7 +10,7 @@ import SwiftUI /// Profile Name used when displaying an event in the timeline struct EventProfileName: View { let damus_state: DamusState - let pubkey: String + let pubkey: Pubkey let profile: Profile? @State var display_name: DisplayName? @@ -19,7 +19,7 @@ struct EventProfileName: View { let size: EventViewKind - init(pubkey: String, profile: Profile?, damus: DamusState, size: EventViewKind = .normal) { + init(pubkey: Pubkey, profile: Profile?, damus: DamusState, size: EventViewKind = .normal) { self.damus_state = damus self.pubkey = pubkey self.profile = profile diff --git a/damus/Views/Profile/MaybeAnonPfpView.swift b/damus/Views/Profile/MaybeAnonPfpView.swift @@ -10,10 +10,10 @@ import SwiftUI struct MaybeAnonPfpView: View { let state: DamusState let is_anon: Bool - let pubkey: String + let pubkey: Pubkey let size: CGFloat - init(state: DamusState, is_anon: Bool, pubkey: String, size: CGFloat) { + init(state: DamusState, is_anon: Bool, pubkey: Pubkey, size: CGFloat) { self.state = state self.is_anon = is_anon self.pubkey = pubkey diff --git a/damus/Views/Profile/ProfileName.swift b/damus/Views/Profile/ProfileName.swift @@ -12,7 +12,7 @@ enum FriendType { case fof } -func get_friend_type(contacts: Contacts, pubkey: String) -> FriendType? { +func get_friend_type(contacts: Contacts, pubkey: Pubkey) -> FriendType? { if contacts.is_friend_or_self(pubkey) { return .friend } @@ -26,7 +26,7 @@ func get_friend_type(contacts: Contacts, pubkey: String) -> FriendType? { struct ProfileName: View { let damus_state: DamusState - let pubkey: String + let pubkey: Pubkey let profile: Profile? let prefix: String @@ -36,7 +36,7 @@ struct ProfileName: View { @State var nip05: NIP05? @State var donation: Int? - init(pubkey: String, profile: Profile?, prefix: String = "", damus: DamusState, show_nip5_domain: Bool = true) { + init(pubkey: Pubkey, profile: Profile?, prefix: String = "", damus: DamusState, show_nip5_domain: Bool = true) { self.pubkey = pubkey self.profile = profile self.prefix = prefix diff --git a/damus/Views/Profile/ProfileNameView.swift b/damus/Views/Profile/ProfileNameView.swift @@ -8,7 +8,7 @@ import SwiftUI struct ProfileNameView: View { - let pubkey: String + let pubkey: Pubkey let profile: Profile? let follows_you: Bool let damus: DamusState diff --git a/damus/Views/Profile/ProfilePicView.swift b/damus/Views/Profile/ProfilePicView.swift @@ -31,7 +31,7 @@ func pfp_line_width(_ h: Highlight) -> CGFloat { struct InnerProfilePicView: View { let url: URL? let fallbackUrl: URL? - let pubkey: String + let pubkey: Pubkey let size: CGFloat let highlight: Highlight let disable_animation: Bool @@ -67,7 +67,7 @@ struct InnerProfilePicView: View { } struct ProfilePicView: View { - let pubkey: String + let pubkey: Pubkey let size: CGFloat let highlight: Highlight let profiles: Profiles @@ -75,7 +75,7 @@ struct ProfilePicView: View { @State var picture: String? - init(pubkey: String, size: CGFloat, highlight: Highlight, profiles: Profiles, disable_animation: Bool, picture: String? = nil) { + init(pubkey: Pubkey, size: CGFloat, highlight: Highlight, profiles: Profiles, disable_animation: Bool, picture: String? = nil) { self.pubkey = pubkey self.profiles = profiles self.size = size @@ -98,7 +98,7 @@ struct ProfilePicView: View { } } -func get_profile_url(picture: String?, pubkey: String, profiles: Profiles) -> URL { +func get_profile_url(picture: String?, pubkey: Pubkey, profiles: Profiles) -> URL { let pic = picture ?? profiles.lookup(id: pubkey)?.picture ?? robohash(pubkey) if let url = URL(string: pic) { return url diff --git a/damus/Views/Profile/ProfilePictureSelector.swift b/damus/Views/Profile/ProfilePictureSelector.swift @@ -13,7 +13,7 @@ struct EditProfilePictureView: View { @State var profile_url: URL? - let pubkey: String + let pubkey: Pubkey var damus_state: DamusState? var size: CGFloat = 80.0 let highlight: Highlight = .custom(Color.white, 2.0) @@ -52,7 +52,6 @@ struct EditProfilePictureView: View { struct ProfilePictureSelector_Previews: PreviewProvider { static var previews: some View { - let test_pubkey = "ff48854ac6555fed8e439ebb4fa2d928410e0eef13fa41164ec45aaaa132d846" EditProfilePictureView(pubkey: test_pubkey, uploadObserver: ImageUploadingObserver()) { _ in // } diff --git a/damus/Views/Profile/ProfileView.swift b/damus/Views/Profile/ProfileView.swift @@ -31,7 +31,7 @@ func follow_btn_txt(_ fs: FollowState, follows_you: Bool) -> String { } } -func followedByString(_ friend_intersection: [String], profiles: Profiles, locale: Locale = Locale.current) -> String { +func followedByString(_ friend_intersection: [Pubkey], profiles: Profiles, locale: Locale = Locale.current) -> String { let bundle = bundleForLocale(locale: locale) let names: [String] = friend_intersection.prefix(3).map { let profile = profiles.lookup(id: $0) @@ -90,7 +90,7 @@ struct ProfileView: View { self._followers = StateObject(wrappedValue: followers) } - init(damus_state: DamusState, pubkey: String) { + init(damus_state: DamusState, pubkey: Pubkey) { self.damus_state = damus_state self._profile = StateObject(wrappedValue: ProfileModel(pubkey: pubkey, damus: damus_state)) self._followers = StateObject(wrappedValue: FollowersModel(damus_state: damus_state, target: pubkey)) @@ -493,7 +493,7 @@ struct ProfileView_Previews: PreviewProvider { } struct KeyView: View { - let pubkey: String + let pubkey: Pubkey @Environment(\.colorScheme) var colorScheme @@ -566,7 +566,7 @@ extension View { } } -func check_nip05_validity(pubkey: String, profiles: Profiles) { +func check_nip05_validity(pubkey: Pubkey, profiles: Profiles) { guard let profile = profiles.lookup(id: pubkey), let nip05 = profile.nip05, profiles.is_validated(pubkey) == nil diff --git a/damus/Views/QRCodeView.swift b/damus/Views/QRCodeView.swift @@ -9,7 +9,7 @@ import SwiftUI import CoreImage.CIFilterBuiltins struct ProfileScanResult: Equatable { - let pubkey: String + let pubkey: Pubkey init(hex: String) { self.pubkey = hex @@ -42,7 +42,7 @@ struct ProfileScanResult: Equatable { struct QRCodeView: View { let damus_state: DamusState - @State var pubkey: String + @State var pubkey: Pubkey @Environment(\.presentationMode) var presentationMode diff --git a/damus/Views/Search/SearchingEventView.swift b/damus/Views/Search/SearchingEventView.swift @@ -10,7 +10,7 @@ import SwiftUI enum SearchState { case searching case found(NostrEvent) - case found_profile(String) + case found_profile(Pubkey) case not_found } diff --git a/damus/Views/SearchResultsView.swift b/damus/Views/SearchResultsView.swift @@ -15,8 +15,8 @@ struct MultiSearch { enum Search: Identifiable { case profiles([SearchedUser]) case hashtag(String) - case profile(String) - case note(String) + case profile(Pubkey) + case note(NoteId) case nip05(String) case hex(String) case multi(MultiSearch) @@ -38,7 +38,7 @@ struct InnerSearchResults: View { let damus_state: DamusState let search: Search? - func ProfileSearchResult(pk: String) -> some View { + func ProfileSearchResult(pk: Pubkey) -> some View { FollowUserView(target: .pubkey(pk), damus_state: damus_state) } diff --git a/damus/Views/SelectWalletView.swift b/damus/Views/SelectWalletView.swift @@ -10,7 +10,7 @@ import SwiftUI struct SelectWalletView: View { let default_wallet: Wallet @Binding var active_sheet: Sheets? - let our_pubkey: String + let our_pubkey: Pubkey let invoice: String @State var invoice_copied: Bool = false @@ -71,6 +71,6 @@ struct SelectWalletView_Previews: PreviewProvider { @State static var active_sheet: Sheets? = nil static var previews: some View { - SelectWalletView(default_wallet: .lnlink, active_sheet: $active_sheet, our_pubkey: "", invoice: "") + SelectWalletView(default_wallet: .lnlink, active_sheet: $active_sheet, our_pubkey: test_pubkey, invoice: "") } } diff --git a/damus/Views/Zaps/ZapTypePicker.swift b/damus/Views/Zaps/ZapTypePicker.swift @@ -31,7 +31,7 @@ struct ZapTypePicker: View { @Binding var zap_type: ZapType @ObservedObject var settings: UserSettingsStore let profiles: Profiles - let pubkey: String + let pubkey: Pubkey @Environment(\.colorScheme) var colorScheme @@ -106,11 +106,11 @@ struct ZapTypePicker_Previews: PreviewProvider { @State static var zap_type: ZapType = .pub static var previews: some View { let ds = test_damus_state() - ZapTypePicker(zap_type: $zap_type, settings: ds.settings, profiles: ds.profiles, pubkey: "bob") + ZapTypePicker(zap_type: $zap_type, settings: ds.settings, profiles: ds.profiles, pubkey: test_pubkey) } } -func zap_type_desc(type: ZapType, profiles: Profiles, pubkey: String) -> String { +func zap_type_desc(type: ZapType, profiles: Profiles, pubkey: Pubkey) -> String { switch type { case .pub: return NSLocalizedString("Everyone will see that you zapped", comment: "Description of public zap type where the zap is sent publicly and identifies the user who sent it.") diff --git a/damus/Views/Zaps/ZapUserView.swift b/damus/Views/Zaps/ZapUserView.swift @@ -9,8 +9,8 @@ import SwiftUI struct ZapUserView: View { let state: DamusState - let pubkey: String - + let pubkey: Pubkey + var body: some View { HStack(alignment: .center) { Text("Zap") diff --git a/damusTests/UserSearchCacheTests.swift b/damusTests/UserSearchCacheTests.swift @@ -86,7 +86,7 @@ final class UserSearchCacheTests: XCTestCase { let damus = "3efdaebb1d8923ebd99c9e7ace3b4194ab45512e2be79c1b7d68d9243e0d2681" let jb55 = "32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245" - var pubkeysToPetnames = [String: String]() + var pubkeysToPetnames = [Pubkey: String]() pubkeysToPetnames[damus] = "damus" pubkeysToPetnames[jb55] = "jb55" @@ -114,7 +114,7 @@ final class UserSearchCacheTests: XCTestCase { XCTAssertEqual(damusState.user_search_cache.search(key: "l"), [jb55]) } - private func createContactsEventWithPetnames(pubkeysToPetnames: [String: String]) throws -> NostrEvent { + private func createContactsEventWithPetnames(pubkeysToPetnames: [Pubkey: String]) throws -> NostrEvent { let keypair = try XCTUnwrap(keypair) let bootstrapRelays = load_bootstrap_relays(pubkey: keypair.pubkey) diff --git a/nostrdb/NdbNote.swift b/nostrdb/NdbNote.swift @@ -242,7 +242,7 @@ extension NdbNote { References.hashtags(tags: self.tags) } - func event_refs(_ privkey: String?) -> [EventRef] { + func event_refs(_ privkey: Privkey?) -> [EventRef] { if let rs = _event_refs { return rs } @@ -251,7 +251,7 @@ extension NdbNote { return refs } - func get_content(_ privkey: String?) -> String { + func get_content(_ privkey: Privkey?) -> String { if known_kind == .dm { return decrypted(privkey: privkey) ?? "*failed to decrypt content*" } @@ -259,7 +259,7 @@ extension NdbNote { return content } - func blocks(_ privkey: String?) -> Blocks { + func blocks(_ privkey: Privkey?) -> Blocks { if let bs = _blocks { return bs } let blocks = get_blocks(content: self.get_content(privkey)) @@ -268,8 +268,8 @@ extension NdbNote { } // NDBTODO: switch this to operating on bytes not strings - func decrypted(privkey: String?) -> String? { - if let decrypted_content = decrypted_content { + func decrypted(privkey: Privkey?) -> String? { + if let decrypted_content { return decrypted_content } @@ -312,7 +312,7 @@ extension NdbNote { } */ - public func direct_replies(_ privkey: String?) -> [ReferencedId] { + public func direct_replies(_ privkey: Privkey?) -> [ReferencedId] { return event_refs(privkey).reduce(into: []) { acc, evref in if let direct_reply = evref.is_direct_reply { acc.append(direct_reply) @@ -321,7 +321,7 @@ extension NdbNote { } // NDBTODO: just use Id - public func thread_id(privkey: String?) -> String { + public func thread_id(privkey: Privkey?) -> NoteId { for ref in event_refs(privkey) { if let thread_id = ref.is_thread_id { return thread_id.ref_id @@ -346,11 +346,11 @@ extension NdbNote { return false } - func is_reply(_ privkey: String?) -> Bool { + func is_reply(_ privkey: Privkey?) -> Bool { return event_is_reply(self.event_refs(privkey)) } - func note_language(_ privkey: String?) async -> String? { + func note_language(_ privkey: Privkey?) async -> String? { let t = Task.detached { // Rely on Apple's NLLanguageRecognizer to tell us which language it thinks the note is in // and filter on only the text portions of the content as URLs and hashtags confuse the language recognizer.