I am developing a Swift Vapor app. I want to access the Terminal app (among other apps).
The user will enter a front-end Terminal command and it will be performed by the backend server and the result will be displayed.
What I have done:
The issue:
The operation couldn’t be completed. Permission denied
What I have tried:
"--disable-sandbox"
App
app.environment.arguments
to ["--disable-sandbox"]
(see below)swift run --disable-sandbox
Tutorials:
Code:
import Leaf
import Vapor
/*
// Kill a already working server instance.
sudo lsof -i :8080
kill PID
*/
// configures your application
public func configure(_ app: Application) async throws {
// uncomment to serve files from /Public folder
// app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))
app.views.use(.leaf)
// app.environment.arguments = ["--disable-sandbox"]
// register routes
try routes(app)
}
import Vapor
import ConsoleKit
// Web URL:
// http://127.0.0.1:8080/terminalCommand/
// #Example:
// http://127.0.0.1:8080/terminalCommand/123
func routes(_ app: Application) throws {
app.get { req async throws in
try await req.view.render("index", ["title": "TerminalCommand"])
}
app.get("terminalCommand", ":commandName") { req -> String in
let terminal: Terminal = .init()
var visibleResultMessage: String = ""
var resultMessage: String = ""
guard let commandName: String = req.parameters.get("commandName") else {
throw Abort(.internalServerError)
}
/*
let commandContext: CommandContext = CommandContext(console: terminal, input: .init(arguments: [""]))
let command = TerminalCommand(app: app)
*/
let pmset: Process = Process()
// pmset.currentDirectoryURL = URL(fileURLWithPath: NSHomeDirectory())
let pipe: Pipe = Pipe()
// let workingDirectory: String = app.directory.workingDirectory
let defaultExecutableURL: URL = URL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app")
pmset.executableURL = defaultExecutableURL
pmset.executableURL?.startAccessingSecurityScopedResource()
pmset.standardOutput = pipe
do {
try pmset.run()
pmset.waitUntilExit()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
if let output = String(data: data, encoding: String.Encoding.utf8) {
// context.console.print(output)
print(output)
}
resultMessage = "SUCCESS: Run terminal command."
pmset.executableURL?.stopAccessingSecurityScopedResource()
} catch let error {
resultMessage = "ERROR: Run terminal command -> \(error.localizedDescription)"
}
visibleResultMessage =
"""
Result:
\(resultMessage)
Output:
%: \(commandName)
"""
return visibleResultMessage
}
}
Additional Info:
Thank you for you time and support.
The problem was in this line:
let defaultExecutableURL: URL = URL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app")
The mentioned URL is a folder url, and not the executable url. The solution is:
let defaultExecutableURL: URL = URL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal")
The error message was misleading. I have found the solution by logging the actual error and trying to find the error code 13. This lead me to another SO anwser that said that its a folder access error.