Hello I have a log in view that uses face recognition to authenticate the user and If the user is authenticated it reads their log in info from keychain if they have it saved. For some reason all this functionality isn't working, Ive looked at some other SO threads and was not able to get it working. I think something is wrong with both the save and read functions. I was able to get the authentication function working however. Id appreciate any help.
import SwiftUI
import LocalAuthentication
import AuthenticationServices
struct LogInView: View {
@State private var email = ""
@State private var password = ""
var body: some View {
ZStack(alignment: .top){
GeometryReader { geometry in
VStack {
HStack{
Button {
save(email: email, password: password)
} label: {
Text("Save password")
}
}.padding(.top, 10)
VStack(spacing: 15){
CustomTextField(imageName: "envelope", placeHolderText: "Email", text: $email)
CustomTextField(imageName: "lock", placeHolderText: "Password", isSecureField: true, text: $password)
}
}
}
}
.onAppear(perform: authenticate)
}
func save(email: String, password: String) {
let emailData = email.data(using: .utf8)!
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassInternetPassword,
kSecAttrService as String: "https://hustle.page",
kSecAttrAccount as String: emailData,
kSecValueData as String: passwordData
]
let saveStatus = SecItemAdd(query as CFDictionary, nil)
if saveStatus == errSecDuplicateItem {
update(email: email, password: password)
}
}
func update(email: String, password: String) {
let emailData = email.data(using: .utf8)!
let passwordData = password.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassInternetPassword,
kSecAttrService as String: "https://hustle.page",
kSecAttrAccount as String: emailData
]
let updatedData: [String: Any] = [
kSecValueData as String: passwordData
]
SecItemUpdate(query as CFDictionary, updatedData as CFDictionary)
}
func read(service: String) -> (String, String)? {
let query: [String: Any] = [
kSecClass as String: kSecClassInternetPassword,
kSecAttrService as String: service,
kSecReturnAttributes as String: true,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitAll
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
if status == errSecSuccess, let items = result as? [[String: Any]], let item = items.first {
if let account = item[kSecAttrAccount as String] as? String,
let passwordData = item[kSecValueData as String] as? Data,
let password = String(data: passwordData, encoding: .utf8) {
return (account, password)
}
}
return nil
}
func authenticate() {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
let reason = "Secure Authentication."
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, authenticationError in
if success {
if let loginInfo = read(service: "https://hustle.page") {
let (email, password) = loginInfo
}
}
}
}
}
}