RadrootsUserPresence.swift (3358B)
1 import Foundation 2 3 public enum RadrootsUserPresencePolicy: String, Sendable, Equatable, Hashable, CaseIterable { 4 case deviceOwnerAuthentication 5 case deviceOwnerAuthenticationWithBiometrics 6 } 7 8 public enum RadrootsUserPresenceSupport: String, Sendable, Equatable, Hashable { 9 case none 10 case deviceCredential 11 case biometricsOrDeviceCredential 12 } 13 14 public enum RadrootsBiometryKind: String, Sendable, Equatable, Hashable { 15 case none 16 case touchID 17 case faceID 18 case opticID 19 case unknown 20 } 21 22 public struct RadrootsUserPresenceStatus: Sendable, Equatable, Hashable { 23 public let support: RadrootsUserPresenceSupport 24 public let biometryKind: RadrootsBiometryKind 25 public let canEvaluateDeviceCredential: Bool 26 public let canEvaluateBiometrics: Bool 27 28 public init( 29 support: RadrootsUserPresenceSupport, 30 biometryKind: RadrootsBiometryKind, 31 canEvaluateDeviceCredential: Bool, 32 canEvaluateBiometrics: Bool 33 ) { 34 self.support = support 35 self.biometryKind = biometryKind 36 self.canEvaluateDeviceCredential = canEvaluateDeviceCredential 37 self.canEvaluateBiometrics = canEvaluateBiometrics 38 } 39 40 public static let unavailable = Self( 41 support: .none, 42 biometryKind: .none, 43 canEvaluateDeviceCredential: false, 44 canEvaluateBiometrics: false 45 ) 46 } 47 48 public struct RadrootsUserPresenceRequest: Sendable, Equatable, Hashable { 49 public let policy: RadrootsUserPresencePolicy 50 public let reason: String 51 52 public init( 53 policy: RadrootsUserPresencePolicy = .deviceOwnerAuthentication, 54 reason: String 55 ) throws { 56 let normalizedReason = reason.trimmingCharacters(in: .whitespacesAndNewlines) 57 guard !normalizedReason.isEmpty else { 58 throw RadrootsUserPresenceError.invalidRequest("user presence reason cannot be empty") 59 } 60 self.policy = policy 61 self.reason = normalizedReason 62 } 63 } 64 65 public struct RadrootsUserPresenceResult: Sendable, Equatable, Hashable { 66 public let policy: RadrootsUserPresencePolicy 67 public let verified: Bool 68 69 public init(policy: RadrootsUserPresencePolicy, verified: Bool) { 70 self.policy = policy 71 self.verified = verified 72 } 73 } 74 75 public enum RadrootsUserPresenceError: Error, Equatable, Sendable { 76 case invalidRequest(String) 77 case userCancelled(String) 78 case permissionDenied(String) 79 case unavailable(String) 80 case timeout(String) 81 case transientFailure(String) 82 case permanentFailure(String) 83 } 84 85 extension RadrootsUserPresenceError: LocalizedError { 86 public var errorDescription: String? { 87 switch self { 88 case .invalidRequest(let message): 89 message 90 case .userCancelled(let message): 91 message 92 case .permissionDenied(let message): 93 message 94 case .unavailable(let message): 95 message 96 case .timeout(let message): 97 message 98 case .transientFailure(let message): 99 message 100 case .permanentFailure(let message): 101 message 102 } 103 } 104 } 105 106 public protocol RadrootsUserPresence: Sendable { 107 func currentStatus() async throws -> RadrootsUserPresenceStatus 108 func verify(_ request: RadrootsUserPresenceRequest) async throws -> RadrootsUserPresenceResult 109 }