Skip to content

Commit

Permalink
Use FileHandle for reading base64 secret key from file (#2615)
Browse files Browse the repository at this point in the history
Fixes process substitution failing to work for providing the private key as file argument (#2605).
  • Loading branch information
zorgiepoo authored Aug 31, 2024
1 parent ed98751 commit 8bc4976
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 10 deletions.
38 changes: 38 additions & 0 deletions common_cli/secret.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,41 @@ func decodePrivateAndPublicKeys(secret: Data) -> (privateKey: Data, publicKey: D

return (privateKey, publicKey)
}

enum DecodeSecretStringError : LocalizedError {
case unableToReadData
case unableToDecodeDataAsUTF8String

public var errorDescription: String? {
switch self {
case .unableToReadData:
return "Unable to read EdDSA private key data"
case .unableToDecodeDataAsUTF8String:
return "Unable to read EdDSA private key data as UTF-8 string"
}
}
}

// Reads secret base64 string from a file
func decodeSecretString(filePath: String) throws -> String {
let privateKeyString: String
if #available(macOS 10.15.4, *) {
// Prefer to use FileHandle which supports process substitution:
// https://github.com/sparkle-project/Sparkle/issues/2605
let fileHandle = try FileHandle(forReadingFrom: URL(fileURLWithPath: filePath))

guard let data = try fileHandle.readToEnd() else {
throw DecodeSecretStringError.unableToReadData
}

guard let decodedPrivateKeyString = String(data: data, encoding: .utf8) else {
throw DecodeSecretStringError.unableToDecodeDataAsUTF8String
}

privateKeyString = decodedPrivateKeyString
} else {
privateKeyString = try String(contentsOf: URL(fileURLWithPath: filePath))
}

return privateKeyString.trimmingCharacters(in: .whitespacesAndNewlines)
}
11 changes: 7 additions & 4 deletions generate_appcast/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -285,19 +285,22 @@ struct GenerateAppcast: ParsableCommand {
allowNewPrivateKey = false
} else if let privateEdKeyPath = privateEdKeyPath {
do {
let privateKeyString: String
if privateEdKeyPath == "-" && !FileManager.default.fileExists(atPath: privateEdKeyPath) {
if let line = readLine(strippingNewline: true) {
privateKeyString = line
privateEdKeyString = line
} else {
print("Unable to read EdDSA private key from standard input")
throw ExitCode(1)
}
} else {
privateKeyString = try String(contentsOf: URL(fileURLWithPath: privateEdKeyPath))
do {
privateEdKeyString = try decodeSecretString(filePath: privateEdKeyPath)
} catch {
print(error.localizedDescription)
throw ExitCode(1)
}
}

privateEdKeyString = privateKeyString
allowNewPrivateKey = true
} catch {
print("Unable to load EdDSA private key from", privateEdKeyPath, "\n", error)
Expand Down
6 changes: 3 additions & 3 deletions generate_keys/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -235,12 +235,12 @@ struct GenerateKeys: ParsableCommand {
let secretBase64File = importedPrivateKeyFile
let secretBase64: String
do {
secretBase64 = try String(contentsOfFile: secretBase64File)
secretBase64 = try decodeSecretString(filePath: secretBase64File)
} catch {
failure("Failed to read private-key-file: \(error)")
failure("Failed to read private-key-file: \(error.localizedDescription)")
}

guard let secret = Data(base64Encoded: secretBase64.trimmingCharacters(in: .whitespacesAndNewlines), options: .init()) else {
guard let secret = Data(base64Encoded: secretBase64, options: .init()) else {
failure("Failed to decode base64 encoded key data from: \(secretBase64)")
}

Expand Down
6 changes: 3 additions & 3 deletions sign_update/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ func findKeys(inFile secretFile: String) throws -> (Data, Data) {
throw ExitCode(1)
}
} else {
secretString = try String(contentsOfFile: secretFile)
secretString = try decodeSecretString(filePath: secretFile)
}
return try findKeys(inString: secretString, allowNewFormat: true)
}

func findKeys(inString secretBase64String: String, allowNewFormat: Bool) throws -> (Data, Data) {
guard let secret = Data(base64Encoded: secretBase64String.trimmingCharacters(in: .whitespacesAndNewlines), options: .init()) else {
guard let secret = Data(base64Encoded: secretBase64String, options: .init()) else {
print("ERROR! Failed to decode base64 encoded key data from: \(secretBase64String)")
throw ExitCode.failure
}
Expand Down Expand Up @@ -141,7 +141,7 @@ struct SignUpdate: ParsableCommand {
func run() throws {
let (priv, pub): (Data, Data)

if let privateKey = privateKey {
if let privateKey = privateKey?.trimmingCharacters(in: .whitespacesAndNewlines) {
fputs("Warning: The -s option for passing the private EdDSA key is insecure and deprecated. Please see its help usage for more information.\n", stderr)

(priv, pub) = try findKeys(inString: privateKey, allowNewFormat: false)
Expand Down

0 comments on commit 8bc4976

Please sign in to comment.