diff --git a/BrewBar/BrewBarApp.swift b/BrewBar/BrewBarApp.swift index c43e4e0..ce7fb7b 100644 --- a/BrewBar/BrewBarApp.swift +++ b/BrewBar/BrewBarApp.swift @@ -150,26 +150,28 @@ class AppDelegate: NSObject, NSApplicationDelegate { /// prompt whenever brew needs admin rights (no terminal is attached to /// Process). If two brew commands overlap, the later one's text wins — /// harmless, since prompts realistically only appear during upgrades. - static func writeAskpassScript(for command: String) -> URL { + static func writeAskpassScript(message: String) -> URL { let dir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0] .appendingPathComponent("BrewBar", isDirectory: true) try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true) // the text lands inside shell single quotes AND an AppleScript string; // whitelist characters that cannot break out of either - let safeCommand = command.filter { $0.isLetter || $0.isNumber || " ._@+=:/-".contains($0) } + let safeMessage = message.filter { $0.isLetter || $0.isNumber || " ._@+=:/-".contains($0) } let url = dir.appendingPathComponent("askpass.sh") let script = """ #!/bin/zsh - osascript -e 'display dialog "BrewBar needs your administrator password to run:\\n\\nbrew \(safeCommand)" default answer "" with hidden answer with title "BrewBar" with icon caution buttons {"Cancel", "OK"} default button "OK"' -e 'text returned of result' + osascript -e 'display dialog "BrewBar needs your administrator password to \(safeMessage)." default answer "" with hidden answer with title "BrewBar" with icon caution buttons {"Cancel", "OK"} default button "OK"' -e 'text returned of result' """ try? script.write(to: url, atomically: true, encoding: .utf8) try? FileManager.default.setAttributes([.posixPermissions: 0o700], ofItemAtPath: url.path) return url } - func runBrew(_ command: String, completion: @escaping (String) -> Void = { _ in }) { + /// askpassMessage customizes the sudo dialog ("...password to ."); + /// defaults to naming the brew command. + func runBrew(_ command: String, askpassMessage: String? = nil, completion: @escaping (String) -> Void = { _ in }) { DispatchQueue.global().async { let brew = self.resolveBrewPath() let cleaned = command.replacingOccurrences(of: "brew ", with: "") @@ -184,7 +186,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { process.arguments = arguments var environment = ProcessInfo.processInfo.environment - environment["SUDO_ASKPASS"] = Self.writeAskpassScript(for: cleaned).path + environment["SUDO_ASKPASS"] = Self.writeAskpassScript(message: askpassMessage ?? "run: brew \(cleaned)").path process.environment = environment let pipe = Pipe()