Mist/MistHelperTool/main.swift
2022-12-08 20:33:37 +11:00

85 lines
3.4 KiB
Swift

//
// main.swift
// MistHelperTool
//
// Created by Nindi Gill on 21/6/2022.
//
import Foundation
import SecureXPC
/// Helper Tool struct to run a command sent from the main application.
struct HelperToolCommandRunner {
/// Run the requested command and return the status and output.
///
/// - Parameters:
/// - request: A `HelperToolCommandRequest` struct containing the command to run with optional arguments.
///
/// - Throws: A `MistError` if the command failed to execute.
///
/// - Returns: A `HelperToolCommandResponse` struct containing the termination status, standard output and standard error.
static func run(_ request: HelperToolCommandRequest) throws -> HelperToolCommandResponse {
switch request.type {
case .remove:
guard let path: String = request.arguments.first else {
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: "Invalid URL: \(request.arguments)")
}
guard FileManager.default.fileExists(atPath: path) else {
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
}
do {
try FileManager.default.removeItem(atPath: path)
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
} catch {
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: error.localizedDescription)
}
case .fileAttributes:
guard let path: String = request.arguments.first,
let ownerAccountName: String = request.arguments.last else {
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: "Invalid attributes: \(request.arguments)")
}
let attributes: [FileAttributeKey: Any] = [
.posixPermissions: 0o755,
.ownerAccountName: ownerAccountName,
.groupOwnerAccountName: "staff"
]
do {
try FileManager.default.setAttributes(attributes, ofItemAtPath: path)
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
} catch {
return HelperToolCommandResponse(terminationStatus: 1, standardOutput: nil, standardError: error.localizedDescription)
}
case .kill:
ShellExecutor.shared.terminate()
return HelperToolCommandResponse(terminationStatus: 0, standardOutput: nil, standardError: nil)
default:
let response: (terminationStatus: Int32, standardOutput: String?, standardError: String?) = try ShellExecutor.shared.execute(request.arguments, environment: request.environment)
return HelperToolCommandResponse(terminationStatus: response.terminationStatus, standardOutput: response.standardOutput, standardError: response.standardError)
}
}
}
// launchd pid = 1
guard getppid() == 1 else {
exit(1)
}
/// XPCServer used to monitor incoming requests
let server: XPCServer = try XPCServer.forMachService()
server.registerRoute(XPCRoute.commandRoute, handler: HelperToolCommandRunner.run(_:))
server.setErrorHandler { error in
if case .connectionInvalid = error {
// do nothing
} else {
NSLog("error: \(error)")
}
}
server.startAndBlock()