diff --git a/damus.xcodeproj/project.pbxproj b/damus.xcodeproj/project.pbxproj index 895a6e4c..e7e4308d 100644 --- a/damus.xcodeproj/project.pbxproj +++ b/damus.xcodeproj/project.pbxproj @@ -1494,6 +1494,7 @@ INFOPLIST_FILE = damus/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Damus; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Local authentication to access private key"; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Granting Damus access to your photos allows you to save images."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; @@ -1535,6 +1536,7 @@ INFOPLIST_FILE = damus/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Damus; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Local authentication to access private key"; INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "Granting Damus access to your photos allows you to save images."; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; diff --git a/damus/Views/ConfigView.swift b/damus/Views/ConfigView.swift index 217469e4..81ad009c 100644 --- a/damus/Views/ConfigView.swift +++ b/damus/Views/ConfigView.swift @@ -7,6 +7,7 @@ import AVFoundation import Kingfisher import SwiftUI +import LocalAuthentication struct ConfigView: View { let state: DamusState @@ -14,6 +15,7 @@ struct ConfigView: View { @State var confirm_logout: Bool = false @State var confirm_delete_account: Bool = false @State var show_privkey: Bool = false + @State var has_authenticated_locally: Bool = false @State var show_libretranslate_api_key: Bool = false @State var privkey: String @State var privkey_copied: Bool = false @@ -30,13 +32,45 @@ struct ConfigView: View { _settings = ObservedObject(initialValue: state.settings) } + func authenticateLocally(completion: @escaping (Bool) -> Void) { + // Need to authenticate only once while ConfigView is presented + guard !has_authenticated_locally else { + completion(true) + return + } + let context = LAContext() + if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) { + context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: NSLocalizedString("Local authentication to access private key", comment: "Face ID usage description shown when trying to access private key")) { success, error in + DispatchQueue.main.async { + has_authenticated_locally = success + completion(success) + } + } + } else { + // If there's no authentication set up on the device, let the user copy the key without it + has_authenticated_locally = true + completion(true) + } + } + // TODO: (jb55) could be more general but not gonna worry about it atm func CopyButton(is_pk: Bool) -> some View { return Button(action: { - UIPasteboard.general.string = is_pk ? self.state.keypair.pubkey_bech32 : self.privkey - self.privkey_copied = !is_pk - self.pubkey_copied = is_pk - generator.impactOccurred() + let copyKey = { + UIPasteboard.general.string = is_pk ? self.state.keypair.pubkey_bech32 : self.privkey + self.privkey_copied = !is_pk + self.pubkey_copied = is_pk + generator.impactOccurred() + } + if has_authenticated_locally { + copyKey() + } else { + authenticateLocally { success in + if success { + copyKey() + } + } + } }) { let copied = is_pk ? self.pubkey_copied : self.privkey_copied Image(systemName: copied ? "checkmark.circle" : "doc.on.doc") @@ -58,7 +92,7 @@ struct ConfigView: View { if let sec = state.keypair.privkey_bech32 { Section(NSLocalizedString("Secret Account Login Key", comment: "Section title for user's secret account login key.")) { HStack { - if show_privkey == false { + if show_privkey == false || !has_authenticated_locally { SecureField(NSLocalizedString("Private Key", comment: "Title of the secure field that holds the user's private key."), text: $privkey) .disabled(true) } else { @@ -70,6 +104,13 @@ struct ConfigView: View { } Toggle(NSLocalizedString("Show", comment: "Toggle to show or hide user's secret account login key."), isOn: $show_privkey) + .onChange(of: show_privkey) { newValue in + if newValue { + authenticateLocally { success in + show_privkey = success + } + } + } } } diff --git a/translations/en-US.xcloc/Localized Contents/en-US.xliff b/translations/en-US.xcloc/Localized Contents/en-US.xliff index 35fe4a41..aba43920 100644 --- a/translations/en-US.xcloc/Localized Contents/en-US.xliff +++ b/translations/en-US.xcloc/Localized Contents/en-US.xliff @@ -15,6 +15,11 @@ damus Bundle name + + Local authentication to access private key + Local authentication to access private key + Privacy - Face ID Usage Description + Granting Damus access to your photos allows you to save images. Granting Damus access to your photos allows you to save images. @@ -444,6 +449,11 @@ Number of profiles a user is following. Follow Button to follow a user. + + Follow me on nostr + Follow me on nostr + No comment provided by engineer. + Followers Followers @@ -540,6 +550,11 @@ Part of a larger sentence to describe how many profiles a user is following.Lightning Invoice Indicates that the view is for paying a Lightning invoice. + + Local authentication to access private key + Local authentication to access private key + Face ID usage description shown when trying to access private key + Local default Local default @@ -573,11 +588,6 @@ Part of a larger sentence to describe how many profiles a user is following.NIP-05 Verification Label for NIP-05 Verification section of user profile form. - - No - No - Button to cancel out of posting a note after being alerted that it looks like they might be posting a private key. - No block list found, create a new one? This will overwrite any previous block lists. No block list found, create a new one? This will overwrite any previous block lists. @@ -588,11 +598,6 @@ Part of a larger sentence to describe how many profiles a user is following.None Dropdown option for selecting no translation server. - - Note contains "nsec1" private key. Are you sure? - Note contains "nsec1" private key. Are you sure? - Alert user that they might be attempting to paste a private key and ask them to confirm. - Nothing to see here. Check back later! Nothing to see here. Check back later! @@ -714,6 +719,11 @@ Part of a larger sentence to describe how many profiles a user is following.Relays have been notified and clients will be able to use this information to filter content. Thank you! Description of what was done as a result of sending a report to relay servers. + + Remote Image Loading Policy + Remote Image Loading Policy + Section title for remote image loading policy + Remove all Remove all @@ -796,6 +806,11 @@ Part of a larger sentence to describe how many profiles a user is following.Save Image Context menu option to save an image. + + Scan the code + Scan the code + No comment provided by engineer. + Search hashtag: #%@ Search hashtag: #%@ @@ -1011,11 +1026,6 @@ Part of a larger sentence to describe how many profiles a user is following.Yes, Overwrite Text of button that confirms to overwrite the existing mutelist. - - Yes, Post with Private Key - Yes, Post with Private Key - Button to proceed with posting a note even though it looks like they might be posting a private key. - Your Name Your Name @@ -1026,6 +1036,11 @@ Part of a larger sentence to describe how many profiles a user is following.Your report will be sent to the relays you are connected to Footer text to inform user what will happen when the report is submitted. + + Zaps + Zaps + Part of a larger sentence to describe how many zap payments there are on a post. + Zebedee Zebedee @@ -1131,11 +1146,6 @@ Part of a larger sentence to describe how many profiles a user is following.you You, in this context, is the person who controls their own social network. You is used in the context of a larger sentence that welcomes the reader to the social network that they control themself. - - zaps_count - zaps_count - Part of a larger sentence to describe how many zap payments there are on a post. (Key in .stringsdict) - ⚡️ %@ ⚡️ %@ @@ -1281,17 +1291,17 @@ Part of a larger sentence to describe how many profiles a user is following. %#@ZAPS@ %#@ZAPS@ - Part of a larger sentence to describe how many zap payments there are on a post. + Zap Zap - Part of a larger sentence to describe how many zap payments there are on a post. + Zaps Zaps - Part of a larger sentence to describe how many zap payments there are on a post. + diff --git a/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/InfoPlist.strings b/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/InfoPlist.strings index 4a87ad72..adb97316 100644 --- a/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/InfoPlist.strings +++ b/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/InfoPlist.strings @@ -2,5 +2,7 @@ "CFBundleDisplayName" = "Damus"; /* Bundle name */ "CFBundleName" = "damus"; +/* Privacy - Face ID Usage Description */ +"NSFaceIDUsageDescription" = "Local authentication to access private key"; /* Privacy - Photo Library Additions Usage Description */ "NSPhotoLibraryAddUsageDescription" = "Granting Damus access to your photos allows you to save images."; diff --git a/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings b/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings index daf06b11..70207729 100644 Binary files a/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings and b/translations/en-US.xcloc/Source Contents/damus/en-US.lproj/Localizable.strings differ