diff --git a/Sources/Packages/Package.swift b/Sources/Packages/Package.swift index 39d9a99..fc0d2e9 100644 --- a/Sources/Packages/Package.swift +++ b/Sources/Packages/Package.swift @@ -44,7 +44,7 @@ let package = Package( .target( name: "SecureEnclaveSecretKit", dependencies: ["SecretKit"], - swiftSettings: [.enableExperimentalFeature("StrictConcurrency"), .unsafeFlags(["-warnings-as-errors"])] + swiftSettings: [.unsafeFlags(["-warnings-as-errors"])] ), .target( name: "SmartCardSecretKit", diff --git a/Sources/Packages/Sources/SecretKit/Types/Secret.swift b/Sources/Packages/Sources/SecretKit/Types/Secret.swift index 8f9656c..6139c21 100644 --- a/Sources/Packages/Sources/SecretKit/Types/Secret.swift +++ b/Sources/Packages/Sources/SecretKit/Types/Secret.swift @@ -17,7 +17,7 @@ public protocol Secret: Identifiable, Hashable { } /// The type of algorithm the Secret uses. Currently, only elliptic curve algorithms are supported. -public enum Algorithm: Hashable { +public enum Algorithm: Hashable, Sendable { case ellipticCurve case rsa diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift index 530d01e..229f055 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveSecret.swift @@ -5,7 +5,7 @@ import SecretKit extension SecureEnclave { /// An implementation of Secret backed by the Secure Enclave. - public struct Secret: SecretKit.Secret { + public struct Secret: SecretKit.Secret, Sendable { public let id: Data public let name: String diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index d079bf3..f17df64 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -180,7 +180,7 @@ extension SecureEnclave { public func persistAuthentication(secret: Secret, forDuration duration: TimeInterval) throws { let newContext = LAContext() - newContext.touchIDAuthenticationAllowableReuseDuration = duration + newContext.touchIDAuthenticationAllowableReuseDuration = max(duration, LATouchIDAuthenticationMaximumAllowableReuseDuration) newContext.localizedCancelTitle = String(localized: "auth_context_request_deny_button") let formatter = DateComponentsFormatter() @@ -196,6 +196,18 @@ extension SecureEnclave { guard success else { return } let context = PersistentAuthenticationContext(secret: secret, context: newContext, duration: duration) self?.persistedAuthenticationContexts[secret] = context + // Contexts will expire within LATouchIDAuthenticationMaximumAllowableReuseDuration unless we periodically refresh them + if duration > LATouchIDAuthenticationMaximumAllowableReuseDuration { + Timer.scheduledTimer(withTimeInterval: LATouchIDAuthenticationMaximumAllowableReuseDuration - 10, repeats: true) { [weak self] timer in + guard let refreshContext = self?.persistedAuthenticationContexts[secret] else { return } + guard refreshContext.valid else { + timer.invalidate() + return + } + refreshContext.context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: "Refresh") { success, _ in + } + } + } } }