我正在创建一个 macOS 应用程序(使用 SwiftUI),它将运行一个脚本。要运行脚本,我需要系统(或管理员)密码。因为当我在终端中运行该脚本时,它会询问用户密码然后运行该脚本。 我可以使用 securefeild 在按钮单击时运行脚本,但是 在应用程序中向用户显示安全字段并询问其系统密码是不合适的,同时也违反了苹果的指导方针。所以我删除了那个字段。 现在我不知道如何在系统密码身份验证后运行脚本。 为了显示用户身份验证,我正在使用它。
let context = LAContext()
func authorize() {
var error: NSError? = nil // Create optional error variable
let reason = "This action requires your authentication for security purposes."
let policy: LAPolicy = .deviceOwnerAuthentication // Adjust policy based on device capabilities (e.g., biometrics, passcode)
context.evaluatePolicy(policy, localizedReason: reason, reply: { (success, error) in
if success {
// User was successfully authenticated
**// Proceed with your script execution here, but the problem is I dont have user password here, and not found even from the Keychain, because before fetch password from keychain it should be store there**
print("Success")
} else {
// Authentication failed or was canceled
if let error = error {
// Handle the error appropriately
print(error.localizedDescription)
}
}
})
}
我认为,为了安全起见,我应该将密码保存在钥匙串中,而不是访问,但是,首先我需要在不违反苹果指南的情况下获取密码。
这就是整个问题,我没有找到相关的东西。
编辑:
当我在成功案例中运行脚本时,它会在终端下方的 Xcode 中显示消息。
sudo: a password is required
sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
我自己找到了问题的解决方案。就我而言,
let context = LAContext()
不起作用,也没有必要。
用管理员运行脚本不需要在钥匙串中存储密码。当时编写脚本时用这个东西编写脚本。
let osacScript = "osascript -e 'do shell script \"\(script)\" with administrator privileges'"
我们可以像这样编写
sudo
脚本(当我们想要执行一些操作(例如创建文件夹或移动文件夹)时需要sudo脚本)
let osacScript = "osascript -e 'do shell script \"sudo \(script)\" with administrator privileges'"
解决我的问题的代码如下:
func installScript(scriptPath: String, installingDir: String) {
let script = "\(scriptPath) --noprompt --dir \(installingDir) --key ABCKEY --region name-for-region --server https://myserver.com"
DispatchQueue.global(qos: .background).async { // I am using SwiftUI so to avoid blocking the UI running script in the background.
let osacScript = "osascript -e 'do shell script \"\(script)\" with administrator privileges'"
print(osacScript)
var arguments = [String]()
arguments.append("-c")
arguments .append(osacScript)
let process = Process()
process.launchPath = "/bin/bash" // Specify the shell to use
process.arguments = arguments
let pipe = Pipe()
process.standardOutput = pipe
process.standardError = pipe // Redirect standard error to the same pipe
let fileHandle = pipe.fileHandleForReading
process.launch()
process.waitUntilExit()
let data = fileHandle.readDataToEndOfFile()
let logFilePath = Bundle.main.path(forResource: "logfile", ofType: "txt")! // This thing can lead to error if file does not exist, so make sure it should be optional.
if let output = String(data: data, encoding: .utf8) {
print("output:\(output)")
// Write output to file
do {
try output.write(toFile: logFilePath, atomically: true, encoding: .utf8)
} catch {
print("Error writing to file: \(error)")
}
}
}
}