Add local authentication when accessing private key
Changelog-Added: Use local authentication (faceid) to access private key
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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.";
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user