Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make core types Sendable and @unchecked Sendable #308

Merged
merged 3 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Sources/Valet/Accessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation


@objc(VALAccessibility)
public enum Accessibility: Int, CaseIterable, CustomStringConvertible, Equatable {
public enum Accessibility: Int, CaseIterable, CustomStringConvertible, Equatable, Sendable {
/// Valet data can only be accessed while the device is unlocked. This attribute is recommended for data that only needs to be accessible while the application is in the foreground. Valet data with this attribute will migrate to a new device when using encrypted backups.
case whenUnlocked = 1
/// Valet data cannot be accessed after a restart until the device has been unlocked once; data is accessible until the device is next rebooted. This attribute is recommended for data that needs to be accessible by background applications. Valet data with this attribute will migrate to a new device when using encrypted backups.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/CloudAccessibility.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation


@objc(VALCloudAccessibility)
public enum CloudAccessibility: Int, CaseIterable, CustomStringConvertible, Equatable {
public enum CloudAccessibility: Int, CaseIterable, CustomStringConvertible, Equatable, Sendable {
/// Valet data can only be accessed while the device is unlocked. This attribute is recommended for data that only needs to be accessible while the application is in the foreground. Valet data with this attribute will migrate to a new device when using encrypted backups.
case whenUnlocked = 1
/// Valet data cannot be accessed after a restart until the device has been unlocked once; data is accessible until the device is next rebooted. This attribute is recommended for data that needs to be accessible by background applications. Valet data with this attribute will migrate to a new device when using encrypted backups.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/Identifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation


public struct Identifier: CustomStringConvertible {
public struct Identifier: CustomStringConvertible, Sendable {

// MARK: Initialization

Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/Internal/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation


internal enum Configuration: CustomStringConvertible {
internal enum Configuration: CustomStringConvertible, Sendable {
case valet(Accessibility)
case iCloud(CloudAccessibility)
case secureEnclave(SecureEnclaveAccessControl)
Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/Internal/Service.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation


internal enum Service: CustomStringConvertible, Equatable {
internal enum Service: CustomStringConvertible, Equatable, Sendable {
case standard(Identifier, Configuration)
case sharedGroup(SharedGroupIdentifier, Identifier?, Configuration)

Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/KeychainError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation


@objc(VALKeychainError)
public enum KeychainError: Int, CaseIterable, CustomStringConvertible, Error, Equatable {
public enum KeychainError: Int, CaseIterable, CustomStringConvertible, Error, Equatable, Sendable {
/// The keychain could not be accessed.
case couldNotAccessKeychain
/// User dismissed the user-presence prompt.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/MigrationError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation


@objc(VALMigrationResult)
public enum MigrationError: Int, CaseIterable, CustomStringConvertible, Error, Equatable {
public enum MigrationError: Int, CaseIterable, CustomStringConvertible, Error, Equatable, Sendable {
/// Migration failed because the keychain query was not valid.
case invalidQuery
/// Migration failed because a key staged for migration was invalid.
Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/SecureEnclave.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation


public final class SecureEnclave {
public final class SecureEnclave: Sendable {

// MARK: Internal Methods

Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/SecureEnclaveAccessControl.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import Foundation


@objc(VALSecureEnclaveAccessControl)
public enum SecureEnclaveAccessControl: Int, CustomStringConvertible, Equatable {
public enum SecureEnclaveAccessControl: Int, CustomStringConvertible, Equatable, Sendable {
/// Access to keychain elements requires user presence verification via Touch ID, Face ID, or device Passcode. On macOS 10.15 and later, this element may also be accessed via a prompt on a paired watch. Keychain elements are still accessible by Touch ID even if fingers are added or removed. Touch ID does not have to be available or enrolled.
case userPresence = 1

Expand Down
7 changes: 4 additions & 3 deletions Sources/Valet/SecureEnclaveValet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Foundation

/// Reads and writes keychain elements that are stored on the Secure Enclave using Accessibility attribute `.whenPasscodeSetThisDeviceOnly`. Accessing these keychain elements will require the user to confirm their presence via Touch ID, Face ID, or passcode entry. If no passcode is set on the device, accessing the keychain via a `SecureEnclaveValet` will fail. Data is removed from the Secure Enclave when the user removes a passcode from the device.
@objc(VALSecureEnclaveValet)
public final class SecureEnclaveValet: NSObject {
public final class SecureEnclaveValet: NSObject, Sendable {

// MARK: Public Class Methods

Expand Down Expand Up @@ -92,7 +92,6 @@ public final class SecureEnclaveValet: NSObject {
self.identifier = identifier
self.service = service
self.accessControl = accessControl
baseKeychainQuery = service.generateBaseQuery()
}

// MARK: Hashable
Expand Down Expand Up @@ -232,7 +231,9 @@ public final class SecureEnclaveValet: NSObject {
// MARK: Private Properties

private let lock = NSLock()
private let baseKeychainQuery: [String : AnyHashable]
private var baseKeychainQuery: [String : AnyHashable] {
return service.generateBaseQuery()
}
Comment on lines +234 to +236
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't love this, but AnyHashable isn't Sendable and service.generateBaseQuery() is fast, so in the tug-of-war between "have the compiler check the thing I know is safe" and "we know it's safe so opt out of checking to do something faster" I'm leaning towards the former.


}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Valet/SharedGroupIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation


public struct SharedGroupIdentifier: CustomStringConvertible {
public struct SharedGroupIdentifier: CustomStringConvertible, Sendable {

// MARK: Initialization

Expand Down
4 changes: 2 additions & 2 deletions Sources/Valet/SinglePromptSecureEnclaveValet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import Foundation
/// Reads and writes keychain elements that are stored on the Secure Enclave using Accessibility attribute `.whenPasscodeSetThisDeviceOnly`. The first access of these keychain elements will require the user to confirm their presence via Touch ID, Face ID, or passcode entry. If no passcode is set on the device, accessing the keychain via a `SinglePromptSecureEnclaveValet` will fail. Data is removed from the Secure Enclave when the user removes a passcode from the device.
@objc(VALSinglePromptSecureEnclaveValet)
@available(watchOS 3, *)
public final class SinglePromptSecureEnclaveValet: NSObject {
public final class SinglePromptSecureEnclaveValet: NSObject, @unchecked Sendable {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The localization context is a var on the type. It's only mutated within a lock, so we are indeed sendable. But the compiler won't be convinced of that... so we use unchecked.


// MARK: Public Class Methods

/// - Parameters:
Expand Down
9 changes: 4 additions & 5 deletions Sources/Valet/Valet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Foundation

/// Reads and writes keychain elements.
@objc(VALValet)
public final class Valet: NSObject {
public final class Valet: NSObject, Sendable {

// MARK: Public Class Methods

Expand Down Expand Up @@ -198,7 +198,6 @@ public final class Valet: NSObject {
self.configuration = configuration
self.service = service
accessibility = configuration.accessibility
baseKeychainQuery = service.generateBaseQuery()
}

#if os(macOS)
Expand All @@ -207,15 +206,13 @@ public final class Valet: NSObject {
self.configuration = configuration
service = .standardOverride(service: identifier, configuration)
accessibility = configuration.accessibility
baseKeychainQuery = service.generateBaseQuery()
}

private init(overrideSharedAccess identifier: SharedGroupIdentifier, configuration: Configuration) {
self.identifier = identifier.asIdentifier
self.configuration = configuration
service = .sharedGroupOverride(service: identifier, configuration)
accessibility = configuration.accessibility
baseKeychainQuery = service.generateBaseQuery()
}
#endif

Expand Down Expand Up @@ -483,7 +480,9 @@ public final class Valet: NSObject {

internal let configuration: Configuration
internal let service: Service
internal let baseKeychainQuery: [String : AnyHashable]
internal var baseKeychainQuery: [String : AnyHashable] {
return service.generateBaseQuery()
}

// MARK: Private Properties

Expand Down
Loading