Add local authentication when accessing private key
This commit is contained in:
@@ -1494,6 +1494,7 @@
|
|||||||
INFOPLIST_FILE = damus/Info.plist;
|
INFOPLIST_FILE = damus/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Damus;
|
INFOPLIST_KEY_CFBundleDisplayName = Damus;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
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_NSPhotoLibraryAddUsageDescription = "Granting Damus access to your photos allows you to save images.";
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
@@ -1535,6 +1536,7 @@
|
|||||||
INFOPLIST_FILE = damus/Info.plist;
|
INFOPLIST_FILE = damus/Info.plist;
|
||||||
INFOPLIST_KEY_CFBundleDisplayName = Damus;
|
INFOPLIST_KEY_CFBundleDisplayName = Damus;
|
||||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking";
|
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_NSPhotoLibraryAddUsageDescription = "Granting Damus access to your photos allows you to save images.";
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
import AVFoundation
|
import AVFoundation
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import LocalAuthentication
|
||||||
|
|
||||||
enum RemoteImagePolicy: String, CaseIterable {
|
enum RemoteImagePolicy: String, CaseIterable {
|
||||||
case everyone
|
case everyone
|
||||||
@@ -34,6 +35,7 @@ struct ConfigView: View {
|
|||||||
@State var confirm_logout: Bool = false
|
@State var confirm_logout: Bool = false
|
||||||
@State var confirm_delete_account: Bool = false
|
@State var confirm_delete_account: Bool = false
|
||||||
@State var show_privkey: 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 show_libretranslate_api_key: Bool = false
|
||||||
@State var privkey: String
|
@State var privkey: String
|
||||||
@State var privkey_copied: Bool = false
|
@State var privkey_copied: Bool = false
|
||||||
@@ -50,13 +52,45 @@ struct ConfigView: View {
|
|||||||
_settings = ObservedObject(initialValue: state.settings)
|
_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
|
// TODO: (jb55) could be more general but not gonna worry about it atm
|
||||||
func CopyButton(is_pk: Bool) -> some View {
|
func CopyButton(is_pk: Bool) -> some View {
|
||||||
return Button(action: {
|
return Button(action: {
|
||||||
UIPasteboard.general.string = is_pk ? self.state.keypair.pubkey_bech32 : self.privkey
|
let copyKey = {
|
||||||
self.privkey_copied = !is_pk
|
UIPasteboard.general.string = is_pk ? self.state.keypair.pubkey_bech32 : self.privkey
|
||||||
self.pubkey_copied = is_pk
|
self.privkey_copied = !is_pk
|
||||||
generator.impactOccurred()
|
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
|
let copied = is_pk ? self.pubkey_copied : self.privkey_copied
|
||||||
Image(systemName: copied ? "checkmark.circle" : "doc.on.doc")
|
Image(systemName: copied ? "checkmark.circle" : "doc.on.doc")
|
||||||
@@ -78,7 +112,7 @@ struct ConfigView: View {
|
|||||||
if let sec = state.keypair.privkey_bech32 {
|
if let sec = state.keypair.privkey_bech32 {
|
||||||
Section(NSLocalizedString("Secret Account Login Key", comment: "Section title for user's secret account login key.")) {
|
Section(NSLocalizedString("Secret Account Login Key", comment: "Section title for user's secret account login key.")) {
|
||||||
HStack {
|
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)
|
SecureField(NSLocalizedString("Private Key", comment: "Title of the secure field that holds the user's private key."), text: $privkey)
|
||||||
.disabled(true)
|
.disabled(true)
|
||||||
} else {
|
} 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)
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user