Add local authentication when accessing private key

This commit is contained in:
Andrii Sievrikov
2023-02-04 23:11:36 -05:00
parent 7d3d23def3
commit 84ad0e03d0
2 changed files with 48 additions and 5 deletions

View File

@@ -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;

View File

@@ -7,6 +7,7 @@
import AVFoundation
import Kingfisher
import SwiftUI
import LocalAuthentication
enum RemoteImagePolicy: String, CaseIterable {
case everyone
@@ -34,6 +35,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
@@ -50,13 +52,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")
@@ -78,7 +112,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 {
@@ -90,6 +124,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
}
}
}
}
}