Add support for account deletion

As per apple guidelines

Changelog-Added: Added support for account deletion
This commit is contained in:
William Casarin
2023-01-30 13:26:04 -08:00
parent 9fa11118d3
commit e1578c0337
12 changed files with 102 additions and 12 deletions

View File

@@ -73,6 +73,7 @@ struct ContentView: View {
@State var damus_state: DamusState? = nil
@State var selected_timeline: Timeline? = .home
@State var is_thread_open: Bool = false
@State var is_deleted_account: Bool = false
@State var is_profile_open: Bool = false
@State var event: NostrEvent? = nil
@State var active_profile: String? = nil
@@ -348,6 +349,9 @@ struct ContentView: View {
}
.onReceive(handle_notify(.like)) { like in
}
.onReceive(handle_notify(.deleted_account)) { notif in
self.is_deleted_account = true
}
.onReceive(handle_notify(.report)) { notif in
let target = notif.object as! ReportTarget
self.active_sheet = .report(target)
@@ -434,7 +438,13 @@ struct ContentView: View {
.onReceive(handle_notify(.new_mutes)) { notif in
home.filter_muted()
}
.alert(NSLocalizedString("User blocked", comment: "Alert message to indicate "), isPresented: $user_blocked_confirm, actions: {
.alert(NSLocalizedString("Deleted Account", comment: "Alert message to indicate this is a deleted account"), isPresented: $is_deleted_account) {
Button(NSLocalizedString("Logout", comment: "Button to close the alert that informs that the current account has been deleted.")) {
is_deleted_account = false
notify(.logout, ())
}
}
.alert(NSLocalizedString("User blocked", comment: "Alert message to indicate the user has been blocked"), isPresented: $user_blocked_confirm, actions: {
Button(NSLocalizedString("Thanks!", comment: "Button to close out of alert that informs that the action to block a user was successful.")) {
user_blocked_confirm = false
}

View File

@@ -86,7 +86,7 @@ class FollowersModel: ObservableObject {
if ev.known_kind == .contacts {
handle_contact_event(ev)
} else if ev.known_kind == .metadata {
process_metadata_event(profiles: damus_state.profiles, ev: ev)
process_metadata_event(our_pubkey: damus_state.pubkey, profiles: damus_state.profiles, ev: ev)
}
case .notice(let msg):

View File

@@ -60,7 +60,7 @@ class FollowingModel {
switch nev {
case .event(_, let ev):
if ev.kind == 0 {
process_metadata_event(profiles: damus_state.profiles, ev: ev)
process_metadata_event(our_pubkey: damus_state.pubkey, profiles: damus_state.profiles, ev: ev)
}
case .notice(let msg):
print("followingmodel notice: \(msg)")

View File

@@ -372,7 +372,7 @@ class HomeModel: ObservableObject {
}
func handle_metadata_event(_ ev: NostrEvent) {
process_metadata_event(profiles: damus_state.profiles, ev: ev)
process_metadata_event(our_pubkey: damus_state.pubkey, profiles: damus_state.profiles, ev: ev)
}
func get_last_event_of_kind(relay_id: String, kind: Int) -> NostrEvent? {
@@ -530,10 +530,17 @@ func print_filters(relay_id: String?, filters groups: [[NostrFilter]]) {
print("-----")
}
func process_metadata_event(profiles: Profiles, ev: NostrEvent) {
func process_metadata_event(our_pubkey: String, profiles: Profiles, ev: NostrEvent) {
guard let profile: Profile = decode_data(Data(ev.content.utf8)) else {
return
}
if our_pubkey == ev.pubkey && (profile.deleted ?? false) {
DispatchQueue.main.async {
notify(.deleted_account, ())
}
return
}
var old_nip05: String? = nil
if let mprof = profiles.lookup_with_timestamp(id: ev.pubkey) {

View File

@@ -97,7 +97,7 @@ class ProfileModel: ObservableObject, Equatable {
} else if ev.known_kind == .contacts {
handle_profile_contact_event(ev)
} else if ev.known_kind == .metadata {
process_metadata_event(profiles: damus.profiles, ev: ev)
process_metadata_event(our_pubkey: damus.pubkey, profiles: damus.profiles, ev: ev)
}
seen_event.insert(ev.id)
}

View File

@@ -129,7 +129,7 @@ func load_profiles(profiles_subid: String, relay_id: String, events: [NostrEvent
}
if ev.known_kind == .metadata {
process_metadata_event(profiles: damus_state.profiles, ev: ev)
process_metadata_event(our_pubkey: damus_state.pubkey, profiles: damus_state.profiles, ev: ev)
}
}

View File

@@ -190,7 +190,7 @@ class ThreadModel: ObservableObject {
}
if ev.known_kind == .metadata {
process_metadata_event(profiles: damus_state.profiles, ev: ev)
process_metadata_event(our_pubkey: damus_state.pubkey, profiles: damus_state.profiles, ev: ev)
} else if ev.is_textlike {
self.add_event(ev, privkey: self.damus_state.keypair.privkey)
} else if ev.known_kind == .channel_meta || ev.known_kind == .channel_create {

View File

@@ -24,18 +24,22 @@ struct Profile: Codable {
}
private func str(_ str: String) -> String? {
guard let val = self.value[str] else{
return get_val(str)
}
private func get_val<T>(_ v: String) -> T? {
guard let val = self.value[v] else{
return nil
}
guard let s = val.value as? String else {
guard let s = val.value as? T else {
return nil
}
return s
}
private mutating func set_str(_ key: String, _ val: String?) {
private mutating func set_val<T>(_ key: String, _ val: T?) {
if val == nil {
self.value.removeValue(forKey: key)
return
@@ -44,6 +48,15 @@ struct Profile: Codable {
self.value[key] = AnyCodable.init(val)
}
private mutating func set_str(_ key: String, _ val: String?) {
set_val(key, val)
}
var deleted: Bool? {
get { return get_val("deleted"); }
set(s) { set_val("deleted", s) }
}
var display_name: String? {
get { return str("display_name"); }
set(s) { set_str("display_name", s) }
@@ -109,6 +122,10 @@ struct Profile: Codable {
return make_ln_url(self.lnurl)
}
init() {
self.value = [:]
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
self.value = try container.decode([String: AnyCodable].self)

View File

@@ -0,0 +1,22 @@
//
// AccountDeletion.swift
// damus
//
// Created by William Casarin on 2023-01-30.
//
import Foundation
func created_deleted_account_profile(keypair: FullKeypair) -> NostrEvent {
var profile = Profile()
profile.deleted = true
profile.about = "account deleted"
profile.name = "nobody"
let content = encode_json(profile)!
let ev = NostrEvent(content: content, pubkey: keypair.pubkey, kind: 0)
ev.id = calculate_event_id(ev: ev)
ev.sig = sign_event(privkey: keypair.privkey, ev: ev)
return ev
}

View File

@@ -95,6 +95,9 @@ extension Notification.Name {
static var new_unmutes: Notification.Name {
return Notification.Name("new_unmutes")
}
static var deleted_account: Notification.Name {
return Notification.Name("deleted_account")
}
}
func handle_notify(_ name: Notification.Name) -> NotificationCenter.Publisher {

View File

@@ -13,12 +13,14 @@ struct ConfigView: View {
@Environment(\.dismiss) var dismiss
@State var show_add_relay: Bool = false
@State var confirm_logout: Bool = false
@State var confirm_delete_account: Bool = false
@State var new_relay: String = ""
@State var show_privkey: Bool = false
@State var privkey: String
@State var privkey_copied: Bool = false
@State var pubkey_copied: Bool = false
@State var relays: [RelayDescriptor]
@State var delete_text: String = ""
@EnvironmentObject var user_settings: UserSettingsStore
let generator = UIImpactFeedbackGenerator(style: .light)
@@ -128,16 +130,41 @@ struct ConfigView: View {
KingfisherManager.shared.cache.cleanExpiredDiskCache()
}
}
Section(NSLocalizedString("Reset", comment: "Section title for resetting the user")) {
Button(NSLocalizedString("Logout", comment: "Button to logout the user.")) {
confirm_logout = true
}
if state.is_privkey_user {
Button(NSLocalizedString("Delete Account", comment: "Button to delete the user's account."), role: .destructive) {
confirm_delete_account = true
}
}
}
}
}
.navigationTitle(NSLocalizedString("Settings", comment: "Navigation title for Settings view."))
.navigationBarTitleDisplayMode(.large)
.alert(NSLocalizedString("Delete Account", comment: "Alert for deleting the users account."), isPresented: $confirm_delete_account) {
TextField("Type DELETE to delete", text: $delete_text)
Button(NSLocalizedString("Cancel", comment: "Cancel deleting the user."), role: .cancel) {
confirm_delete_account = false
}
Button(NSLocalizedString("Delete", comment: "Button for deleting the users account."), role: .destructive) {
guard let full_kp = state.keypair.to_full() else {
return
}
guard delete_text == "DELETE" else {
return
}
let ev = created_deleted_account_profile(keypair: full_kp)
state.pool.send(.event(ev))
notify(.logout, ())
}
}
.alert(NSLocalizedString("Logout", comment: "Alert for logging out the user."), isPresented: $confirm_logout) {
Button(NSLocalizedString("Cancel", comment: "Cancel out of logging out the user."), role: .cancel) {
confirm_logout = false