From 309c7f2f3c01ba301c1f2f89861f772848d7a8c4 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Wed, 15 Jan 2025 22:01:52 -0300 Subject: [PATCH 1/3] Add `Sendable` conformance --- SimpleKeychain/Accessibility.swift | 2 +- SimpleKeychain/SimpleKeychain.swift | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/SimpleKeychain/Accessibility.swift b/SimpleKeychain/Accessibility.swift index 698cfb9..36cde3f 100644 --- a/SimpleKeychain/Accessibility.swift +++ b/SimpleKeychain/Accessibility.swift @@ -1,7 +1,7 @@ import Security /// Represents the accessibility types of Keychain items. It's a mirror of `kSecAttrAccessible` values. -public enum Accessibility: RawRepresentable { +public enum Accessibility: RawRepresentable, Sendable { /// The data in the Keychain item can be accessed only while the device is unlocked by the user. /// See [kSecAttrAccessibleWhenUnlocked](https://developer.apple.com/documentation/security/ksecattraccessiblewhenunlocked). diff --git a/SimpleKeychain/SimpleKeychain.swift b/SimpleKeychain/SimpleKeychain.swift index c9fe1ab..8ff3d07 100644 --- a/SimpleKeychain/SimpleKeychain.swift +++ b/SimpleKeychain/SimpleKeychain.swift @@ -1,7 +1,7 @@ import Foundation import Security #if canImport(LocalAuthentication) -import LocalAuthentication +@preconcurrency import LocalAuthentication #endif typealias RetrieveFunction = (_ query: CFDictionary, _ result: UnsafeMutablePointer?) -> OSStatus @@ -10,16 +10,16 @@ typealias RemoveFunction = (_ query: CFDictionary) -> OSStatus /// A simple Keychain wrapper for iOS, macOS, tvOS, and watchOS. /// Supports sharing credentials with an **access group** or through **iCloud**, and integrating /// **Touch ID / Face ID**. -public struct SimpleKeychain { +public struct SimpleKeychain: Sendable { let service: String let accessGroup: String? let accessibility: Accessibility let accessControlFlags: SecAccessControlCreateFlags? let isSynchronizable: Bool - let attributes: [String: Any] + nonisolated(unsafe) let attributes: [String: Any] - var retrieve: RetrieveFunction = SecItemCopyMatching - var remove: RemoveFunction = SecItemDelete + nonisolated(unsafe) var retrieve: RetrieveFunction = SecItemCopyMatching + nonisolated(unsafe) var remove: RemoveFunction = SecItemDelete #if canImport(LocalAuthentication) && !os(tvOS) let context: LAContext? From fe3ede74ff9caeb23312b4bed4664a33722ac318 Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 16 Jan 2025 19:27:31 +0000 Subject: [PATCH 2/3] Guard changes with `canImport` for older Xcode versions --- SimpleKeychain/Accessibility.swift | 8 +++++++- SimpleKeychain/SimpleKeychain.swift | 21 +++++++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/SimpleKeychain/Accessibility.swift b/SimpleKeychain/Accessibility.swift index 36cde3f..ea54dd4 100644 --- a/SimpleKeychain/Accessibility.swift +++ b/SimpleKeychain/Accessibility.swift @@ -1,7 +1,7 @@ import Security /// Represents the accessibility types of Keychain items. It's a mirror of `kSecAttrAccessible` values. -public enum Accessibility: RawRepresentable, Sendable { +public enum Accessibility: RawRepresentable { /// The data in the Keychain item can be accessed only while the device is unlocked by the user. /// See [kSecAttrAccessibleWhenUnlocked](https://developer.apple.com/documentation/security/ksecattraccessiblewhenunlocked). @@ -50,3 +50,9 @@ public enum Accessibility: RawRepresentable, Sendable { } } } + +// MARK: - Sendable conformance + +#if canImport(_Concurrency) +extension Accessibility: Sendable {} +#endif diff --git a/SimpleKeychain/SimpleKeychain.swift b/SimpleKeychain/SimpleKeychain.swift index 8ff3d07..2e01b20 100644 --- a/SimpleKeychain/SimpleKeychain.swift +++ b/SimpleKeychain/SimpleKeychain.swift @@ -1,7 +1,12 @@ import Foundation import Security #if canImport(LocalAuthentication) +#if canImport(_Concurrency) @preconcurrency import LocalAuthentication +#else +// swiftlint:disable:next duplicate_imports +import LocalAuthentication +#endif #endif typealias RetrieveFunction = (_ query: CFDictionary, _ result: UnsafeMutablePointer?) -> OSStatus @@ -10,16 +15,22 @@ typealias RemoveFunction = (_ query: CFDictionary) -> OSStatus /// A simple Keychain wrapper for iOS, macOS, tvOS, and watchOS. /// Supports sharing credentials with an **access group** or through **iCloud**, and integrating /// **Touch ID / Face ID**. -public struct SimpleKeychain: Sendable { +public struct SimpleKeychain { let service: String let accessGroup: String? let accessibility: Accessibility let accessControlFlags: SecAccessControlCreateFlags? let isSynchronizable: Bool - nonisolated(unsafe) let attributes: [String: Any] + #if canImport(_Concurrency) + nonisolated(unsafe) let attributes: [String: Any] nonisolated(unsafe) var retrieve: RetrieveFunction = SecItemCopyMatching nonisolated(unsafe) var remove: RemoveFunction = SecItemDelete + #else + let attributes: [String: Any] + var retrieve: RetrieveFunction = SecItemCopyMatching + var remove: RemoveFunction = SecItemDelete + #endif #if canImport(LocalAuthentication) && !os(tvOS) let context: LAContext? @@ -321,3 +332,9 @@ extension SimpleKeychain { return query } } + +// MARK: - Sendable conformance + +#if canImport(_Concurrency) +extension SimpleKeychain: Sendable {} +#endif From 8de16a83a3e8e335981937625470f1a768818f1d Mon Sep 17 00:00:00 2001 From: Rita Zerrizuela Date: Thu, 16 Jan 2025 19:34:30 +0000 Subject: [PATCH 3/3] Use `@unchecked` instead of `nonisolated` --- SimpleKeychain/Accessibility.swift | 8 +------- SimpleKeychain/SimpleKeychain.swift | 21 ++------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/SimpleKeychain/Accessibility.swift b/SimpleKeychain/Accessibility.swift index ea54dd4..6af1fa7 100644 --- a/SimpleKeychain/Accessibility.swift +++ b/SimpleKeychain/Accessibility.swift @@ -1,7 +1,7 @@ import Security /// Represents the accessibility types of Keychain items. It's a mirror of `kSecAttrAccessible` values. -public enum Accessibility: RawRepresentable { +public enum Accessibility: RawRepresentable, @unchecked Sendable { /// The data in the Keychain item can be accessed only while the device is unlocked by the user. /// See [kSecAttrAccessibleWhenUnlocked](https://developer.apple.com/documentation/security/ksecattraccessiblewhenunlocked). @@ -50,9 +50,3 @@ public enum Accessibility: RawRepresentable { } } } - -// MARK: - Sendable conformance - -#if canImport(_Concurrency) -extension Accessibility: Sendable {} -#endif diff --git a/SimpleKeychain/SimpleKeychain.swift b/SimpleKeychain/SimpleKeychain.swift index 2e01b20..24191d5 100644 --- a/SimpleKeychain/SimpleKeychain.swift +++ b/SimpleKeychain/SimpleKeychain.swift @@ -1,12 +1,7 @@ import Foundation import Security #if canImport(LocalAuthentication) -#if canImport(_Concurrency) @preconcurrency import LocalAuthentication -#else -// swiftlint:disable:next duplicate_imports -import LocalAuthentication -#endif #endif typealias RetrieveFunction = (_ query: CFDictionary, _ result: UnsafeMutablePointer?) -> OSStatus @@ -15,22 +10,16 @@ typealias RemoveFunction = (_ query: CFDictionary) -> OSStatus /// A simple Keychain wrapper for iOS, macOS, tvOS, and watchOS. /// Supports sharing credentials with an **access group** or through **iCloud**, and integrating /// **Touch ID / Face ID**. -public struct SimpleKeychain { +public struct SimpleKeychain: @unchecked Sendable { let service: String let accessGroup: String? let accessibility: Accessibility let accessControlFlags: SecAccessControlCreateFlags? let isSynchronizable: Bool - - #if canImport(_Concurrency) - nonisolated(unsafe) let attributes: [String: Any] - nonisolated(unsafe) var retrieve: RetrieveFunction = SecItemCopyMatching - nonisolated(unsafe) var remove: RemoveFunction = SecItemDelete - #else let attributes: [String: Any] + var retrieve: RetrieveFunction = SecItemCopyMatching var remove: RemoveFunction = SecItemDelete - #endif #if canImport(LocalAuthentication) && !os(tvOS) let context: LAContext? @@ -332,9 +321,3 @@ extension SimpleKeychain { return query } } - -// MARK: - Sendable conformance - -#if canImport(_Concurrency) -extension SimpleKeychain: Sendable {} -#endif