mirror of
https://github.com/maxgoedjen/secretive.git
synced 2025-04-10 17:47:19 +00:00
.
This commit is contained in:
parent
eaee8aaaa2
commit
4171a7264d
@ -22,7 +22,7 @@ public class Agent {
|
|||||||
logger.debug("Agent is running")
|
logger.debug("Agent is running")
|
||||||
self.storeList = storeList
|
self.storeList = storeList
|
||||||
self.witness = witness
|
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(SSHAgent.ResponseType.agentSignResponse.data)
|
||||||
response.append(try sign(data: data, provenance: provenance))
|
response.append(try sign(data: data, provenance: provenance))
|
||||||
logger.debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)")
|
logger.debug("Agent returned \(SSHAgent.ResponseType.agentSignResponse.debugDescription)")
|
||||||
case .addIdentity:
|
|
||||||
try addIdentity(data: data)
|
|
||||||
response.append(SSHAgent.ResponseType.agentSuccess.data)
|
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
response.removeAll()
|
response.removeAll()
|
||||||
@ -87,7 +84,8 @@ extension Agent {
|
|||||||
/// Lists the identities available for signing operations
|
/// Lists the identities available for signing operations
|
||||||
/// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations.
|
/// - Returns: An OpenSSH formatted Data payload listing the identities available for signing operations.
|
||||||
func identities() -> Data {
|
func identities() -> Data {
|
||||||
let secrets = storeList.stores.flatMap(\.secrets)
|
let secrets = storeList.allSecrets
|
||||||
|
certificateHandler.reloadCertificates(for: secrets)
|
||||||
var count = UInt32(secrets.count).bigEndian
|
var count = UInt32(secrets.count).bigEndian
|
||||||
let countData = Data(bytes: &count, count: UInt32.bitWidth/8)
|
let countData = Data(bytes: &count, count: UInt32.bitWidth/8)
|
||||||
var keyData = Data()
|
var keyData = Data()
|
||||||
@ -188,18 +186,6 @@ extension Agent {
|
|||||||
return signedData
|
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 {
|
extension Agent {
|
||||||
|
@ -10,7 +10,6 @@ extension SSHAgent {
|
|||||||
|
|
||||||
case requestIdentities = 11
|
case requestIdentities = 11
|
||||||
case signRequest = 13
|
case signRequest = 13
|
||||||
case addIdentity = 17
|
|
||||||
|
|
||||||
public var debugDescription: String {
|
public var debugDescription: String {
|
||||||
switch self {
|
switch self {
|
||||||
@ -18,8 +17,6 @@ extension SSHAgent {
|
|||||||
return "RequestIdentities"
|
return "RequestIdentities"
|
||||||
case .signRequest:
|
case .signRequest:
|
||||||
return "SignRequest"
|
return "SignRequest"
|
||||||
case .addIdentity:
|
|
||||||
return "AddIdentity"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,23 +16,20 @@ public class OpenSSHCertificateHandler {
|
|||||||
/// Reloads any certificates in the PublicKeys folder.
|
/// Reloads any certificates in the PublicKeys folder.
|
||||||
/// - Parameter secrets: the secrets to look up corresponding certificates for.
|
/// - Parameter secrets: the secrets to look up corresponding certificates for.
|
||||||
public func reloadCertificates(for secrets: [AnySecret]) {
|
public func reloadCertificates(for secrets: [AnySecret]) {
|
||||||
|
guard publicKeyFileStoreController.hasAnyCertificates else {
|
||||||
|
logger.log("No certificates, short circuiting")
|
||||||
|
return
|
||||||
|
}
|
||||||
keyBlobsAndNames = secrets.reduce(into: [:]) { partialResult, next in
|
keyBlobsAndNames = secrets.reduce(into: [:]) { partialResult, next in
|
||||||
partialResult[next] = try? loadKeyblobAndName(for: next)
|
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.
|
/// Whether or not the certificate handler has a certifiicate associated with a given secret.
|
||||||
/// - Parameter secret: The secret to check for a certificate.
|
/// - 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
|
/// - 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 {
|
public func hasCertificate<SecretType: Secret>(for secret: SecretType) -> Bool {
|
||||||
keyBlobsAndNames[secret] != nil
|
keyBlobsAndNames[AnySecret(secret)] != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -63,14 +60,14 @@ public class OpenSSHCertificateHandler {
|
|||||||
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
||||||
/// - Parameter secret: The secret to search for a certificate with
|
/// - Parameter secret: The secret to search for a certificate with
|
||||||
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
|
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
|
||||||
public func keyBlobAndName(for secret: AnySecret) throws -> (Data, Data)? {
|
public func keyBlobAndName<SecretType: Secret>(for secret: SecretType) throws -> (Data, Data)? {
|
||||||
keyBlobsAndNames[secret]
|
keyBlobsAndNames[AnySecret(secret)]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
/// Attempts to find an OpenSSH Certificate that corresponds to a ``Secret``
|
||||||
/// - Parameter secret: The secret to search for a certificate with
|
/// - Parameter secret: The secret to search for a certificate with
|
||||||
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
|
/// - Returns: A (``Data``, ``Data``) tuple containing the certificate and certificate name, respectively.
|
||||||
private func loadKeyblobAndName(for secret: AnySecret) throws -> (Data, Data)? {
|
private func loadKeyblobAndName<SecretType: Secret>(for secret: SecretType) throws -> (Data, Data)? {
|
||||||
let certificatePath = publicKeyFileStoreController.sshCertificatePath(for: secret)
|
let certificatePath = publicKeyFileStoreController.sshCertificatePath(for: secret)
|
||||||
guard FileManager.default.fileExists(atPath: certificatePath) else {
|
guard FileManager.default.fileExists(atPath: certificatePath) else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -45,6 +45,18 @@ public class PublicKeyFileStoreController {
|
|||||||
return directory.appending("/").appending("\(minimalHex).pub")
|
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.
|
/// The path for a Secret's SSH Certificate public key.
|
||||||
/// - Parameter secret: The Secret to return the path for.
|
/// - Parameter secret: The Secret to return the path for.
|
||||||
/// - Returns: The path to the SSH Certificate public key.
|
/// - Returns: The path to the SSH Certificate public key.
|
||||||
|
@ -31,6 +31,10 @@ public class SecretStoreList: ObservableObject {
|
|||||||
stores.reduce(false, { $0 || $1.isAvailable })
|
stores.reduce(false, { $0 || $1.isAvailable })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public var allSecrets: [AnySecret] {
|
||||||
|
stores.flatMap(\.secrets)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SecretStoreList {
|
extension SecretStoreList {
|
||||||
|
@ -34,9 +34,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|||||||
self.socketController.handler = self.agent.handle(reader:writer:)
|
self.socketController.handler = self.agent.handle(reader:writer:)
|
||||||
}
|
}
|
||||||
NotificationCenter.default.addObserver(forName: .secretStoreReloaded, object: nil, queue: .main) { [self] _ in
|
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()
|
notifier.prompt()
|
||||||
updateSink = updater.$update.sink { update in
|
updateSink = updater.$update.sink { update in
|
||||||
guard let update = update else { return }
|
guard let update = update else { return }
|
||||||
|
Loading…
Reference in New Issue
Block a user