mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-01-07 17:02:00 +01:00
Merge 825824d5cb into 9f2c6d9e84
This commit is contained in:
commit
34c4cf0988
@ -18,6 +18,7 @@ extension SecureEnclave {
|
|||||||
public let id = UUID()
|
public let id = UUID()
|
||||||
public let name = String(localized: .secureEnclave)
|
public let name = String(localized: .secureEnclave)
|
||||||
private let persistentAuthenticationHandler = PersistentAuthenticationHandler<Secret>()
|
private let persistentAuthenticationHandler = PersistentAuthenticationHandler<Secret>()
|
||||||
|
private let signingSerializer = SigningSerializer()
|
||||||
|
|
||||||
/// Initializes a Store.
|
/// Initializes a Store.
|
||||||
@MainActor public init() {
|
@MainActor public init() {
|
||||||
@ -38,6 +39,16 @@ extension SecureEnclave {
|
|||||||
// MARK: SecretStore
|
// MARK: SecretStore
|
||||||
|
|
||||||
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) async throws -> Data {
|
public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) async throws -> Data {
|
||||||
|
if secret.attributes.authentication.required {
|
||||||
|
return try await signingSerializer.serialize { [self] in
|
||||||
|
try await self.performSign(data: data, with: secret, for: provenance)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return try await performSign(data: data, with: secret, for: provenance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func performSign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) async throws -> Data {
|
||||||
var context: LAContext
|
var context: LAContext
|
||||||
if let existing = await persistentAuthenticationHandler.existingPersistedAuthenticationContext(secret: secret) {
|
if let existing = await persistentAuthenticationHandler.existingPersistedAuthenticationContext(secret: secret) {
|
||||||
context = unsafe existing.context
|
context = unsafe existing.context
|
||||||
@ -85,7 +96,6 @@ extension SecureEnclave {
|
|||||||
default:
|
default:
|
||||||
throw UnsupportedAlgorithmError()
|
throw UnsupportedAlgorithmError()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func existingPersistedAuthenticationContext(secret: Secret) async -> PersistedAuthenticationContext? {
|
public func existingPersistedAuthenticationContext(secret: Secret) async -> PersistedAuthenticationContext? {
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// Serializes signing operations for protected keys to prevent LAContext conflicts.
|
||||||
|
/// macOS only allows one biometric authentication prompt at a time, so concurrent
|
||||||
|
/// requests for protected Secure Enclave keys must be queued.
|
||||||
|
actor SigningSerializer {
|
||||||
|
private var isProcessing = false
|
||||||
|
private var waiters: [CheckedContinuation<Void, Never>] = []
|
||||||
|
|
||||||
|
func serialize<T: Sendable>(operation: @escaping @Sendable () async throws -> T) async throws -> T {
|
||||||
|
// If someone is already processing, wait in line
|
||||||
|
if isProcessing {
|
||||||
|
await withCheckedContinuation { continuation in
|
||||||
|
waiters.append(continuation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isProcessing = true
|
||||||
|
|
||||||
|
defer {
|
||||||
|
if let next = waiters.first {
|
||||||
|
waiters.removeFirst()
|
||||||
|
next.resume()
|
||||||
|
} else {
|
||||||
|
isProcessing = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return try await operation()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user