cmux/scripts/derive_sparkle_public_key.swift
Lawrence Chen 0340e794b8
Fix Sparkle auto-update: inject SUPublicEDKey into Info.plist via PlistBuddy (#15)
Root cause: INFOPLIST_KEY_ build setting prefix only works for Apple-recognized
keys (CF*, NS*, LS*), not custom keys like SUPublicEDKey. The key was never
being added to Info.plist, so generate_appcast silently skipped EdDSA signing
(no public key in app = nothing to match against).

Fix:
- Derive public key from private key at build time using CryptoKit
- Use PlistBuddy to inject SUPublicEDKey and SUFeedURL after build
- Add sign_update fallback in appcast script if generate_appcast skips signing
- Add base64 padding normalization for key handling
2026-02-05 19:57:01 -08:00

39 lines
1.2 KiB
Swift

#!/usr/bin/env swift
import CryptoKit
import Foundation
// Derives the Ed25519 public key from a Sparkle private key (base64-encoded).
// Supports both new format (32-byte seed) and old format (96-byte key+pub).
guard CommandLine.arguments.count > 1 else {
fputs("Usage: derive_sparkle_public_key.swift <base64-private-key>\n", stderr)
exit(1)
}
// Pad base64 string if needed (Sparkle keys may be stored without padding)
var b64 = CommandLine.arguments[1]
while b64.count % 4 != 0 {
b64 += "="
}
guard let data = Data(base64Encoded: b64) else {
fputs("Error: invalid base64 input\n", stderr)
exit(1)
}
if data.count == 32 {
// New format: 32-byte Ed25519 seed
do {
let privateKey = try Curve25519.Signing.PrivateKey(rawRepresentation: data)
print(privateKey.publicKey.rawRepresentation.base64EncodedString())
} catch {
fputs("Error deriving key: \(error)\n", stderr)
exit(1)
}
} else if data.count == 96 {
// Old format: 64-byte private key + 32-byte public key
let pubKeyData = data[64...]
print(pubKeyData.base64EncodedString())
} else {
fputs("Error: unexpected key length \(data.count) (expected 32 or 96)\n", stderr)
exit(1)
}