commit aeab8aa5d8200e5605cb45cb8d9e7aa890ff242b
parent 1df0c238686c127613b2658a1791e282cffd58fe
Author: Marc Stibane <marc@taler.net>
Date: Thu, 5 Jun 2025 16:14:15 +0200
BiometricService
Diffstat:
1 file changed, 75 insertions(+), 0 deletions(-)
diff --git a/TalerWallet1/Controllers/BiometricService.swift b/TalerWallet1/Controllers/BiometricService.swift
@@ -0,0 +1,75 @@
+/*
+ * This file is part of GNU Taler, ©2022-25 Taler Systems S.A.
+ * See LICENSE.md
+ */
+/**
+ *
+ * @author Marc Stibane
+ */
+import SwiftUI
+import LocalAuthentication
+
+class BiometricService: ObservableObject {
+ static let shared = BiometricService()
+ @Published var isAuthenticated = false
+ @Published var authenticationError: String?
+
+ private var context: LAContext?
+
+ func authenticateUser() {
+ let reason = resetContext()
+
+ guard let context = context else {
+ authenticationError = String(localized: "Failed to initialize authentication context.", comment: "FaceID")
+ return
+ }
+ guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: nil) else {
+ authenticationError = String(localized: "Authentication is not available on this device.", comment: "FaceID")
+ return
+ }
+ context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { [weak self] success, authenticationError in
+ DispatchQueue.main.async {
+ if success {
+ self?.isAuthenticated = true
+ self?.authenticationError = nil
+ } else if let error = authenticationError as? LAError {
+ self?.authenticationError = self?.errorMessage(for: error)
+ } else {
+ self?.authenticationError = String(localized: "Unknown authentication error occurred.", comment: "FaceID")
+ }
+ }
+ }
+ }
+
+ private func resetContext() -> String {
+ let reason = String(localized: "Authenticate to access your money", comment: "FaceID")
+ context = LAContext()
+ context?.localizedReason = reason
+ context?.localizedCancelTitle = String(localized: "Cancel", comment: "FaceID")
+ context?.localizedFallbackTitle = String(localized: "Use Passcode", comment: "FaceID")
+ return reason
+ }
+
+ private func errorMessage(for error: LAError) -> String {
+ switch error.code {
+ case .authenticationFailed:
+ return String(localized: "Authentication failed. Please try again.", comment: "FaceID")
+ case .userCancel:
+ return String(localized: "You canceled the authentication.", comment: "FaceID")
+ case .userFallback:
+ return String(localized: "You chose to use the fallback option.", comment: "FaceID")
+ case .systemCancel:
+ return String(localized: "The system canceled the authentication.", comment: "FaceID")
+ case .passcodeNotSet:
+ return String(localized: "Passcode is not set on this device.", comment: "FaceID")
+ case .biometryNotAvailable:
+ return String(localized: "Biometric authentication is not available on this device.", comment: "FaceID")
+ case .biometryNotEnrolled:
+ return String(localized: "No biometrics are enrolled on this device.", comment: "FaceID")
+ case .biometryLockout:
+ return String(localized: "Biometric authentication is locked. Enter your passcode to unlock.", comment: "FaceID")
+ default:
+ return String(localized: "An unknown error occurred.", comment: "FaceID")
+ }
+ }
+}