From 8aacd428b1e2364ec5e962cc85d5ec9e28bb7b69 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sat, 30 Aug 2025 15:41:15 -0700 Subject: [PATCH 1/8] Fix deleting key attribution (#648) --- Sources/Secretive/Views/EditSecretView.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Sources/Secretive/Views/EditSecretView.swift b/Sources/Secretive/Views/EditSecretView.swift index 606b130..4690dde 100644 --- a/Sources/Secretive/Views/EditSecretView.swift +++ b/Sources/Secretive/Views/EditSecretView.swift @@ -53,9 +53,7 @@ struct EditSecretView: View { func rename() { var attributes = secret.attributes - if !publicKeyAttribution.isEmpty { - attributes.publicKeyAttribution = publicKeyAttribution - } + attributes.publicKeyAttribution = publicKeyAttribution Task { do { try await store.update(secret: secret, name: name, attributes: attributes) From f652d1d96191019667c151a0019a7f8cc74326cd Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 31 Aug 2025 13:50:16 -0700 Subject: [PATCH 2/8] Return name as identities comment. (#647) --- Sources/Packages/Sources/SecretAgentKit/Agent.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index cd5bfa1..d00d963 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -89,9 +89,8 @@ extension Agent { for secret in secrets { let keyBlob = publicKeyWriter.data(secret: secret) - let curveData = publicKeyWriter.openSSHIdentifier(for: secret.keyType) keyData.append(keyBlob.lengthAndData) - keyData.append(curveData.lengthAndData) + keyData.append(secret.name.lengthAndData) count += 1 if let (certificateData, name) = try? await certificateHandler.keyBlobAndName(for: secret) { From 51fed9e59356f937110e17f2c3b4b06555e65e3d Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 31 Aug 2025 14:22:08 -0700 Subject: [PATCH 3/8] Fix potential timing bug (#649) --- .../Packages/Sources/SecretAgentKit/SocketController.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/Packages/Sources/SecretAgentKit/SocketController.swift b/Sources/Packages/Sources/SecretAgentKit/SocketController.swift index 0f592a0..19b040a 100644 --- a/Sources/Packages/Sources/SecretAgentKit/SocketController.swift +++ b/Sources/Packages/Sources/SecretAgentKit/SocketController.swift @@ -78,7 +78,6 @@ extension SocketController { provenance = SigningRequestTracer().provenance(from: fileHandle) (messages, messagesContinuation) = AsyncStream.makeStream() Task { [messagesContinuation, logger] in - await fileHandle.waitForDataInBackgroundAndNotifyOnMainActor() for await _ in NotificationCenter.default.notifications(named: .NSFileHandleDataAvailable, object: fileHandle) { let data = fileHandle.availableData guard !data.isEmpty else { @@ -91,6 +90,9 @@ extension SocketController { logger.debug("Socket controller yielded data.") } } + Task { + await fileHandle.waitForDataInBackgroundAndNotifyOnMainActor() + } } /// Writes new data to the socket. From a0a632f245cf95b9f022c32cf8d29564e47c0d45 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 31 Aug 2025 16:03:59 -0700 Subject: [PATCH 4/8] Save nil if empty string. (#650) --- Sources/Secretive/Views/EditSecretView.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Secretive/Views/EditSecretView.swift b/Sources/Secretive/Views/EditSecretView.swift index 4690dde..cdc4114 100644 --- a/Sources/Secretive/Views/EditSecretView.swift +++ b/Sources/Secretive/Views/EditSecretView.swift @@ -53,7 +53,7 @@ struct EditSecretView: View { func rename() { var attributes = secret.attributes - attributes.publicKeyAttribution = publicKeyAttribution + attributes.publicKeyAttribution = publicKeyAttribution.isEmpty ? nil : publicKeyAttribution Task { do { try await store.update(secret: secret, name: name, attributes: attributes) From 935ac32ea20c0447edef37e7962d2308d45cb3b1 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 31 Aug 2025 16:07:35 -0700 Subject: [PATCH 5/8] Factor out comment writer. (#651) --- .../Sources/SecretAgentKit/Agent.swift | 2 +- .../OpenSSH/OpenSSHPublicKeyWriter.swift | 26 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index d00d963..8851127 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -90,7 +90,7 @@ extension Agent { for secret in secrets { let keyBlob = publicKeyWriter.data(secret: secret) keyData.append(keyBlob.lengthAndData) - keyData.append(secret.name.lengthAndData) + keyData.append(publicKeyWriter.comment(secret: secret).lengthAndData) count += 1 if let (certificateData, name) = try? await certificateHandler.keyBlobAndName(for: secret) { diff --git a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift index 2c7f446..99713e0 100644 --- a/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift +++ b/Sources/Packages/Sources/SecretKit/OpenSSH/OpenSSHPublicKeyWriter.swift @@ -31,18 +31,7 @@ public struct OpenSSHPublicKeyWriter: Sendable { /// Generates an OpenSSH string representation of the secret. /// - Returns: OpenSSH string representation of the secret. public func openSSHString(secret: SecretType) -> String { - let resolvedComment: String - if let comment = secret.publicKeyAttribution { - resolvedComment = comment - } else { - let dashedKeyName = secret.name.replacingOccurrences(of: " ", with: "-") - let dashedHostName = ["secretive", Host.current().localizedName, "local"] - .compactMap { $0 } - .joined(separator: ".") - .replacingOccurrences(of: " ", with: "-") - resolvedComment = "\(dashedKeyName)@\(dashedHostName)" - } - return [openSSHIdentifier(for: secret.keyType), data(secret: secret).base64EncodedString(), resolvedComment] + return [openSSHIdentifier(for: secret.keyType), data(secret: secret).base64EncodedString(), comment(secret: secret)] .compactMap { $0 } .joined(separator: " ") } @@ -65,6 +54,19 @@ public struct OpenSSHPublicKeyWriter: Sendable { .joined(separator: ":") } + public func comment(secret: SecretType) -> String { + if let comment = secret.publicKeyAttribution { + return comment + } else { + let dashedKeyName = secret.name.replacingOccurrences(of: " ", with: "-") + let dashedHostName = ["secretive", Host.current().localizedName, "local"] + .compactMap { $0 } + .joined(separator: ".") + .replacingOccurrences(of: " ", with: "-") + return "\(dashedKeyName)@\(dashedHostName)" + } + + } } extension OpenSSHPublicKeyWriter { From 99a6d48e535bd841d6dcb0fa44057a52fd3ac245 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Sun, 31 Aug 2025 19:41:47 -0700 Subject: [PATCH 6/8] Specify private key usage explicitly (#652) --- .../Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index c57b712..1953fa0 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -112,7 +112,7 @@ extension SecureEnclave { var accessError: SecurityError? let flags: SecAccessControlCreateFlags = switch attributes.authentication { case .notRequired: - [] + [.privateKeyUsage] case .presenceRequired: [.userPresence, .privateKeyUsage] case .biometryCurrent: From 6dc93806a80ad807dd715ab3d15a2639633cd619 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Mon, 1 Sep 2025 18:46:06 -0700 Subject: [PATCH 7/8] Enable GitHub private security issue reporting and update policies (#653) * Revise security vulnerability reporting process Updated security reporting instructions in README.md. * Change vulnerability reporting email to GitHub feature Updated the vulnerability reporting method to use GitHub's private reporting feature. --- README.md | 2 +- SECURITY.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 50d8cd1..66d2b04 100644 --- a/README.md +++ b/README.md @@ -61,4 +61,4 @@ Because secrets in the Secure Enclave are not exportable, they are not able to b ## Security -If you discover any vulnerabilities in this project, please notify [max.goedjen@gmail.com](mailto:max.goedjen@gmail.com) with the subject containing "SECRETIVE SECURITY." +Secretive's security policy is detailed in [SECURITY.md](SECURITY.md). To report security issues, please use [GitHub's private reporting feature.](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) diff --git a/SECURITY.md b/SECURITY.md index 94d1da3..63412c6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -24,4 +24,4 @@ The latest version on the [Releases page](https://github.com/maxgoedjen/secretiv ## Reporting a Vulnerability -If you discover any vulnerabilities in this project, please notify max.goedjen@gmail.com with the subject containing "SECRETIVE SECURITY." +To report security issues, please use [GitHub's private reporting feature.](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability) From ddcb2a36ec7728c6df6c19c4f148f38e5104b2ad Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Mon, 1 Sep 2025 20:09:32 -0700 Subject: [PATCH 8/8] Fixes to agent reloading. (#656) --- .../Sources/SecretKit/PublicKeyStandinFileController.swift | 3 ++- .../Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift index ada02d7..45bd222 100644 --- a/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift +++ b/Sources/Packages/Sources/SecretKit/PublicKeyStandinFileController.swift @@ -26,7 +26,8 @@ public final class PublicKeyFileStoreController: Sendable { let untracked = Set(fullPathContents) .subtracting(validPaths) for path in untracked { - try? FileManager.default.removeItem(at: URL(fileURLWithPath: path)) + // string instead of fileURLWithPath since we're already using fileURL format. + try? FileManager.default.removeItem(at: URL(string: path)!) } } try? FileManager.default.createDirectory(at: URL(fileURLWithPath: directory), withIntermediateDirectories: false, attributes: nil) diff --git a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift index 1953fa0..433759d 100644 --- a/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift +++ b/Sources/Packages/Sources/SecureEnclaveSecretKit/SecureEnclaveStore.swift @@ -26,7 +26,7 @@ extension SecureEnclave { for await note in DistributedNotificationCenter.default().notifications(named: .secretStoreUpdated) { guard Constants.notificationToken != (note.object as? String) else { // Don't reload if we're the ones triggering this by reloading. - return + continue } reloadSecrets() }