mirror of
https://github.com/maxgoedjen/secretive.git
synced 2026-03-16 22:37:25 +01:00
Merge branch 'main' into sshcertcleanup_2
This commit is contained in:
@@ -12,7 +12,7 @@ public class Agent {
|
||||
private let writer = OpenSSHKeyWriter()
|
||||
private let requestTracer = SigningRequestTracer()
|
||||
private let certificateHandler = OpenSSHCertificateHandler()
|
||||
private let logger = Logger()
|
||||
private let logger = Logger(subsystem: "com.maxgoedjen.secretive.secretagent.agent", category: "")
|
||||
|
||||
/// Initializes an agent with a store list and a witness.
|
||||
/// - Parameters:
|
||||
@@ -53,6 +53,8 @@ extension Agent {
|
||||
}
|
||||
|
||||
func handle(requestType: SSHAgent.RequestType, data: Data, reader: FileHandleReader) -> Data {
|
||||
// Depending on the launch context (such as after macOS update), the agent may need to reload secrets before acting
|
||||
reloadSecretsIfNeccessary()
|
||||
var response = Data()
|
||||
do {
|
||||
switch requestType {
|
||||
@@ -106,7 +108,7 @@ extension Agent {
|
||||
keyData.append(writer.lengthAndData(of: curveData))
|
||||
|
||||
}
|
||||
logger.debug("Agent enumerated \(secrets.count) identities")
|
||||
logger.log("Agent enumerated \(secrets.count) identities")
|
||||
return countData + keyData
|
||||
}
|
||||
|
||||
@@ -202,6 +204,16 @@ extension Agent {
|
||||
|
||||
extension Agent {
|
||||
|
||||
/// Gives any store with no loaded secrets a chance to reload.
|
||||
func reloadSecretsIfNeccessary() {
|
||||
for store in storeList.stores {
|
||||
if store.secrets.isEmpty {
|
||||
logger.debug("Store \(store.name, privacy: .public) has no loaded secrets. Reloading.")
|
||||
store.reloadSecrets()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Finds a ``Secret`` matching a specified hash whos signature was requested.
|
||||
/// - Parameter hash: The hash to match against.
|
||||
/// - Returns: A ``Secret`` and the ``SecretStore`` containing it, if a match is found.
|
||||
|
||||
@@ -12,6 +12,7 @@ public class AnySecretStore: SecretStore {
|
||||
private let _sign: (Data, AnySecret, SigningRequestProvenance) throws -> Data
|
||||
private let _existingPersistedAuthenticationContext: (AnySecret) -> PersistedAuthenticationContext?
|
||||
private let _persistAuthentication: (AnySecret, TimeInterval) throws -> Void
|
||||
private let _reloadSecrets: () -> Void
|
||||
|
||||
private var sink: AnyCancellable?
|
||||
|
||||
@@ -24,6 +25,7 @@ public class AnySecretStore: SecretStore {
|
||||
_sign = { try secretStore.sign(data: $0, with: $1.base as! SecretStoreType.SecretType, for: $2) }
|
||||
_existingPersistedAuthenticationContext = { secretStore.existingPersistedAuthenticationContext(secret: $0.base as! SecretStoreType.SecretType) }
|
||||
_persistAuthentication = { try secretStore.persistAuthentication(secret: $0.base as! SecretStoreType.SecretType, forDuration: $1) }
|
||||
_reloadSecrets = { secretStore.reloadSecrets() }
|
||||
sink = secretStore.objectWillChange.sink { _ in
|
||||
self.objectWillChange.send()
|
||||
}
|
||||
@@ -57,6 +59,10 @@ public class AnySecretStore: SecretStore {
|
||||
try _persistAuthentication(secret, duration)
|
||||
}
|
||||
|
||||
public func reloadSecrets() {
|
||||
_reloadSecrets()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class AnySecretStoreModifiable: AnySecretStore, SecretStoreModifiable {
|
||||
|
||||
@@ -36,6 +36,9 @@ public protocol SecretStore: ObservableObject, Identifiable {
|
||||
/// - Note: This is used for temporarily unlocking access to a secret which would otherwise require authentication every single use. This is useful for situations where the user anticipates several rapid accesses to a authorization-guarded secret.
|
||||
func persistAuthentication(secret: SecretType, forDuration duration: TimeInterval) throws
|
||||
|
||||
/// Requests that the store reload secrets from any backing store, if neccessary.
|
||||
func reloadSecrets()
|
||||
|
||||
}
|
||||
|
||||
/// A SecretStore that the Secretive admin app can modify.
|
||||
|
||||
@@ -24,7 +24,7 @@ extension SecureEnclave {
|
||||
/// Initializes a Store.
|
||||
public init() {
|
||||
DistributedNotificationCenter.default().addObserver(forName: .secretStoreUpdated, object: nil, queue: .main) { _ in
|
||||
self.reloadSecrets(notifyAgent: false)
|
||||
self.reloadSecretsInternal(notifyAgent: false)
|
||||
}
|
||||
loadSecrets()
|
||||
}
|
||||
@@ -68,7 +68,7 @@ extension SecureEnclave {
|
||||
throw KeychainError(statusCode: nil)
|
||||
}
|
||||
try savePublicKey(publicKey, name: name)
|
||||
reloadSecrets()
|
||||
reloadSecretsInternal()
|
||||
}
|
||||
|
||||
public func delete(secret: Secret) throws {
|
||||
@@ -80,7 +80,7 @@ extension SecureEnclave {
|
||||
if status != errSecSuccess {
|
||||
throw KeychainError(statusCode: status)
|
||||
}
|
||||
reloadSecrets()
|
||||
reloadSecretsInternal()
|
||||
}
|
||||
|
||||
public func update(secret: Secret, name: String) throws {
|
||||
@@ -97,7 +97,7 @@ extension SecureEnclave {
|
||||
if status != errSecSuccess {
|
||||
throw KeychainError(statusCode: status)
|
||||
}
|
||||
reloadSecrets()
|
||||
reloadSecretsInternal()
|
||||
}
|
||||
|
||||
public func sign(data: Data, with secret: SecretType, for provenance: SigningRequestProvenance) throws -> Data {
|
||||
@@ -163,6 +163,10 @@ extension SecureEnclave {
|
||||
}
|
||||
}
|
||||
|
||||
public func reloadSecrets() {
|
||||
reloadSecretsInternal(notifyAgent: false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -171,12 +175,15 @@ extension SecureEnclave.Store {
|
||||
|
||||
/// Reloads all secrets from the store.
|
||||
/// - Parameter notifyAgent: A boolean indicating whether a distributed notification should be posted, notifying other processes (ie, the SecretAgent) to reload their stores as well.
|
||||
private func reloadSecrets(notifyAgent: Bool = true) {
|
||||
private func reloadSecretsInternal(notifyAgent: Bool = true) {
|
||||
let before = secrets
|
||||
secrets.removeAll()
|
||||
loadSecrets()
|
||||
NotificationCenter.default.post(name: .secretStoreReloaded, object: self)
|
||||
if notifyAgent {
|
||||
DistributedNotificationCenter.default().postNotificationName(.secretStoreUpdated, object: nil, deliverImmediately: true)
|
||||
if secrets != before {
|
||||
NotificationCenter.default.post(name: .secretStoreReloaded, object: self)
|
||||
if notifyAgent {
|
||||
DistributedNotificationCenter.default().postNotificationName(.secretStoreUpdated, object: nil, deliverImmediately: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,19 @@ extension SmartCard {
|
||||
public func persistAuthentication(secret: SmartCard.Secret, forDuration: TimeInterval) throws {
|
||||
}
|
||||
|
||||
/// Reloads all secrets from the store.
|
||||
public func reloadSecrets() {
|
||||
DispatchQueue.main.async {
|
||||
self.isAvailable = self.tokenID != nil
|
||||
let before = self.secrets
|
||||
self.secrets.removeAll()
|
||||
self.loadSecrets()
|
||||
if self.secrets != before {
|
||||
NotificationCenter.default.post(name: .secretStoreReloaded, object: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -102,15 +115,6 @@ extension SmartCard.Store {
|
||||
reloadSecrets()
|
||||
}
|
||||
|
||||
/// Reloads all secrets from the store.
|
||||
private func reloadSecrets() {
|
||||
DispatchQueue.main.async {
|
||||
self.isAvailable = self.tokenID != nil
|
||||
self.secrets.removeAll()
|
||||
self.loadSecrets()
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads all secrets from the store.
|
||||
private func loadSecrets() {
|
||||
guard let tokenID = tokenID else { return }
|
||||
|
||||
@@ -78,6 +78,9 @@ extension Stub {
|
||||
public func persistAuthentication(secret: Stub.Secret, forDuration duration: TimeInterval) throws {
|
||||
}
|
||||
|
||||
public func reloadSecrets() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user