show the triggering brew command in the sudo password dialog
The askpass script is now rewritten before each brew invocation with
the current command baked into the dialog text ("...to run: brew
upgrade tailscale-app") instead of a generic message written once at
launch. The command text is whitelisted to characters that cannot
break out of the shell/AppleScript quoting it is embedded in.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
421ae5c40d
commit
89921275b8
|
|
@ -145,22 +145,29 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
return "brew"
|
return "brew"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Written once per launch; sudo runs it to show a GUI password dialog
|
/// Rewritten before each brew command so the sudo password dialog can say
|
||||||
/// whenever brew needs admin rights (no terminal is attached to Process).
|
/// which command needs it. Sudo runs this script to show a GUI password
|
||||||
static let askpassURL: URL = {
|
/// 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 {
|
||||||
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;
|
||||||
|
// whitelist characters that cannot break out of either
|
||||||
|
let safeCommand = command.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 continue:" 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 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'
|
||||||
"""
|
"""
|
||||||
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 }) {
|
func runBrew(_ command: String, completion: @escaping (String) -> Void = { _ in }) {
|
||||||
DispatchQueue.global().async {
|
DispatchQueue.global().async {
|
||||||
|
|
@ -177,7 +184,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.askpassURL.path
|
environment["SUDO_ASKPASS"] = Self.writeAskpassScript(for: cleaned).path
|
||||||
process.environment = environment
|
process.environment = environment
|
||||||
|
|
||||||
let pipe = Pipe()
|
let pipe = Pipe()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue