From 6a8100152fd38d595297d6f69a4d06dd58dc583a Mon Sep 17 00:00:00 2001 From: Thomas Rademaker Date: Thu, 22 Dec 2022 18:13:33 -0500 Subject: [PATCH 1/7] save the private key to the keychain and not user defaults --- damus.xcodeproj/project.pbxproj | 17 ++++++++ .../xcshareddata/swiftpm/Package.resolved | 9 ++++ damus/Util/Keys.swift | 43 +++++++++++++------ damus/Views/LoginView.swift | 28 ++++++++++-- damus/Views/SaveKeysView.swift | 9 +++- damus/damusApp.swift | 2 +- 6 files changed, 89 insertions(+), 19 deletions(-) diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 883eda4a..cbc6eb21 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -129,6 +129,7 @@ 4CEE2AF7280B2DEA00AB5EEF /* ProfileName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF6280B2DEA00AB5EEF /* ProfileName.swift */; }; 4CEE2AF9280B2EAC00AB5EEF /* PowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2AF8280B2EAC00AB5EEF /* PowView.swift */; }; 4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; }; + 6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -314,6 +315,7 @@ buildActionMask = 2147483647; files = ( 4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */, + 6C7DE41F2955169800E66263 /* Vault in Frameworks */, 4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */, 4C649881286E0EE300EAE2B3 /* secp256k1 in Frameworks */, ); @@ -623,6 +625,7 @@ 4CE6DF1127F7A2B300C66700 /* Starscream */, 4C649880286E0EE300EAE2B3 /* secp256k1 */, 4C06670328FC7EC500038D2A /* Kingfisher */, + 6C7DE41E2955169800E66263 /* Vault */, ); productName = damus; productReference = 4CE6DEE327F7A08100C66700 /* damus.app */; @@ -702,6 +705,7 @@ 4C64987F286E0EE300EAE2B3 /* XCRemoteSwiftPackageReference "secp256k1" */, 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */, 3169CAE9294FCABA00EE4006 /* XCRemoteSwiftPackageReference "Shimmer" */, + 6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */, ); productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */; projectDirPath = ""; @@ -1238,6 +1242,14 @@ minimumVersion = 4.0.0; }; }; + 6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SparrowTek/Vault"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.0.0; + }; + }; /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -1256,6 +1268,11 @@ package = 4CE6DF1027F7A2B300C66700 /* XCRemoteSwiftPackageReference "Starscream" */; productName = Starscream; }; + 6C7DE41E2955169800E66263 /* Vault */ = { + isa = XCSwiftPackageProductDependency; + package = 6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */; + productName = Vault; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 4CE6DEDB27F7A08100C66700 /* Project object */; diff --git a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 58468d85..270e63f4 100644 --- a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -34,6 +34,15 @@ "revision" : "df8d82047f6654d8e4b655d1b1525c64e1059d21", "version" : "4.0.4" } + }, + { + "identity" : "vault", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SparrowTek/Vault", + "state" : { + "revision" : "f5707fac23f4a17b3e5ed32dd444f502773615ae", + "version" : "1.0.2" + } } ], "version" : 2 diff --git a/damus/Util/Keys.swift b/damus/Util/Keys.swift index dfa66a3c..9bc318a8 100644 --- a/damus/Util/Keys.swift +++ b/damus/Util/Keys.swift @@ -7,6 +7,7 @@ import Foundation import secp256k1 +import Vault let PUBKEY_HRP = "npub" let PRIVKEY_HRP = "nsec" @@ -29,6 +30,12 @@ enum Bech32Key { case sec(String) } +struct DamusKeychainConfiguration: KeychainConfiguration { + var serviceName = "damus" + var accessGroup: String? = nil + var accountName = "privkey" +} + func decode_bech32_key(_ key: String) -> Bech32Key? { guard let decoded = try? bech32_decode(key) else { return nil @@ -86,32 +93,38 @@ func save_pubkey(pubkey: String) { UserDefaults.standard.set(pubkey, forKey: "pubkey") } -func save_privkey(privkey: String) { - UserDefaults.standard.set(privkey, forKey: "privkey") +func save_privkey(privkey: String) throws { + try Vault.savePrivateKey(privkey, keychainConfiguration: DamusKeychainConfiguration()) } -func clear_saved_privkey() { - UserDefaults.standard.removeObject(forKey: "privkey") +func clear_saved_privkey() throws { + try Vault.deletePrivateKey(keychainConfiguration: DamusKeychainConfiguration()) } func clear_saved_pubkey() { UserDefaults.standard.removeObject(forKey: "pubkey") } -func save_keypair(pubkey: String, privkey: String) { +func save_keypair(pubkey: String, privkey: String) throws { save_pubkey(pubkey: pubkey) - save_privkey(privkey: privkey) + try save_privkey(privkey: privkey) } -func clear_keypair() { - clear_saved_privkey() +func clear_keypair() throws { + try clear_saved_privkey() clear_saved_pubkey() } func get_saved_keypair() -> Keypair? { - get_saved_pubkey().flatMap { pubkey in - let privkey = get_saved_privkey() - return Keypair(pubkey: pubkey, privkey: privkey) + do { + try removePrivateKeyFromUserDefaults() + + return get_saved_pubkey().flatMap { pubkey in + let privkey = get_saved_privkey() + return Keypair(pubkey: pubkey, privkey: privkey) + } + } catch { + return nil } } @@ -120,5 +133,11 @@ func get_saved_pubkey() -> String? { } func get_saved_privkey() -> String? { - return UserDefaults.standard.string(forKey: "privkey") + try? Vault.getPrivateKey(keychainConfiguration: DamusKeychainConfiguration()) +} + +fileprivate func removePrivateKeyFromUserDefaults() throws { + guard let privKey = UserDefaults.standard.string(forKey: "privkey") else { return } + try save_privkey(privkey: privKey) + UserDefaults.standard.removeObject(forKey: "privkey") } diff --git a/damus/Views/LoginView.swift b/damus/Views/LoginView.swift index 06856b0d..67232297 100644 --- a/damus/Views/LoginView.swift +++ b/damus/Views/LoginView.swift @@ -52,14 +52,24 @@ struct LoginView: View { func process_login(_ key: ParsedKey, is_pubkey: Bool) -> Bool { switch key { case .priv(let priv): - save_privkey(privkey: priv) + do { + try save_privkey(privkey: priv) + } catch { + return false + } + guard let pk = privkey_to_pubkey(privkey: priv) else { return false } save_pubkey(pubkey: pk) case .pub(let pub): - clear_saved_privkey() + do { + try clear_saved_privkey() + } catch { + return false + } + save_pubkey(pubkey: pub) case .nip05(let id): @@ -82,10 +92,20 @@ struct LoginView: View { case .hex(let hexstr): if is_pubkey { - clear_saved_privkey() + do { + try clear_saved_privkey() + } catch { + return false + } + save_pubkey(pubkey: hexstr) } else { - save_privkey(privkey: hexstr) + do { + try save_privkey(privkey: hexstr) + } catch { + return false + } + guard let pk = privkey_to_pubkey(privkey: hexstr) else { return false } diff --git a/damus/Views/SaveKeysView.swift b/damus/Views/SaveKeysView.swift index 70d26c09..7f92f279 100644 --- a/damus/Views/SaveKeysView.swift +++ b/damus/Views/SaveKeysView.swift @@ -107,8 +107,13 @@ struct SaveKeysView: View { self.pool.send(.event(contacts_ev)) } - save_keypair(pubkey: account.pubkey, privkey: account.privkey) - notify(.login, account.keypair) + do { + try save_keypair(pubkey: account.pubkey, privkey: account.privkey) + notify(.login, account.keypair) + } catch { + self.error = "Failed to save keys" + } + case .error(let err): self.loading = false self.error = "\(err.debugDescription)" diff --git a/damus/damusApp.swift b/damus/damusApp.swift index d23a8602..ae720a32 100644 --- a/damus/damusApp.swift +++ b/damus/damusApp.swift @@ -36,7 +36,7 @@ struct MainView: View { } } .onReceive(handle_notify(.logout)) { _ in - clear_keypair() + try? clear_keypair() keypair = nil } .onAppear { From 41a75c2adf6966e82ba74e1221cf0632e90ab724 Mon Sep 17 00:00:00 2001 From: Thomas Rademaker Date: Fri, 23 Dec 2022 09:54:44 -0500 Subject: [PATCH 2/7] update vault --- .../project.xcworkspace/xcshareddata/swiftpm/Package.resolved | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 270e63f4..8b889102 100644 --- a/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/damus.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -40,8 +40,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/SparrowTek/Vault", "state" : { - "revision" : "f5707fac23f4a17b3e5ed32dd444f502773615ae", - "version" : "1.0.2" + "revision" : "87db56c3c8b6421c65b0745f73e08b0dc56f79d4", + "version" : "1.0.3" } } ], From 3c1e8b0bfcbb56f5ca248047514ca85454a2e54a Mon Sep 17 00:00:00 2001 From: Thomas Rademaker Date: Fri, 23 Dec 2022 09:55:29 -0500 Subject: [PATCH 3/7] add keychain sharing entitlement --- damus/damus.entitlements | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/damus/damus.entitlements b/damus/damus.entitlements index 903def2a..f8f93464 100644 --- a/damus/damus.entitlements +++ b/damus/damus.entitlements @@ -4,5 +4,9 @@ aps-environment development + keychain-access-groups + + $(AppIdentifierPrefix)com.jb55.damus2 + From 898a880a15a12f8e8135373851740c2f03d9fbd9 Mon Sep 17 00:00:00 2001 From: William Casarin Date: Sun, 25 Dec 2022 12:49:56 -0800 Subject: [PATCH 4/7] stay on 0.1.8 for now --- damus.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index ec4e33c9..e314ffa9 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -1023,7 +1023,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\""; DEVELOPMENT_TEAM = XK7H4JAB3D; ENABLE_PREVIEWS = YES; @@ -1043,7 +1043,7 @@ "$(inherited)", "$(PROJECT_DIR)", ); - MARKETING_VERSION = 0.1.9; + MARKETING_VERSION = 0.1.8; PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus2; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -1062,7 +1062,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\""; DEVELOPMENT_TEAM = XK7H4JAB3D; ENABLE_PREVIEWS = YES; @@ -1082,7 +1082,7 @@ "$(inherited)", "$(PROJECT_DIR)", ); - MARKETING_VERSION = 0.1.9; + MARKETING_VERSION = 0.1.8; PRODUCT_BUNDLE_IDENTIFIER = com.jb55.damus2; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; From 4a83d370d27021ca52222400fa6de0045ab61d3a Mon Sep 17 00:00:00 2001 From: Sam DuBois Date: Thu, 22 Dec 2022 13:49:10 -0700 Subject: [PATCH 5/7] Changed the layout of the image to be a bit more UI friendly Changelog-Changed: Show rounded corners on inline images --- damus/Components/ImageCarousel.swift | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/damus/Components/ImageCarousel.swift b/damus/Components/ImageCarousel.swift index f08f0b99..1c1e058a 100644 --- a/damus/Components/ImageCarousel.swift +++ b/damus/Components/ImageCarousel.swift @@ -121,21 +121,25 @@ struct ImageCarousel: View { var body: some View { TabView { ForEach(urls, id: \.absoluteString) { url in - KFAnimatedImage(url) - .configure { view in - view.framePreloadCount = 3 + Rectangle() + .overlay { + KFAnimatedImage(url) + .configure { view in + view.framePreloadCount = 3 + } + .cacheOriginalImage() + .loadDiskFileSynchronously() + .scaleFactor(UIScreen.main.scale) + .fade(duration: 0.1) + .aspectRatio(contentMode: .fill) + .tabItem { + Text(url.absoluteString) + } + .id(url.absoluteString) } - .cacheOriginalImage() - .loadDiskFileSynchronously() - .scaleFactor(UIScreen.main.scale) - .fade(duration: 0.1) - .aspectRatio(contentMode: .fit) - .tabItem { - Text(url.absoluteString) - } - .id(url.absoluteString) } } + .cornerRadius(10) .sheet(isPresented: $open_sheet) { ImageViewer(urls: urls) } From 8844764e0c26d552d384284d5f31b3f6be7b5a2b Mon Sep 17 00:00:00 2001 From: William Casarin Date: Sun, 25 Dec 2022 12:48:55 -0800 Subject: [PATCH 6/7] images: also show inline images from friend-of-friends Changelog-Changed: Also show inline images from friend-of-friends --- damus/Views/EventView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/damus/Views/EventView.swift b/damus/Views/EventView.swift index 2138757e..a17e3635 100644 --- a/damus/Views/EventView.swift +++ b/damus/Views/EventView.swift @@ -161,7 +161,7 @@ struct EventView: View { // blame the porn bots for this code func should_show_images(contacts: Contacts, ev: NostrEvent) -> Bool { - if contacts.is_friend(ev.pubkey) { + if contacts.is_in_friendosphere(ev.pubkey) { return true } return false From 1f6585e4193dd4f9ee2d47b2c85606c54cdbd7d6 Mon Sep 17 00:00:00 2001 From: Nitesh Balusu Date: Sun, 25 Dec 2022 13:52:58 -0500 Subject: [PATCH 7/7] Make about me multi-line in profile editor Closes: #138 Changelog-Fixed: Make about me multi-line in profile editor Signed-off-by: Nitesh Balusu --- damus/Views/EditMetadataView.swift | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/damus/Views/EditMetadataView.swift b/damus/Views/EditMetadataView.swift index 4bbe8689..9513a7d1 100644 --- a/damus/Views/EditMetadataView.swift +++ b/damus/Views/EditMetadataView.swift @@ -129,14 +129,16 @@ struct EditMetadataView: View { } Section("About Me") { + let placeholder = "Absolute Boss" ZStack(alignment: .topLeading) { TextEditor(text: $about) .textInputAutocapitalization(.sentences) - if about.isEmpty { - Text("Absolute boss") - .offset(x: 0, y: 7) - .foregroundColor(Color(uiColor: .placeholderText)) - } + .frame(minHeight: 20, alignment: .leading) + .multilineTextAlignment(.leading) + Text(about.isEmpty ? placeholder : about) + .padding(.leading, 4) + .opacity(about.isEmpty ? 1 : 0) + .foregroundColor(Color(uiColor: .placeholderText)) } }