Files
Termind/Frameworks/TermindApplication/SecretStoring.swift
T

93 lines
3.3 KiB
Swift

import Foundation
import TermindDomain
public nonisolated struct SSHPrivateKeySecret: Codable, Hashable, Sendable {
public var privateKey: String
public init(privateKey: String) {
self.privateKey = privateKey
}
}
public nonisolated protocol SSHRuntimeSecretResolving: Sendable {
func sshSecret(for account: String, storage: PasswordStorage) throws -> SSHSecret?
func sshKeyCredential(
for account: String, storage: KeyStorage
) throws -> SSHResolvedKeyCredential?
}
public nonisolated protocol SecretStoring: SSHRuntimeSecretResolving {
func string(for account: String, storage: PasswordStorage) throws -> String?
func containsString(for account: String, storage: PasswordStorage) throws -> Bool
func setString(_ value: String?, for account: String, storage: PasswordStorage) throws
func keyCredential(
for account: String, storage: KeyStorage
) throws -> StoredSSHKeyCredential?
func containsKeyCredential(for account: String, storage: KeyStorage) throws -> Bool
func setKeyCredential(
_ value: StoredSSHKeyCredential?, for account: String, storage: KeyStorage
) throws
func removePassword(_ account: String, storage: PasswordStorage) throws
func removeKeyCredential(_ account: String, storage: KeyStorage) throws
}
nonisolated extension SecretStoring {
public func containsString(for account: String, storage: PasswordStorage) throws -> Bool {
try string(for: account, storage: storage) != nil
}
public func containsKeyCredential(for account: String, storage: KeyStorage) throws -> Bool {
try keyCredential(for: account, storage: storage) != nil
}
public func sshSecret(for account: String, storage: PasswordStorage) throws -> SSHSecret? {
try string(for: account, storage: storage).map(SSHSecret.init)
}
public func sshKeyCredential(
for account: String, storage: KeyStorage
) throws -> SSHResolvedKeyCredential? {
switch try keyCredential(for: account, storage: storage) {
case .software(let secret): .software(SSHSecret(secret.privateKey))
case .secureEnclave(let credential): .secureEnclave(credential)
case nil: nil
}
}
}
public nonisolated final class InMemorySecretStore: SecretStoring, @unchecked Sendable {
public init() {}
private let lock = NSLock()
private var strings: [String: String] = [:]
private var keys: [String: StoredSSHKeyCredential] = [:]
public func string(for account: String, storage: PasswordStorage) throws -> String? {
lock.withLock { strings[account] }
}
public func setString(_ value: String?, for account: String, storage: PasswordStorage) throws {
lock.withLock { strings[account] = value }
}
public func keyCredential(
for account: String, storage: KeyStorage
) throws -> StoredSSHKeyCredential? {
lock.withLock { keys[account] }
}
public func setKeyCredential(
_ value: StoredSSHKeyCredential?, for account: String, storage: KeyStorage
) throws {
lock.withLock { keys[account] = value }
}
public func removePassword(_ account: String, storage: PasswordStorage) throws {
lock.withLock { strings[account] = nil }
}
public func removeKeyCredential(_ account: String, storage: KeyStorage) throws {
lock.withLock { keys[account] = nil }
}
}