From 4171a7264de37c367849b557cc4a5d85b859928e Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 18 Dec 2022 17:01:07 -0800 Subject: [PATCH] . --- .../Sources/SecretAgentKit/Agent.swift | 20 +++--------------- .../SecretAgentKit/SSHAgentProtocol.swift | 3 --- .../OpenSSH/OpenSSHCertificateHandler.swift | 21 ++++++++----------- .../PublicKeyStandinFileController.swift | 12 +++++++++++ .../Sources/SecretKit/SecretStoreList.swift | 4 ++++ Sources/SecretAgent/AppDelegate.swift | 4 ++-- 6 files changed, 30 insertions(+), 34 deletions(-) diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index f0978f8..84cd238 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -22,7 +22,7 @@ public class Agent { logger.debug("Agent is running") self.storeList = storeList self.witness = witness - certificateHandler.reloadCertificates(for: storeList.stores.flatMap(\.secrets)) + certificateHandler.reloadCertificates(for: storeList.allSecrets) } } @@ -67,9 +67,6 @@ extension Agent { response.append(SSHAgent.ResponseType.agentSignResponse.data) response.append(try sign(data: data, provenance: provenance)) logger.debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)") - case .addIdentity: - try addIdentity(data: data) - response.append(SSHAgent.ResponseType.agentSuccess.data) } } catch { response.removeAll() @@ -87,7 +84,8 @@ extension Agent { /// Lists the identities available for signing operations /// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations. func identities() -> Data { - let secrets = storeList.stores.flatMap(\.secrets) + let secrets = storeList.allSecrets + certificateHandler.reloadCertificates(for: secrets) var count = UInt32(secrets.count).bigEndian let countData = Data(bytes: &count, count: UInt32.bitWidth/8) var keyData = Data() @@ -188,18 +186,6 @@ extension Agent { return signedData } - /// Stub for the ssh-add operation, which reloads from the store and reloads any OpenSSH certificate public keys. - /// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations. - func addIdentity(data: Data) throws { - // FIXME: This -// guard isCertificate else throw { AgentError.notOpenSSHCertificate } - // FIXME: READ REAL SECRET HASH -// let secret = secret(matching: hash) - let secret = AnySecret(storeList.stores.first!.secrets.first!) - try certificateHandler.copyCertificate(data: data, for: secret) - print(data) - } - } extension Agent { diff --git a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift b/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift index 4839bba..4c45616 100644 --- a/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift +++ b/Sources/Packages/Sources/SecretAgentKit/SSHAgentProtocol.swift @@ -10,7 +10,6 @@ extension SSHAgent { case requestIdentities = 11 case signRequest = 13 - case addIdentity = 17 public var debugDescription: String { switch self { @@ -18,8 +17,6 @@ extension SSHAgent { return "RequestIdentities" case .signRequest: return "SignRequest" - case .addIdentity: - return "AddIdentity" } } } diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift index 22fb72a..435c310 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHCertificateHandler.swift @@ -16,23 +16,20 @@ public class OpenSSHCertificateHandler { /// Reloads any certificates in the PublicKeys folder. /// - Parameter secrets: the secrets to look up corresponding certificates for. public func reloadCertificates(for secrets: [AnySecret]) { + guard publicKeyFileStoreController.hasAnyCertificates else { + logger.log("No certificates, short circuiting") + return + } keyBlobsAndNames = secrets.reduce(into: [:]) { partialResult, next in partialResult[next] = try? loadKeyblobAndName(for: next) } } - /// Copies a certificate to the PublicKeys folder, if it's not already tehre. - /// - Parameter url: the URL of the certificate to copy. - public func copyCertificate(data: Data, for secret: AnySecret) throws { - try data.write(to: URL(fileURLWithPath: publicKeyFileStoreController.sshCertificatePath(for: secret)) -) - } - /// Whether or not the certificate handler has a certifiicate associated with a given secret. /// - Parameter secret: The secret to check for a certificate. /// - Returns: A boolean describing whether or not the certificate handler has a certifiicate associated with a given secret - public func hasCertificate(for secret: AnySecret) -> Bool { - keyBlobsAndNames[secret] != nil + public func hasCertificate(for secret: SecretType) -> Bool { + keyBlobsAndNames[AnySecret(secret)] != nil } @@ -63,14 +60,14 @@ public class OpenSSHCertificateHandler { /// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret`` /// - Parameter secret: The secret to search for a certificate with /// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively. - public func keyBlobAndName(for secret: AnySecret) throws -> (Data, Data)? { - keyBlobsAndNames[secret] + public func keyBlobAndName(for secret: SecretType) throws -> (Data, Data)? { + keyBlobsAndNames[AnySecret(secret)] } /// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret`` /// - Parameter secret: The secret to search for a certificate with /// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively. - private func loadKeyblobAndName(for secret: AnySecret) throws -> (Data, Data)? { + private func loadKeyblobAndName(for secret: SecretType) throws -> (Data, Data)? { let certificatePath = publicKeyFileStoreController.sshCertificatePath(for: secret) guard FileManager.default.fileExists(atPath: certificatePath) else { return nil diff --git a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift index cbf40a6..e30627a 100644 --- a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift +++ b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift @@ -45,6 +45,18 @@ public class PublicKeyFileStoreController { return directory.appending("/").appending("\(minimalHex).pub") } + /// Short-circuit check to ship enumerating a bunch of paths if there's nothing in the cert directory. + public var hasAnyCertificates: Bool { + do { + return try FileManager.default + .contentsOfDirectory(atPath: directory) + .filter { $0.hasSuffix("-cert.pub") } + .isEmpty == false + } catch { + return false + } + } + /// The path for a Secret's SSH Certificate public key. /// - Parameter secret: The Secret to return the path for. /// - Returns: The path to the SSH Certificate public key. diff --git a/Sources/Packages/Sources/SecretKit/SecretStoreList.swift b/Sources/Packages/Sources/SecretKit/SecretStoreList.swift index 57fed98..fbde248 100644 --- a/Sources/Packages/Sources/SecretKit/SecretStoreList.swift +++ b/Sources/Packages/Sources/SecretKit/SecretStoreList.swift @@ -31,6 +31,10 @@ public class SecretStoreList: ObservableObject { stores.reduce(false, { $0 || $1.isAvailable }) } + public var allSecrets: [AnySecret] { + stores.flatMap(\.secrets) + } + } extension SecretStoreList { diff --git a/Sources/SecretAgent/AppDelegate.swift b/Sources/SecretAgent/AppDelegate.swift index 45f176c..e21587f 100644 --- a/Sources/SecretAgent/AppDelegate.swift +++ b/Sources/SecretAgent/AppDelegate.swift @@ -34,9 +34,9 @@ class AppDelegate: NSObject, NSApplicationDelegate { self.socketController.handler = self.agent.handle(reader:writer:) } NotificationCenter.default.addObserver(forName: .secretStoreReloaded, object: nil, queue: .main) { [self] _ in - try? publicKeyFileStoreController.generatePublicKeys(for: storeList.stores.flatMap({ $0.secrets }), clear: true) + try? publicKeyFileStoreController.generatePublicKeys(for: storeList.allSecrets, clear: true) } - try? publicKeyFileStoreController.generatePublicKeys(for: storeList.stores.flatMap({ $0.secrets }), clear: true) + try? publicKeyFileStoreController.generatePublicKeys(for: storeList.allSecrets, clear: true) notifier.prompt() updateSink = updater.$update.sink { update in guard let update = update else { return }