diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 2d7ad03e..bd5f60a9 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -131,6 +131,7 @@ 4CEE2B02280B39E800AB5EEF /* EventActionBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CEE2B01280B39E800AB5EEF /* EventActionBar.swift */; }; E990020F2955F837003BBC5A /* EditMetadataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E990020E2955F837003BBC5A /* EditMetadataView.swift */; }; BAB68BED29543FA3007BA466 /* SelectWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB68BEC29543FA3007BA466 /* SelectWalletView.swift */; }; + 6C7DE41F2955169800E66263 /* Vault in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7DE41E2955169800E66263 /* Vault */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -318,6 +319,7 @@ buildActionMask = 2147483647; files = ( 4C06670428FC7EC500038D2A /* Kingfisher in Frameworks */, + 6C7DE41F2955169800E66263 /* Vault in Frameworks */, 4CE6DF1227F7A2B300C66700 /* Starscream in Frameworks */, 4C649881286E0EE300EAE2B3 /* secp256k1 in Frameworks */, ); @@ -629,6 +631,7 @@ 4CE6DF1127F7A2B300C66700 /* Starscream */, 4C649880286E0EE300EAE2B3 /* secp256k1 */, 4C06670328FC7EC500038D2A /* Kingfisher */, + 6C7DE41E2955169800E66263 /* Vault */, ); productName = damus; productReference = 4CE6DEE327F7A08100C66700 /* damus.app */; @@ -708,6 +711,7 @@ 4C64987F286E0EE300EAE2B3 /* XCRemoteSwiftPackageReference "secp256k1" */, 4C06670228FC7EC500038D2A /* XCRemoteSwiftPackageReference "Kingfisher" */, 3169CAE9294FCABA00EE4006 /* XCRemoteSwiftPackageReference "Shimmer" */, + 6C7DE41D2955169800E66263 /* XCRemoteSwiftPackageReference "Vault" */, ); productRefGroup = 4CE6DEE427F7A08100C66700 /* Products */; projectDirPath = ""; @@ -1027,7 +1031,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\""; DEVELOPMENT_TEAM = XK7H4JAB3D; ENABLE_PREVIEWS = YES; @@ -1047,7 +1051,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; @@ -1066,7 +1070,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = damus/damus.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"damus/Preview Content\""; DEVELOPMENT_TEAM = XK7H4JAB3D; ENABLE_PREVIEWS = YES; @@ -1086,7 +1090,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; @@ -1246,6 +1250,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 */ @@ -1264,6 +1276,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/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) } 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/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)) } } 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 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/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 + 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 {