let brew callers customize the sudo dialog message
runBrew gains an optional askpassMessage; the dialog reads "BrewBar needs your administrator password to <message>." and defaults to naming the brew command. Groundwork for per-cask upgrade prompts that name the app instead of the command. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
89921275b8
commit
0def852416
|
|
@ -150,26 +150,28 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
/// prompt whenever brew needs admin rights (no terminal is attached to
|
/// prompt whenever brew needs admin rights (no terminal is attached to
|
||||||
/// Process). If two brew commands overlap, the later one's text wins —
|
/// Process). If two brew commands overlap, the later one's text wins —
|
||||||
/// harmless, since prompts realistically only appear during upgrades.
|
/// 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]
|
let dir = FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask)[0]
|
||||||
.appendingPathComponent("BrewBar", isDirectory: true)
|
.appendingPathComponent("BrewBar", isDirectory: true)
|
||||||
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
try? FileManager.default.createDirectory(at: dir, withIntermediateDirectories: true)
|
||||||
|
|
||||||
// the text lands inside shell single quotes AND an AppleScript string;
|
// the text lands inside shell single quotes AND an AppleScript string;
|
||||||
// whitelist characters that cannot break out of either
|
// 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 url = dir.appendingPathComponent("askpass.sh")
|
||||||
let script = """
|
let script = """
|
||||||
#!/bin/zsh
|
#!/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? script.write(to: url, atomically: true, encoding: .utf8)
|
||||||
try? FileManager.default.setAttributes([.posixPermissions: 0o700], ofItemAtPath: url.path)
|
try? FileManager.default.setAttributes([.posixPermissions: 0o700], ofItemAtPath: url.path)
|
||||||
return url
|
return url
|
||||||
}
|
}
|
||||||
|
|
||||||
func runBrew(_ command: String, completion: @escaping (String) -> Void = { _ in }) {
|
/// askpassMessage customizes the sudo dialog ("...password to <message>.");
|
||||||
|
/// defaults to naming the brew command.
|
||||||
|
func runBrew(_ command: String, askpassMessage: String? = nil, completion: @escaping (String) -> Void = { _ in }) {
|
||||||
DispatchQueue.global().async {
|
DispatchQueue.global().async {
|
||||||
let brew = self.resolveBrewPath()
|
let brew = self.resolveBrewPath()
|
||||||
let cleaned = command.replacingOccurrences(of: "brew ", with: "")
|
let cleaned = command.replacingOccurrences(of: "brew ", with: "")
|
||||||
|
|
@ -184,7 +186,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
process.arguments = arguments
|
process.arguments = arguments
|
||||||
|
|
||||||
var environment = ProcessInfo.processInfo.environment
|
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
|
process.environment = environment
|
||||||
|
|
||||||
let pipe = Pipe()
|
let pipe = Pipe()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue