SecItem
* Added a SecItem enum to wrap existing security API functions * Updated the SecError to easily create an error from an OSStatus * Updated the SecError.Code to be more future proof and performant * Removed the unused Keychain.swift file
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ public struct SecError: Error, Hashable, Sendable {
|
||||
/// The error code.
|
||||
public let code: Code
|
||||
/// The description of the error.
|
||||
public var errorDescription: String? {
|
||||
@inlinable public var errorDescription: String? {
|
||||
SecCopyErrorMessageString(code.rawValue, nil) as? String
|
||||
}
|
||||
|
||||
@@ -21,4 +21,10 @@ public struct SecError: Error, Hashable, Sendable {
|
||||
init(_ code: Code) {
|
||||
self.code = code
|
||||
}
|
||||
|
||||
/// Create the error.
|
||||
/// - Parameter status: The raw status code.
|
||||
init(_ status: OSStatus) {
|
||||
self.init(Code(rawValue: status))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
//
|
||||
// Keychain.swift
|
||||
// Keychain
|
||||
//
|
||||
// Created by Bram Kolkman on 20/02/2026.
|
||||
//
|
||||
115
Keychain/Sources/Keychain/SecItem.swift
Normal file
115
Keychain/Sources/Keychain/SecItem.swift
Normal file
@@ -0,0 +1,115 @@
|
||||
//
|
||||
// SecItem.swift
|
||||
// Keychain
|
||||
//
|
||||
// Created by Bram Kolkman on 23/02/2026.
|
||||
//
|
||||
|
||||
import Security
|
||||
|
||||
public enum SecItem {
|
||||
/// Adds an item to the keychain.
|
||||
///
|
||||
/// Use this function to store credentials, keys, certificates, and other secure data in the keychain.
|
||||
/// The keychain automatically encrypts the data and manages access control.
|
||||
///
|
||||
/// - Parameter attributes: A dictionary containing the attributes of the item to add. At minimum,
|
||||
/// include `kSecClass` to specify the item class and `kSecValueData` or `kSecValueRef` for the item's value.
|
||||
/// Additional attributes control access, persistence, and synchronization behavior.
|
||||
///
|
||||
/// - Returns: If you include the `kSecReturnAttributes`, `kSecReturnData`, `kSecReturnRef`, or
|
||||
/// `kSecReturnPersistentRef` key with a value of `true` in the attributes dictionary, this function
|
||||
/// returns the requested data. Otherwise, it returns `nil`.
|
||||
///
|
||||
/// - Throws: A `SecError` if the item could not be added. Common errors include duplicate items
|
||||
/// (`errSecDuplicateItem`) or invalid parameters (`errSecParam`).
|
||||
@discardableResult
|
||||
public static func add(_ attributes: [CFString: Any]) throws -> CFTypeRef? {
|
||||
var result: CFTypeRef?
|
||||
let status = SecItemAdd(attributes as CFDictionary, &result)
|
||||
|
||||
switch status {
|
||||
case errSecSuccess:
|
||||
return result
|
||||
default:
|
||||
throw SecError(status)
|
||||
}
|
||||
}
|
||||
|
||||
/// Searches for and retrieves items from the keychain.
|
||||
///
|
||||
/// Use this function to find keychain items that match specified search criteria. You can retrieve
|
||||
/// the item's data, attributes, or a persistent reference that you can use for later access.
|
||||
///
|
||||
/// - Parameter query: A dictionary containing the search criteria. At minimum, include `kSecClass`
|
||||
/// to specify the item class. Add search attributes like `kSecAttrAccount` or `kSecAttrService`
|
||||
/// to narrow results. Include return type keys (`kSecReturnData`, `kSecReturnAttributes`,
|
||||
/// `kSecReturnRef`, or `kSecReturnPersistentRef`) to specify what data to return.
|
||||
///
|
||||
/// - Returns: The requested keychain item data, attributes, or reference as specified by the return
|
||||
/// type keys in the query. Returns `nil` if no matching item is found (`errSecItemNotFound`).
|
||||
///
|
||||
/// - Throws: A `SecError` if the search fails for reasons other than the item not being found.
|
||||
/// Common errors include invalid parameters (`errSecParam`) or user interaction cancelled
|
||||
/// (`errSecUserCanceled`).
|
||||
public static func copy(matching query: [CFString: Any]) throws (SecError) -> CFTypeRef? {
|
||||
var result: CFTypeRef?
|
||||
let status = SecItemCopyMatching(query as CFDictionary, &result)
|
||||
|
||||
switch status {
|
||||
case errSecSuccess:
|
||||
return result
|
||||
case errSecItemNotFound:
|
||||
return nil
|
||||
default:
|
||||
throw SecError(status)
|
||||
}
|
||||
}
|
||||
|
||||
/// Modifies items in the keychain that match a search query.
|
||||
///
|
||||
/// Use this function to change the attributes or data of existing keychain items. The function
|
||||
/// finds items matching the search criteria and applies the specified updates to them.
|
||||
///
|
||||
/// - Parameter query: A dictionary containing the search criteria for items to update. At minimum,
|
||||
/// include `kSecClass` to specify the item class. Add search attributes to identify specific items.
|
||||
/// Do not include return type keys in the query dictionary.
|
||||
///
|
||||
/// - Parameter updates: A dictionary containing the attributes to modify. Include only the attributes
|
||||
/// you want to change. You cannot modify the `kSecClass` attribute.
|
||||
///
|
||||
/// - Throws: A `SecError` if the update fails. Common errors include item not found (`errSecItemNotFound`),
|
||||
/// invalid parameters (`errSecParam`), or attempting to create a duplicate item.
|
||||
public static func update(matching query: [CFString: Any], with updates: [CFString: Any]) throws {
|
||||
let status = SecItemUpdate(query as CFDictionary, updates as CFDictionary)
|
||||
switch status {
|
||||
case errSecSuccess:
|
||||
break
|
||||
default:
|
||||
throw SecError(status)
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes items from the keychain that match a search query.
|
||||
///
|
||||
/// Use this function to delete keychain items that are no longer needed. The function finds all items
|
||||
/// matching the search criteria and removes them from the keychain. If no matching items exist,
|
||||
/// the function succeeds without error.
|
||||
///
|
||||
/// - Parameter query: A dictionary containing the search criteria for items to delete. At minimum,
|
||||
/// include `kSecClass` to specify the item class. Add search attributes to identify specific items.
|
||||
/// To delete all items of a class, specify only `kSecClass`.
|
||||
///
|
||||
/// - Throws: A `SecError` if the deletion fails for reasons other than the item not being found.
|
||||
/// Common errors include invalid parameters (`errSecParam`) or user interaction required
|
||||
/// (`errSecInteractionNotAllowed`).
|
||||
public static func delete(matching query: [CFString: Any]) throws {
|
||||
let status = SecItemDelete(query as CFDictionary)
|
||||
switch status {
|
||||
case errSecSuccess, errSecItemNotFound:
|
||||
break
|
||||
default:
|
||||
throw SecError(status)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user