RadrootsUserPresence.swift (3359B)
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 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 77 case userCancelled 78 case permissionDenied 79 case unavailable 80 case timeout 81 case transientFailure 82 case permanentFailure 83 } 84 85 extension RadrootsUserPresenceError: LocalizedError { 86 public var errorDescription: String? { 87 switch self { 88 case .invalidRequest: "The user-presence request is invalid." 89 case .userCancelled: "User-presence verification was cancelled." 90 case .permissionDenied: "User-presence verification was denied." 91 case .unavailable: "User-presence verification is unavailable." 92 case .timeout: "User-presence verification timed out." 93 case .transientFailure: "User-presence verification could not be completed temporarily." 94 case .permanentFailure: "User-presence verification could not be completed." 95 } 96 } 97 } 98 99 public protocol RadrootsUserPresence: Sendable { 100 func currentStatus() async throws -> RadrootsUserPresenceStatus 101 func verify(_ request: RadrootsUserPresenceRequest) async throws -> RadrootsUserPresenceResult 102 }