diff --git a/Sources/Packages/Package.swift b/Sources/Packages/Package.swift index 1594580..a666ec0 100644 --- a/Sources/Packages/Package.swift +++ b/Sources/Packages/Package.swift @@ -27,18 +27,26 @@ let package = Package( .library( name: "Brief", targets: ["Brief"]), + .library( + name: "Backports", + targets: ["Backports"]), ], dependencies: [ ], targets: [ .target( - name: "SecretKit", + name: "Backports", dependencies: [], swiftSettings: swiftSettings ), + .target( + name: "SecretKit", + dependencies: ["Backports"], + swiftSettings: swiftSettings + ), .testTarget( name: "SecretKitTests", - dependencies: ["SecretKit", "SecureEnclaveSecretKit", "SmartCardSecretKit"], + dependencies: ["Backports", "SecretKit", "SecureEnclaveSecretKit", "SmartCardSecretKit"], swiftSettings: swiftSettings ), .target( @@ -48,12 +56,12 @@ let package = Package( ), .target( name: "SmartCardSecretKit", - dependencies: ["SecretKit"], + dependencies: ["Backports", "SecretKit"], swiftSettings: swiftSettings ), .target( name: "SecretAgentKit", - dependencies: ["SecretKit", "SecretAgentKitHeaders"], + dependencies: ["Backports", "SecretKit", "SecretAgentKitHeaders"], swiftSettings: swiftSettings ), .systemLibrary( @@ -65,7 +73,7 @@ let package = Package( , .target( name: "Brief", - dependencies: [] + dependencies: ["Backports"] ), .testTarget( name: "BriefTests", diff --git a/Sources/Packages/Sources/Backports/_Mutex.swift b/Sources/Packages/Sources/Backports/_Mutex.swift new file mode 100644 index 0000000..b389a58 --- /dev/null +++ b/Sources/Packages/Sources/Backports/_Mutex.swift @@ -0,0 +1,30 @@ +import Foundation + +#if canImport(Synchronization) +import Synchronization +public typealias _Mutex = Mutex +#else + +import os + +public final class _Mutex: @unchecked Sendable { + + private var value: Value + private var lock = OSAllocatedUnfairLock() + + public init(_ value: consuming sending Value) { + self.value = value + } + + public borrowing func withLock(_ body: (inout sending Value) throws(E) -> sending Result) throws(E) -> sending Result where E : Error, Result : ~Copyable { + lock.lock() + defer { + lock.unlock() + } + return try body(&value) + } + + +} + +#endif diff --git a/Sources/Packages/Sources/Brief/Updater.swift b/Sources/Packages/Sources/Brief/Updater.swift index 334689d..315e779 100644 --- a/Sources/Packages/Sources/Brief/Updater.swift +++ b/Sources/Packages/Sources/Brief/Updater.swift @@ -1,6 +1,7 @@ import Foundation import Observation import Synchronization +import Backports /// A concrete implementation of ``UpdaterProtocol`` which considers the current release and OS version. @Observable public final class Updater: UpdaterProtocol, ObservableObject, Sendable { @@ -8,7 +9,7 @@ import Synchronization public var update: Release? { _update.withLock { $0 } } - private let _update: Mutex = .init(nil) + private let _update: _Mutex = .init(nil) public let testBuild: Bool /// The current OS version. diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift index d8345ba..fe0243c 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift @@ -1,6 +1,7 @@ import Foundation import OSLog import Synchronization +import Backports /// Manages storage and lookup for OpenSSH certificates. public final class OpenSSHCertificateHandler: Sendable { @@ -8,7 +9,7 @@ public final class OpenSSHCertificateHandler: Sendable { private let publicKeyFileStoreController = PublicKeyFileStoreController(homeDirectory: NSHomeDirectory()) private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent", category: "OpenSSHCertificateHandler") private let writer = OpenSSHKeyWriter() - private let keyBlobsAndNames: Mutex<[AnySecret: (Data, Data)]> = .init([:]) + private let keyBlobsAndNames: _Mutex<[AnySecret: (Data, Data)]> = .init([:]) /// Initializes an OpenSSHCertificateHandler. public init() { diff --git a/Sources/Packages/Sources/SecretKit/SecretStoreList.swift b/Sources/Packages/Sources/SecretKit/SecretStoreList.swift index b2ef3b2..be01ed5 100644 --- a/Sources/Packages/Sources/SecretKit/SecretStoreList.swift +++ b/Sources/Packages/Sources/SecretKit/SecretStoreList.swift @@ -1,6 +1,7 @@ import Foundation import Observation import Synchronization +import Backports /// A "Store Store," which holds a list of type-erased stores. @Observable public final class SecretStoreList: Sendable { @@ -9,13 +10,13 @@ import Synchronization public var stores: [AnySecretStore] { __stores.withLock { $0 } } - private let __stores: Mutex<[AnySecretStore]> = .init([]) + private let __stores: _Mutex<[AnySecretStore]> = .init([]) /// A modifiable store, if one is available. public var modifiableStore: AnySecretStoreModifiable? { __modifiableStore.withLock { $0 } } - private let __modifiableStore: Mutex = .init(nil) + private let __modifiableStore: _Mutex = .init(nil) /// Initializes a SecretStoreList. public init() { diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index 371cdd5..c37b596 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -5,6 +5,7 @@ import CryptoKit import LocalAuthentication import SecretKit import Synchronization +import Backports extension SecureEnclave { @@ -19,9 +20,9 @@ extension SecureEnclave { public var secrets: [Secret] { _secrets.withLock { $0 } } - private let _secrets: Mutex<[Secret]> = .init([]) + private let _secrets: _Mutex<[Secret]> = .init([]) - private let persistedAuthenticationContexts: Mutex<[Secret: PersistentAuthenticationContext]> = .init([:]) + private let persistedAuthenticationContexts: _Mutex<[Secret: PersistentAuthenticationContext]> = .init([:]) /// Initializes a Store. public init() { @@ -105,7 +106,7 @@ extension SecureEnclave { } public func sign(data: Data, with secret: Secret, for provenance: SigningRequestProvenance) throws -> Data { - let context: Mutex + let context: _Mutex // if let existing = persistedAuthenticationContexts.withLock({ $0 })[secret], existing.valid { // context = existing.context // } else { diff --git a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift index 199e4cd..d561605 100644 --- a/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift +++ b/Sources/Packages/Sources/SmartCardSecretKit/SmartCardStore.swift @@ -5,6 +5,7 @@ import Security import CryptoTokenKit import LocalAuthentication import SecretKit +import Backports extension SmartCard { @@ -19,7 +20,7 @@ extension SmartCard { /// An implementation of Store backed by a Smart Card. @Observable public final class Store: SecretStore { - private let state: Mutex = .init(.init()) + private let state: _Mutex = .init(.init()) public var isAvailable: Bool { state.withLock { $0.isAvailable } } diff --git a/Sources/SecretAgent/Notifier.swift b/Sources/SecretAgent/Notifier.swift index 2f0e15a..ff1d147 100644 --- a/Sources/SecretAgent/Notifier.swift +++ b/Sources/SecretAgent/Notifier.swift @@ -5,6 +5,7 @@ import SecretKit import SecretAgentKit import Brief import Synchronization +import Backports final class Notifier: Sendable { @@ -151,7 +152,7 @@ final class NotificationDelegate: NSObject, UNUserNotificationCenterDelegate, Se fileprivate var pendingPersistableSecrets: [String: AnySecret] = [:] } - fileprivate let state: Mutex = .init(.init()) + fileprivate let state: _Mutex = .init(.init()) func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) { diff --git a/Sources/Secretive/Preview Content/PreviewUpdater.swift b/Sources/Secretive/Preview Content/PreviewUpdater.swift index 6979615..04c6658 100644 --- a/Sources/Secretive/Preview Content/PreviewUpdater.swift +++ b/Sources/Secretive/Preview Content/PreviewUpdater.swift @@ -2,13 +2,14 @@ import Foundation import Synchronization import Observation import Brief +import Backports @Observable class PreviewUpdater: UpdaterProtocol { var update: Release? { _update.withLock { $0 } } - let _update: Mutex = .init(nil) + let _update: _Mutex = .init(nil) let testBuild = false