Docs (#310)
This commit is contained in:
parent
fb6cebe92f
commit
eb282b4116
|
@ -0,0 +1,3 @@
|
||||||
|
# ````SmartCardSecretKit````
|
||||||
|
|
||||||
|
SmartCardSecretKit contains implementations of SecretKit protocols backed by a Smart Card.
|
|
@ -1 +1,2 @@
|
||||||
|
/// Namespace for the Smart Card implementations.
|
||||||
public enum SmartCard {}
|
public enum SmartCard {}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import SecretKit
|
||||||
|
|
||||||
extension SmartCard {
|
extension SmartCard {
|
||||||
|
|
||||||
|
/// An implementation of Secret backed by a Smart Card.
|
||||||
public struct Secret: SecretKit.Secret {
|
public struct Secret: SecretKit.Secret {
|
||||||
|
|
||||||
public let id: Data
|
public let id: Data
|
||||||
|
|
|
@ -8,6 +8,7 @@ import SecretKit
|
||||||
// ie, each token has its own Store.
|
// ie, each token has its own Store.
|
||||||
extension SmartCard {
|
extension SmartCard {
|
||||||
|
|
||||||
|
/// An implementation of Store backed by a Smart Card.
|
||||||
public class Store: SecretStore {
|
public class Store: SecretStore {
|
||||||
|
|
||||||
@Published public var isAvailable: Bool = false
|
@Published public var isAvailable: Bool = false
|
||||||
|
@ -17,6 +18,7 @@ extension SmartCard {
|
||||||
private let watcher = TKTokenWatcher()
|
private let watcher = TKTokenWatcher()
|
||||||
private var tokenID: String?
|
private var tokenID: String?
|
||||||
|
|
||||||
|
/// Initializes a Store.
|
||||||
public init() {
|
public init() {
|
||||||
tokenID = watcher.nonSecureEnclaveTokens.first
|
tokenID = watcher.nonSecureEnclaveTokens.first
|
||||||
watcher.setInsertionHandler { string in
|
watcher.setInsertionHandler { string in
|
||||||
|
@ -56,7 +58,7 @@ extension SmartCard {
|
||||||
kSecAttrTokenID: tokenID,
|
kSecAttrTokenID: tokenID,
|
||||||
kSecUseAuthenticationContext: context,
|
kSecUseAuthenticationContext: context,
|
||||||
kSecReturnRef: true
|
kSecReturnRef: true
|
||||||
] as CFDictionary
|
] as CFDictionary
|
||||||
var untyped: CFTypeRef?
|
var untyped: CFTypeRef?
|
||||||
let status = SecItemCopyMatching(attributes, &untyped)
|
let status = SecItemCopyMatching(attributes, &untyped)
|
||||||
if status != errSecSuccess {
|
if status != errSecSuccess {
|
||||||
|
@ -91,11 +93,14 @@ extension SmartCard {
|
||||||
|
|
||||||
extension SmartCard.Store {
|
extension SmartCard.Store {
|
||||||
|
|
||||||
|
/// Resets the token ID and reloads secrets.
|
||||||
|
/// - Parameter tokenID: The ID of the token that was removed.
|
||||||
private func smartcardRemoved(for tokenID: String? = nil) {
|
private func smartcardRemoved(for tokenID: String? = nil) {
|
||||||
self.tokenID = nil
|
self.tokenID = nil
|
||||||
reloadSecrets()
|
reloadSecrets()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reloads all secrets from the store.
|
||||||
private func reloadSecrets() {
|
private func reloadSecrets() {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.isAvailable = self.tokenID != nil
|
self.isAvailable = self.tokenID != nil
|
||||||
|
@ -104,6 +109,7 @@ extension SmartCard.Store {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Loads all secrets from the store.
|
||||||
private func loadSecrets() {
|
private func loadSecrets() {
|
||||||
guard let tokenID = tokenID else { return }
|
guard let tokenID = tokenID else { return }
|
||||||
|
|
||||||
|
@ -131,7 +137,7 @@ extension SmartCard.Store {
|
||||||
kSecReturnRef: true,
|
kSecReturnRef: true,
|
||||||
kSecMatchLimit: kSecMatchLimitAll,
|
kSecMatchLimit: kSecMatchLimitAll,
|
||||||
kSecReturnAttributes: true
|
kSecReturnAttributes: true
|
||||||
] as CFDictionary
|
] as CFDictionary
|
||||||
var untyped: CFTypeRef?
|
var untyped: CFTypeRef?
|
||||||
SecItemCopyMatching(attributes, &untyped)
|
SecItemCopyMatching(attributes, &untyped)
|
||||||
guard let typed = untyped as? [[CFString: Any]] else { return }
|
guard let typed = untyped as? [[CFString: Any]] else { return }
|
||||||
|
@ -153,6 +159,7 @@ extension SmartCard.Store {
|
||||||
|
|
||||||
extension TKTokenWatcher {
|
extension TKTokenWatcher {
|
||||||
|
|
||||||
|
/// All available tokens, excluding the Secure Enclave.
|
||||||
fileprivate var nonSecureEnclaveTokens: [String] {
|
fileprivate var nonSecureEnclaveTokens: [String] {
|
||||||
tokenIDs.filter { !$0.contains("setoken") }
|
tokenIDs.filter { !$0.contains("setoken") }
|
||||||
}
|
}
|
||||||
|
@ -161,11 +168,15 @@ extension TKTokenWatcher {
|
||||||
|
|
||||||
extension SmartCard {
|
extension SmartCard {
|
||||||
|
|
||||||
|
/// A wrapper around an error code reported by a Keychain API.
|
||||||
public struct KeychainError: Error {
|
public struct KeychainError: Error {
|
||||||
|
/// The status code involved.
|
||||||
public let statusCode: OSStatus
|
public let statusCode: OSStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A signing-related error.
|
||||||
public struct SigningError: Error {
|
public struct SigningError: Error {
|
||||||
|
/// The underlying error reported by the API, if one was returned.
|
||||||
public let error: SecurityError?
|
public let error: SecurityError?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue