commit 53ec89551b4183cd7908b52491bb3915d3f57129
parent 638052492dfb6ac6461463f06c7fe6fb5432b47d
Author: Andrii Sievrikov <devandsev@gmail.com>
Date: Sat, 4 Feb 2023 23:11:36 -0500
Add local authentication when accessing private key
Changelog-Added: Use local authentication (faceid) to access private key
Diffstat:
5 files changed, 83 insertions(+), 28 deletions(-)
diff --git 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
@@ -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
@@ -15,6 +15,11 @@
<target>damus</target>
<note>Bundle name</note>
</trans-unit>
+ <trans-unit id="NSFaceIDUsageDescription" xml:space="preserve">
+ <source>Local authentication to access private key</source>
+ <target>Local authentication to access private key</target>
+ <note>Privacy - Face ID Usage Description</note>
+ </trans-unit>
<trans-unit id="NSPhotoLibraryAddUsageDescription" xml:space="preserve">
<source>Granting Damus access to your photos allows you to save images.</source>
<target>Granting Damus access to your photos allows you to save images.</target>
@@ -444,6 +449,11 @@ Number of profiles a user is following.</note>
<target>Follow</target>
<note>Button to follow a user.</note>
</trans-unit>
+ <trans-unit id="Follow me on nostr" xml:space="preserve">
+ <source>Follow me on nostr</source>
+ <target>Follow me on nostr</target>
+ <note>No comment provided by engineer.</note>
+ </trans-unit>
<trans-unit id="Followers" xml:space="preserve">
<source>Followers</source>
<target>Followers</target>
@@ -540,6 +550,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Lightning Invoice</target>
<note>Indicates that the view is for paying a Lightning invoice.</note>
</trans-unit>
+ <trans-unit id="Local authentication to access private key" xml:space="preserve">
+ <source>Local authentication to access private key</source>
+ <target>Local authentication to access private key</target>
+ <note>Face ID usage description shown when trying to access private key</note>
+ </trans-unit>
<trans-unit id="Local default" xml:space="preserve">
<source>Local default</source>
<target>Local default</target>
@@ -573,11 +588,6 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>NIP-05 Verification</target>
<note>Label for NIP-05 Verification section of user profile form.</note>
</trans-unit>
- <trans-unit id="No" xml:space="preserve">
- <source>No</source>
- <target>No</target>
- <note>Button to cancel out of posting a note after being alerted that it looks like they might be posting a private key.</note>
- </trans-unit>
<trans-unit id="No block list found, create a new one? This will overwrite any previous block lists." xml:space="preserve">
<source>No block list found, create a new one? This will overwrite any previous block lists.</source>
<target>No block list found, create a new one? This will overwrite any previous block lists.</target>
@@ -588,11 +598,6 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>None</target>
<note>Dropdown option for selecting no translation server.</note>
</trans-unit>
- <trans-unit id="Note contains "nsec1" private key. Are you sure?" xml:space="preserve">
- <source>Note contains "nsec1" private key. Are you sure?</source>
- <target>Note contains "nsec1" private key. Are you sure?</target>
- <note>Alert user that they might be attempting to paste a private key and ask them to confirm.</note>
- </trans-unit>
<trans-unit id="Nothing to see here. Check back later!" xml:space="preserve">
<source>Nothing to see here. Check back later!</source>
<target>Nothing to see here. Check back later!</target>
@@ -714,6 +719,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Relays have been notified and clients will be able to use this information to filter content. Thank you!</target>
<note>Description of what was done as a result of sending a report to relay servers.</note>
</trans-unit>
+ <trans-unit id="Remote Image Loading Policy" xml:space="preserve">
+ <source>Remote Image Loading Policy</source>
+ <target>Remote Image Loading Policy</target>
+ <note>Section title for remote image loading policy</note>
+ </trans-unit>
<trans-unit id="Remove all" xml:space="preserve">
<source>Remove all</source>
<target>Remove all</target>
@@ -796,6 +806,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Save Image</target>
<note>Context menu option to save an image.</note>
</trans-unit>
+ <trans-unit id="Scan the code" xml:space="preserve">
+ <source>Scan the code</source>
+ <target>Scan the code</target>
+ <note>No comment provided by engineer.</note>
+ </trans-unit>
<trans-unit id="Search hashtag: #%@" xml:space="preserve">
<source>Search hashtag: #%@</source>
<target>Search hashtag: #%@</target>
@@ -1011,11 +1026,6 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Yes, Overwrite</target>
<note>Text of button that confirms to overwrite the existing mutelist.</note>
</trans-unit>
- <trans-unit id="Yes, Post with Private Key" xml:space="preserve">
- <source>Yes, Post with Private Key</source>
- <target>Yes, Post with Private Key</target>
- <note>Button to proceed with posting a note even though it looks like they might be posting a private key.</note>
- </trans-unit>
<trans-unit id="Your Name" xml:space="preserve">
<source>Your Name</source>
<target>Your Name</target>
@@ -1026,6 +1036,11 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>Your report will be sent to the relays you are connected to</target>
<note>Footer text to inform user what will happen when the report is submitted.</note>
</trans-unit>
+ <trans-unit id="Zaps" xml:space="preserve">
+ <source>Zaps</source>
+ <target>Zaps</target>
+ <note>Part of a larger sentence to describe how many zap payments there are on a post.</note>
+ </trans-unit>
<trans-unit id="Zebedee" xml:space="preserve">
<source>Zebedee</source>
<target>Zebedee</target>
@@ -1131,11 +1146,6 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<target>you</target>
<note>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.</note>
</trans-unit>
- <trans-unit id="zaps_count" translate="no" xml:space="preserve">
- <source>zaps_count</source>
- <target>zaps_count</target>
- <note>Part of a larger sentence to describe how many zap payments there are on a post. (Key in .stringsdict)</note>
- </trans-unit>
<trans-unit id="⚡️ %@" xml:space="preserve">
<source>⚡️ %@</source>
<target>⚡️ %@</target>
@@ -1281,17 +1291,17 @@ Part of a larger sentence to describe how many profiles a user is following.</no
<trans-unit id="/zaps_count:dict/NSStringLocalizedFormatKey:dict/:string" xml:space="preserve">
<source>%#@ZAPS@</source>
<target>%#@ZAPS@</target>
- <note>Part of a larger sentence to describe how many zap payments there are on a post.</note>
+ <note/>
</trans-unit>
<trans-unit id="/zaps_count:dict/ZAPS:dict/one:dict/:string" xml:space="preserve">
<source>Zap</source>
<target>Zap</target>
- <note>Part of a larger sentence to describe how many zap payments there are on a post.</note>
+ <note/>
</trans-unit>
<trans-unit id="/zaps_count:dict/ZAPS:dict/other:dict/:string" xml:space="preserve">
<source>Zaps</source>
<target>Zaps</target>
- <note>Part of a larger sentence to describe how many zap payments there are on a post.</note>
+ <note/>
</trans-unit>
</body>
</file>
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
@@ -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
Binary files differ.