tethering-hider/TetheringHider/Services/AuthenticationService.swift

53 lines
1.9 KiB
Swift
Raw Normal View History

2026-08-12 23:44:59 -05:00
import Foundation
import LocalAuthentication
enum AuthenticationError: LocalizedError {
case biometricsNotAvailable
case authenticationFailed(String)
case userCancelled
var errorDescription: String? {
switch self {
case .biometricsNotAvailable:
return "Touch ID is not available on this device."
case .authenticationFailed(let reason):
return "Authentication failed: \(reason)"
case .userCancelled:
return "Authentication was cancelled."
}
}
}
struct AuthenticationService: Sendable {
/// Attempts biometric authentication (Touch ID) before proceeding.
/// Falls back gracefully if Touch ID is not available.
/// Returns true if authenticated, false if biometrics unavailable (will proceed to admin dialog).
func authenticateWithBiometrics() async throws -> Bool {
let context = LAContext()
var error: NSError?
guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {
// Touch ID not available skip biometric step, will use admin dialog
return true
}
do {
let success = try await context.evaluatePolicy(
.deviceOwnerAuthenticationWithBiometrics,
localizedReason: "Authenticate to modify system TTL value"
)
return success
} catch let authError as LAError {
switch authError.code {
case .userCancel, .appCancel:
throw AuthenticationError.userCancelled
case .userFallback:
// User chose to use password allow proceeding to admin dialog
return true
default:
throw AuthenticationError.authenticationFailed(authError.localizedDescription)
}
}
}
}