Compare commits

...

8 Commits

Author SHA1 Message Date
Max Goedjen
abf5c26d58 Update LOCALIZING.md
Added a section on handling updates for translations.
2025-09-01 18:54:16 -07:00
Max Goedjen
6dc93806a8 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.
2025-09-02 01:46:06 +00:00
Max Goedjen
99a6d48e53 Specify private key usage explicitly (#652) 2025-09-01 02:41:47 +00:00
Max Goedjen
935ac32ea2 Factor out comment writer. (#651) 2025-08-31 23:07:35 +00:00
Max Goedjen
a0a632f245 Save nil if empty string. (#650) 2025-08-31 23:03:59 +00:00
Max Goedjen
51fed9e593 Fix potential timing bug (#649) 2025-08-31 14:22:08 -07:00
Max Goedjen
f652d1d961 Return name as identities comment. (#647) 2025-08-31 20:50:16 +00:00
Max Goedjen
8aacd428b1 Fix deleting key attribution (#648) 2025-08-30 22:41:15 +00:00
8 changed files with 29 additions and 22 deletions

View File

@@ -18,7 +18,7 @@ Open [Sources/Secretive.xcodeproj](Sources/Secretive.xcodeproj) in Xcode.
### Translate
Navigate to [Secretive/Localizable](Sources/Secretive/Localizable.xcstrings).
Navigate to [Sources/Packages/Localizable.xcstrings](Sources/Packages/Localizable.xcstrings).
<img src="/.github/readme/localize_sidebar.png" alt="Screenshot of Xcode navigating to the Localizable file" width="300">
@@ -32,6 +32,12 @@ Start translating! You'll see a list of english phrases, and a space to add a tr
Push your changes and open a pull request.
### Handling Updates
When your translation is merged, I'll invite you to the [secretive-localizers](https://github.com/secretive-localizers) group. I'll tag this group anytime there's a new set of strings, in the hopes that you'll update the translation. If you don't want to be notified, feel free to decline the invitation or leave the organization at any time.
### Questions
Please open an issue if you have a question about translating the app. I'm more than happy to clarify any terms that are ambiguous or confusing. Thanks for contributing!

View File

@@ -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)

View File

@@ -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)

View File

@@ -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(publicKeyWriter.comment(secret: secret).lengthAndData)
count += 1
if let (certificateData, name) = try? await certificateHandler.keyBlobAndName(for: secret) {

View File

@@ -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.

View File

@@ -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<SecretType: Secret>(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<SecretType: Secret>(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 {

View File

@@ -112,7 +112,7 @@ extension SecureEnclave {
var accessError: SecurityError?
let flags: SecAccessControlCreateFlags = switch attributes.authentication {
case .notRequired:
[]
[.privateKeyUsage]
case .presenceRequired:
[.userPresence, .privateKeyUsage]
case .biometryCurrent:

View File

@@ -53,9 +53,7 @@ struct EditSecretView<StoreType: SecretStoreModifiable>: View {
func rename() {
var attributes = secret.attributes
if !publicKeyAttribution.isEmpty {
attributes.publicKeyAttribution = publicKeyAttribution
}
attributes.publicKeyAttribution = publicKeyAttribution.isEmpty ? nil : publicKeyAttribution
Task {
do {
try await store.update(secret: secret, name: name, attributes: attributes)