AuthService.swift 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. // LoopFollow
  2. // AuthService.swift
  3. import Foundation
  4. import LocalAuthentication
  5. public enum AuthResult {
  6. case success
  7. case canceled
  8. case unavailable
  9. case failed
  10. }
  11. public enum AuthService {
  12. /// Unified authentication that prefers biometrics and falls back to passcode automatically.
  13. /// - Parameters:
  14. /// - reason: Shown in the system auth prompt.
  15. /// - reuseDuration: Optional Touch ID/Face ID reuse window (seconds). 0 disables reuse.
  16. /// - completion: Returns an `AuthResult` representing the outcome.
  17. public static func authenticate(reason: String,
  18. reuseDuration: TimeInterval = 0,
  19. completion: @escaping (AuthResult) -> Void)
  20. {
  21. let context = LAContext()
  22. context.localizedFallbackTitle = "Enter Passcode"
  23. if reuseDuration > 0 {
  24. context.touchIDAuthenticationAllowableReuseDuration = reuseDuration
  25. }
  26. var error: NSError?
  27. guard context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) else {
  28. completion(.unavailable)
  29. return
  30. }
  31. context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, err in
  32. DispatchQueue.main.async {
  33. if success {
  34. completion(.success)
  35. return
  36. }
  37. if let e = err as? LAError {
  38. switch e.code {
  39. case .userCancel, .systemCancel, .appCancel:
  40. completion(.canceled)
  41. default:
  42. completion(.failed)
  43. }
  44. } else {
  45. completion(.failed)
  46. }
  47. }
  48. }
  49. }
  50. }