mirror of
https://github.com/SideStore/SideStore.git
synced 2026-02-08 22:33:26 +01:00
[AltJIT] Adds AltJIT CLI tool to enable JIT on devices running iOS 17+
Commands: altjit enable [app/pid] --udid [udid] * Enables JIT for given app/process altjit mount --udid [udid] * Mounts personalized developer disk
This commit is contained in:
9
AltJIT/AltJIT-Bridging-Header.h
Normal file
9
AltJIT/AltJIT-Bridging-Header.h
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "ALTErrorKeys.h"
|
||||
|
||||
// Shared
|
||||
#import "ALTWrappedError.h"
|
||||
#import "NSError+ALTServerError.h"
|
||||
18
AltJIT/AltJIT.swift
Normal file
18
AltJIT/AltJIT.swift
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AltJIT.swift
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 8/29/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import OSLog
|
||||
import ArgumentParser
|
||||
|
||||
@main
|
||||
struct AltJIT: AsyncParsableCommand
|
||||
{
|
||||
static let configuration = CommandConfiguration(commandName: "altjit",
|
||||
abstract: "Enable JIT for sideloaded apps.",
|
||||
subcommands: [EnableJIT.self, MountDisk.self])
|
||||
}
|
||||
452
AltJIT/Commands/EnableJIT.swift
Normal file
452
AltJIT/Commands/EnableJIT.swift
Normal file
@@ -0,0 +1,452 @@
|
||||
//
|
||||
// EnableJIT.swift
|
||||
// AltPackage
|
||||
//
|
||||
// Created by Riley Testut on 8/29/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import OSLog
|
||||
import RegexBuilder
|
||||
|
||||
import ArgumentParser
|
||||
|
||||
struct EnableJIT: PythonCommand
|
||||
{
|
||||
static let configuration = CommandConfiguration(commandName: "enable", abstract: "Enable JIT for a specific app on your device.")
|
||||
|
||||
@Argument(help: "The name or PID of the app to enable JIT for.", transform: AppProcess.init)
|
||||
var process: AppProcess
|
||||
|
||||
@Option(help: "Your iOS device's UDID.")
|
||||
var udid: String
|
||||
|
||||
// PythonCommand
|
||||
var pythonPath: String?
|
||||
|
||||
mutating func run() async throws
|
||||
{
|
||||
// Use local variables to fix "escaping autoclosure captures mutating self parameter" compiler error.
|
||||
let process = self.process
|
||||
let udid = self.udid
|
||||
|
||||
do
|
||||
{
|
||||
do
|
||||
{
|
||||
Logger.main.info("Enabling JIT for \(process, privacy: .private(mask: .hash)) on device \(udid, privacy: .private(mask: .hash))...")
|
||||
|
||||
try await self.prepare()
|
||||
|
||||
let rsdTunnel = try await self.startRSDTunnel()
|
||||
defer { rsdTunnel.process.terminate() }
|
||||
print("Connected to device \(self.udid)!", rsdTunnel)
|
||||
|
||||
let port = try await self.startDebugServer(rsdTunnel: rsdTunnel)
|
||||
print("Started debugserver on port \(port).")
|
||||
|
||||
print("Attaching debugger...")
|
||||
let lldb = try await self.attachDebugger(ipAddress: rsdTunnel.ipAddress, port: port)
|
||||
defer { lldb.terminate() }
|
||||
print("Attached debugger to \(process).")
|
||||
|
||||
try await self.detachDebugger(lldb)
|
||||
print("Detached debugger from \(process).")
|
||||
|
||||
print("✅ Successfully enabled JIT for \(process) on device \(udid)!")
|
||||
}
|
||||
catch let error as ProcessError
|
||||
{
|
||||
if let output = error.output
|
||||
{
|
||||
print(output)
|
||||
}
|
||||
|
||||
throw error
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("❌ Unable to enable JIT for \(process) on device \(udid).")
|
||||
print(error.localizedDescription)
|
||||
|
||||
Logger.main.error("Failed to enable JIT for \(process, privacy: .private(mask: .hash)) on device \(udid, privacy: .private(mask: .hash)). \(error, privacy: .public)")
|
||||
|
||||
throw ExitCode.failure
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension EnableJIT
|
||||
{
|
||||
func startRSDTunnel() async throws -> RemoteServiceDiscoveryTunnel
|
||||
{
|
||||
do
|
||||
{
|
||||
Logger.main.info("Starting RSD tunnel...")
|
||||
|
||||
let process = try Process.launch(.python3, arguments: ["-u", "-m", "pymobiledevice3", "remote", "start-quic-tunnel", "--udid", self.udid], environment: self.processEnvironment)
|
||||
|
||||
do
|
||||
{
|
||||
let rsdTunnel = try await withTimeout(seconds: 20) {
|
||||
let regex = Regex {
|
||||
"--rsd"
|
||||
|
||||
OneOrMore(.whitespace)
|
||||
|
||||
Capture {
|
||||
OneOrMore(.anyGraphemeCluster)
|
||||
}
|
||||
|
||||
OneOrMore(.whitespace)
|
||||
|
||||
TryCapture {
|
||||
OneOrMore(.digit)
|
||||
} transform: { match in
|
||||
Int(match)
|
||||
}
|
||||
}
|
||||
|
||||
for try await line in process.outputLines
|
||||
{
|
||||
if let match = line.firstMatch(of: regex)
|
||||
{
|
||||
let rsdTunnel = RemoteServiceDiscoveryTunnel(ipAddress: String(match.1), port: match.2, process: process)
|
||||
return rsdTunnel
|
||||
}
|
||||
}
|
||||
|
||||
throw ProcessError.unexpectedOutput(executableURL: .python3, output: process.output)
|
||||
}
|
||||
|
||||
// MUST close standardOutput in order to stream output later.
|
||||
process.stopOutput()
|
||||
|
||||
return rsdTunnel
|
||||
}
|
||||
catch is TimedOutError
|
||||
{
|
||||
process.terminate()
|
||||
|
||||
let error = ProcessError.timedOut(executableURL: .python3, output: process.output)
|
||||
throw error
|
||||
}
|
||||
catch
|
||||
{
|
||||
process.terminate()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
catch let error as NSError
|
||||
{
|
||||
let localizedFailure = NSLocalizedString("Could not connect to device \(self.udid).", comment: "")
|
||||
throw error.withLocalizedFailure(localizedFailure)
|
||||
}
|
||||
}
|
||||
|
||||
func startDebugServer(rsdTunnel: RemoteServiceDiscoveryTunnel) async throws -> Int
|
||||
{
|
||||
do
|
||||
{
|
||||
Logger.main.info("Starting debugserver...")
|
||||
|
||||
return try await withTimeout(seconds: 10) {
|
||||
let arguments = ["-u", "-m", "pymobiledevice3", "developer", "debugserver", "start-server"] + rsdTunnel.commandArguments
|
||||
|
||||
let output = try await Process.launchAndWait(.python3, arguments: arguments, environment: self.processEnvironment)
|
||||
|
||||
let port = Reference(Int.self)
|
||||
let regex = Regex {
|
||||
"connect://"
|
||||
|
||||
OneOrMore(.anyGraphemeCluster, .eager)
|
||||
|
||||
":"
|
||||
|
||||
TryCapture(as: port) {
|
||||
OneOrMore(.digit)
|
||||
} transform: { match in
|
||||
Int(match)
|
||||
}
|
||||
}
|
||||
|
||||
if let match = output.firstMatch(of: regex)
|
||||
{
|
||||
return match[port]
|
||||
}
|
||||
|
||||
throw ProcessError.unexpectedOutput(executableURL: .python3, output: output)
|
||||
}
|
||||
}
|
||||
catch let error as NSError
|
||||
{
|
||||
let localizedFailure = NSLocalizedString("Could not start debugserver on device \(self.udid).", comment: "")
|
||||
throw error.withLocalizedFailure(localizedFailure)
|
||||
}
|
||||
}
|
||||
|
||||
func attachDebugger(ipAddress: String, port: Int) async throws -> Process
|
||||
{
|
||||
do
|
||||
{
|
||||
Logger.main.info("Attaching debugger...")
|
||||
|
||||
let processID: Int
|
||||
|
||||
switch self.process
|
||||
{
|
||||
case .pid(let pid): processID = pid
|
||||
case .name(let name):
|
||||
guard let pid = try await self.getPID(for: name) else { throw JITError.processNotRunning(self.process) }
|
||||
processID = pid
|
||||
}
|
||||
|
||||
let process = try Process.launch(.lldb, environment: self.processEnvironment)
|
||||
|
||||
do
|
||||
{
|
||||
try await withThrowingTaskGroup(of: Void.self) { taskGroup in
|
||||
|
||||
// // Throw error if program terminates.
|
||||
// taskGroup.addTask {
|
||||
// try await withCheckedThrowingContinuation { continuation in
|
||||
// process.terminationHandler = { process in
|
||||
// Task {
|
||||
// // Should NEVER be called unless an error occurs.
|
||||
// continuation.resume(throwing: ProcessError.terminated(executableURL: .lldb, exitCode: process.terminationStatus, output: process.output))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
taskGroup.addTask {
|
||||
do
|
||||
{
|
||||
try await self.sendDebuggerCommand("platform select remote-ios", to: process, timeout: 5) {
|
||||
ChoiceOf {
|
||||
"SDK Roots:"
|
||||
"unable to locate SDK"
|
||||
}
|
||||
}
|
||||
|
||||
let ipAddress = "[\(ipAddress)]"
|
||||
let connectCommand = "process connect connect://\(ipAddress):\(port)"
|
||||
try await self.sendDebuggerCommand(connectCommand, to: process, timeout: 10)
|
||||
|
||||
try await self.sendDebuggerCommand("settings set target.memory-module-load-level minimal", to: process, timeout: 5)
|
||||
|
||||
let attachCommand = "attach -p \(processID)"
|
||||
let failureMessage = "attach failed"
|
||||
let output = try await self.sendDebuggerCommand(attachCommand, to: process, timeout: 120) {
|
||||
|
||||
ChoiceOf {
|
||||
failureMessage
|
||||
|
||||
Regex {
|
||||
"Process "
|
||||
OneOrMore(.digit)
|
||||
" stopped"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if output.contains(failureMessage)
|
||||
{
|
||||
throw ProcessError.failed(executableURL: .lldb, exitCode: -1, output: process.output)
|
||||
}
|
||||
}
|
||||
catch is TimedOutError
|
||||
{
|
||||
let error = ProcessError.timedOut(executableURL: .lldb, output: process.output)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until first child task returns
|
||||
_ = try await taskGroup.next()!
|
||||
|
||||
// Cancel remaining tasks
|
||||
taskGroup.cancelAll()
|
||||
}
|
||||
|
||||
return process
|
||||
}
|
||||
catch
|
||||
{
|
||||
process.terminate()
|
||||
throw error
|
||||
}
|
||||
}
|
||||
catch let error as NSError
|
||||
{
|
||||
let localizedFailure = String(format: NSLocalizedString("Could not attach debugger to %@.", comment: ""), self.process.description)
|
||||
throw error.withLocalizedFailure(localizedFailure)
|
||||
}
|
||||
}
|
||||
|
||||
func detachDebugger(_ process: Process) async throws
|
||||
{
|
||||
do
|
||||
{
|
||||
Logger.main.info("Detaching debugger...")
|
||||
|
||||
try await withThrowingTaskGroup(of: Void.self) { taskGroup in
|
||||
|
||||
// // Throw error if program terminates.
|
||||
// taskGroup.addTask {
|
||||
// try await withCheckedThrowingContinuation { continuation in
|
||||
// process.terminationHandler = { process in
|
||||
// if process.terminationStatus == 0
|
||||
// {
|
||||
// continuation.resume()
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// continuation.resume(throwing: ProcessError.terminated(executableURL: .lldb, exitCode: process.terminationStatus, output: process.output))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
taskGroup.addTask {
|
||||
do
|
||||
{
|
||||
try await self.sendDebuggerCommand("c", to: process, timeout: 10) {
|
||||
"Process "
|
||||
OneOrMore(.digit)
|
||||
" resuming"
|
||||
}
|
||||
|
||||
try await self.sendDebuggerCommand("detach", to: process, timeout: 10) {
|
||||
"Process "
|
||||
OneOrMore(.digit)
|
||||
" detached"
|
||||
}
|
||||
}
|
||||
catch is TimedOutError
|
||||
{
|
||||
let error = ProcessError.timedOut(executableURL: .lldb, output: process.output)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until first child task returns
|
||||
_ = try await taskGroup.next()!
|
||||
|
||||
// Cancel remaining tasks
|
||||
taskGroup.cancelAll()
|
||||
}
|
||||
}
|
||||
catch let error as NSError
|
||||
{
|
||||
let localizedFailure = NSLocalizedString("Could not detach debugger from \(self.process).", comment: "")
|
||||
throw error.withLocalizedFailure(localizedFailure)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension EnableJIT
|
||||
{
|
||||
func getPID(for name: String) async throws -> Int?
|
||||
{
|
||||
Logger.main.info("Retrieving PID for \(name, privacy: .private(mask: .hash))...")
|
||||
|
||||
let arguments = ["-m", "pymobiledevice3", "processes", "pgrep", name, "--udid", self.udid]
|
||||
let output = try await Process.launchAndWait(.python3, arguments: arguments, environment: self.processEnvironment)
|
||||
|
||||
let regex = Regex {
|
||||
"INFO"
|
||||
|
||||
OneOrMore(.whitespace)
|
||||
|
||||
TryCapture {
|
||||
OneOrMore(.digit)
|
||||
} transform: { match in
|
||||
Int(match)
|
||||
}
|
||||
|
||||
OneOrMore(.whitespace)
|
||||
|
||||
name
|
||||
}
|
||||
|
||||
if let match = output.firstMatch(of: regex)
|
||||
{
|
||||
Logger.main.info("\(name, privacy: .private(mask: .hash)) PID is \(match.1)")
|
||||
return match.1
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func sendDebuggerCommand(_ command: String, to process: Process, timeout: TimeInterval,
|
||||
@RegexComponentBuilder regex: @escaping () -> (some RegexComponent<Substring>)? = { Optional<Regex<Substring>>.none }) async throws -> String
|
||||
{
|
||||
guard let inputPipe = process.standardInput as? Pipe else { preconditionFailure("`process` must have a Pipe as its standardInput") }
|
||||
defer {
|
||||
inputPipe.fileHandleForWriting.writeabilityHandler = nil
|
||||
}
|
||||
|
||||
let initialOutput = process.output
|
||||
|
||||
let data = (command + "\n").data(using: .utf8)! // Will always succeed.
|
||||
Logger.main.info("Sending lldb command: \(command, privacy: .public)")
|
||||
|
||||
let output = try await withTimeout(seconds: timeout) {
|
||||
// Wait until process is ready to receive input.
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
inputPipe.fileHandleForWriting.writeabilityHandler = { fileHandle in
|
||||
inputPipe.fileHandleForWriting.writeabilityHandler = nil
|
||||
|
||||
let result = Result { try fileHandle.write(contentsOf: data) }
|
||||
continuation.resume(with: result)
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until we receive at least one line of output.
|
||||
for try await _ in process.outputLines
|
||||
{
|
||||
break
|
||||
}
|
||||
|
||||
// Keep waiting until output doesn't change.
|
||||
// If regex is provided, we keep waiting until a match is found.
|
||||
var previousOutput = process.output
|
||||
while true
|
||||
{
|
||||
try await Task.sleep(for: .seconds(0.2))
|
||||
|
||||
let output = process.output
|
||||
if output == previousOutput
|
||||
{
|
||||
guard let regex = regex() else {
|
||||
// No regex, so break as soon as output stops changing.
|
||||
break
|
||||
}
|
||||
|
||||
if output.contains(regex)
|
||||
{
|
||||
// Found a match, so exit while loop.
|
||||
break
|
||||
}
|
||||
else
|
||||
{
|
||||
// Output hasn't changed, but regex does not match (yet).
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
previousOutput = output
|
||||
}
|
||||
|
||||
return previousOutput
|
||||
}
|
||||
|
||||
// Subtract initialOutput from output to get just this command's output.
|
||||
let commandOutput = output.replacingOccurrences(of: initialOutput, with: "")
|
||||
return commandOutput
|
||||
}
|
||||
}
|
||||
75
AltJIT/Commands/MountDisk.swift
Normal file
75
AltJIT/Commands/MountDisk.swift
Normal file
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// MountDisk.swift
|
||||
// AltPackage
|
||||
//
|
||||
// Created by Riley Testut on 8/31/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import OSLog
|
||||
|
||||
import ArgumentParser
|
||||
|
||||
typealias MountError = MountErrorCode.Error
|
||||
enum MountErrorCode: Int, ALTErrorEnum
|
||||
{
|
||||
case alreadyMounted
|
||||
|
||||
var errorFailureReason: String {
|
||||
switch self
|
||||
{
|
||||
case .alreadyMounted: return NSLocalizedString("A personalized Developer Disk is already mounted.", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MountDisk: PythonCommand
|
||||
{
|
||||
static let configuration = CommandConfiguration(commandName: "mount", abstract: "Mount a personalized developer disk image onto an iOS device.")
|
||||
|
||||
@Option(help: "The iOS device's UDID.")
|
||||
var udid: String
|
||||
|
||||
// PythonCommand
|
||||
var pythonPath: String?
|
||||
|
||||
mutating func run() async throws
|
||||
{
|
||||
do
|
||||
{
|
||||
print("Mounting personalized developer disk...")
|
||||
|
||||
try await self.prepare()
|
||||
|
||||
let output = try await Process.launchAndWait(.python3, arguments: ["-m", "pymobiledevice3", "mounter", "auto-mount", "--udid", self.udid])
|
||||
if !output.contains("DeveloperDiskImage")
|
||||
{
|
||||
throw ProcessError.unexpectedOutput(executableURL: .python3, output: output)
|
||||
}
|
||||
|
||||
if output.contains("already mounted")
|
||||
{
|
||||
throw MountError(.alreadyMounted)
|
||||
}
|
||||
|
||||
print("✅ Successfully mounted personalized Developer Disk!")
|
||||
}
|
||||
catch let error as MountError where error.code == .alreadyMounted
|
||||
{
|
||||
// Prepend ⚠️ since this is not really an error.
|
||||
let localizedDescription = "⚠️ " + error.localizedDescription
|
||||
print(localizedDescription)
|
||||
|
||||
throw ExitCode.success
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Output failure message first before error.
|
||||
print("❌ Unable to mount personalized Developer Disk.")
|
||||
print(error.localizedDescription)
|
||||
|
||||
throw ExitCode.failure
|
||||
}
|
||||
}
|
||||
}
|
||||
16
AltJIT/Extensions/Logger+AltJIT.swift
Normal file
16
AltJIT/Extensions/Logger+AltJIT.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// Logger+AltJIT.swift
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 8/29/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import OSLog
|
||||
|
||||
public extension Logger
|
||||
{
|
||||
static let altjitSubsystem = Bundle.main.bundleIdentifier!
|
||||
|
||||
static let main = Logger(subsystem: altjitSubsystem, category: "AltJIT")
|
||||
}
|
||||
57
AltJIT/Extensions/Task+Timeout.swift
Normal file
57
AltJIT/Extensions/Task+Timeout.swift
Normal file
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// Task+Timeout.swift
|
||||
// AltPackage
|
||||
//
|
||||
// Created by Riley Testut on 8/31/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
// Based heavily on https://forums.swift.org/t/running-an-async-task-with-a-timeout/49733/13
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TimedOutError: LocalizedError
|
||||
{
|
||||
var duration: TimeInterval
|
||||
|
||||
public var errorDescription: String? {
|
||||
//TODO: Change pluralization for 1 second.
|
||||
let errorDescription = String(format: NSLocalizedString("The task timed out after %@ seconds.", comment: ""), self.duration.formatted())
|
||||
return errorDescription
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Execute an operation in the current task subject to a timeout.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - seconds: The duration in seconds `operation` is allowed to run before timing out.
|
||||
/// - operation: The async operation to perform.
|
||||
/// - Returns: Returns the result of `operation` if it completed in time.
|
||||
/// - Throws: Throws ``TimedOutError`` if the timeout expires before `operation` completes.
|
||||
/// If `operation` throws an error before the timeout expires, that error is propagated to the caller.
|
||||
func withTimeout<R>(seconds: TimeInterval, file: StaticString = #file, line: Int = #line, operation: @escaping @Sendable () async throws -> R) async throws -> R
|
||||
{
|
||||
return try await withThrowingTaskGroup(of: R.self) { group in
|
||||
let deadline = Date(timeIntervalSinceNow: seconds)
|
||||
|
||||
// Start actual work.
|
||||
group.addTask {
|
||||
return try await operation()
|
||||
}
|
||||
// Start timeout child task.
|
||||
group.addTask {
|
||||
let interval = deadline.timeIntervalSinceNow
|
||||
if interval > 0 {
|
||||
try await Task.sleep(for: .seconds(interval))
|
||||
}
|
||||
try Task.checkCancellation()
|
||||
// We’ve reached the timeout.
|
||||
throw TimedOutError(duration: seconds)
|
||||
}
|
||||
// First finished child task wins, cancel the other task.
|
||||
let result = try await group.next()!
|
||||
group.cancelAll()
|
||||
return result
|
||||
}
|
||||
}
|
||||
15
AltJIT/Extensions/URL+Tools.swift
Normal file
15
AltJIT/Extensions/URL+Tools.swift
Normal file
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// URL+Tools.swift
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 9/3/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension URL
|
||||
{
|
||||
static let python3 = URL(fileURLWithPath: "/usr/bin/python3")
|
||||
static let lldb = URL(fileURLWithPath: "/usr/bin/lldb")
|
||||
}
|
||||
14
AltJIT/Types/ALTErrorKeys.h
Normal file
14
AltJIT/Types/ALTErrorKeys.h
Normal file
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// ALTErrorKeys.h
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 9/1/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
@import Foundation;
|
||||
|
||||
// Can't import AltSign (for reasons), so re-declare these constants here instead.
|
||||
extern NSErrorUserInfoKey const ALTSourceFileErrorKey;
|
||||
extern NSErrorUserInfoKey const ALTSourceLineErrorKey;
|
||||
extern NSErrorUserInfoKey const ALTAppNameErrorKey;
|
||||
13
AltJIT/Types/ALTErrorKeys.m
Normal file
13
AltJIT/Types/ALTErrorKeys.m
Normal file
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// ALTErrorKeys.m
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 9/1/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ALTErrorKeys.h"
|
||||
|
||||
NSErrorUserInfoKey const ALTSourceFileErrorKey = @"ALTSourceFile";
|
||||
NSErrorUserInfoKey const ALTSourceLineErrorKey = @"ALTSourceLine";
|
||||
NSErrorUserInfoKey const ALTAppNameErrorKey = @"appName";
|
||||
58
AltJIT/Types/PythonCommand.swift
Normal file
58
AltJIT/Types/PythonCommand.swift
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// PythonCommand.swift
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 9/6/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import ArgumentParser
|
||||
|
||||
protocol PythonCommand: AsyncParsableCommand
|
||||
{
|
||||
var pythonPath: String? { get set }
|
||||
}
|
||||
|
||||
extension PythonCommand
|
||||
{
|
||||
var processEnvironment: [String: String] {
|
||||
var environment = ProcessInfo.processInfo.environment
|
||||
|
||||
if let pythonPath
|
||||
{
|
||||
environment["PYTHONPATH"] = pythonPath
|
||||
}
|
||||
|
||||
return environment
|
||||
}
|
||||
|
||||
mutating func prepare() async throws
|
||||
{
|
||||
let pythonPath = try await self.readPythonPath()
|
||||
self.pythonPath = pythonPath.path(percentEncoded: false)
|
||||
}
|
||||
}
|
||||
|
||||
private extension PythonCommand
|
||||
{
|
||||
func readPythonPath() async throws -> URL
|
||||
{
|
||||
let processOutput: String
|
||||
|
||||
do
|
||||
{
|
||||
processOutput = try await Process.launchAndWait(.python3, arguments: ["-m", "site", "--user-site"])
|
||||
}
|
||||
catch let error as ProcessError where error.exitCode == 2
|
||||
{
|
||||
// Ignore exit code 2.
|
||||
guard let output = error.output else { throw error }
|
||||
processOutput = output
|
||||
}
|
||||
|
||||
let sanitizedOutput = processOutput.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
let pythonURL = URL(filePath: sanitizedOutput)
|
||||
return pythonURL
|
||||
}
|
||||
}
|
||||
41
AltJIT/Types/RemoteServiceDiscoveryTunnel.swift
Normal file
41
AltJIT/Types/RemoteServiceDiscoveryTunnel.swift
Normal file
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// RemoteServiceDiscoveryTunnel.swift
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 9/3/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
final class RemoteServiceDiscoveryTunnel
|
||||
{
|
||||
let ipAddress: String
|
||||
let port: Int
|
||||
|
||||
let process: Process
|
||||
|
||||
var commandArguments: [String] {
|
||||
["--rsd", self.ipAddress, String(self.port)]
|
||||
}
|
||||
|
||||
init(ipAddress: String, port: Int, process: Process)
|
||||
{
|
||||
self.ipAddress = ipAddress
|
||||
self.port = port
|
||||
|
||||
self.process = process
|
||||
}
|
||||
|
||||
deinit
|
||||
{
|
||||
self.process.terminate()
|
||||
}
|
||||
}
|
||||
|
||||
extension RemoteServiceDiscoveryTunnel: CustomStringConvertible
|
||||
{
|
||||
var description: String {
|
||||
"\(self.ipAddress) \(self.port)"
|
||||
}
|
||||
}
|
||||
@@ -355,9 +355,12 @@
|
||||
D51AD27F29356B7B00967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
||||
D51AD28029356B8000967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
||||
D52C08EE28AEC37A006C4AE5 /* AppVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52C08ED28AEC37A006C4AE5 /* AppVersion.swift */; };
|
||||
D52DD35E2AAA89A600A7F2B6 /* AltSign-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */; };
|
||||
D52DD35F2AAA89A700A7F2B6 /* AltSign-Dynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||
D52EF2BE2A0594550096C377 /* AppDetailCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D52EF2BD2A0594550096C377 /* AppDetailCollectionViewController.swift */; };
|
||||
D533E8B72727841800A9B5DD /* libAppleArchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8B62727841800A9B5DD /* libAppleArchive.tbd */; settings = {ATTRIBUTES = (Weak, ); }; };
|
||||
D533E8BE2727BBF800A9B5DD /* libcurl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D533E8BD2727BBF800A9B5DD /* libcurl.a */; };
|
||||
D537C85B2AA9507A009A1E08 /* libcorecrypto.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D537C85A2AA95066009A1E08 /* libcorecrypto.tbd */; platformFilters = (macos, ); };
|
||||
D53D84022A2158FC00543C3B /* Permissions.plist in Resources */ = {isa = PBXBuildFile; fileRef = D53D84012A2158FC00543C3B /* Permissions.plist */; };
|
||||
D54058B92A1D6269008CCC58 /* AppPermissionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54058B82A1D6269008CCC58 /* AppPermissionProtocol.swift */; };
|
||||
D54058BB2A1D8FE3008CCC58 /* UIColor+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54058BA2A1D8FE3008CCC58 /* UIColor+AltStore.swift */; };
|
||||
@@ -392,7 +395,15 @@
|
||||
D5935AED29C39DE300C157EF /* SourceDetailsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5935AEC29C39DE300C157EF /* SourceDetailsComponents.swift */; };
|
||||
D5935AEF29C3B23600C157EF /* Sources.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5935AEE29C3B23600C157EF /* Sources.storyboard */; };
|
||||
D593F1942717749A006E82DE /* PatchAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D593F1932717749A006E82DE /* PatchAppOperation.swift */; };
|
||||
D59A6B7B2AA91B8E00F61259 /* PythonCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59A6B7A2AA91B8E00F61259 /* PythonCommand.swift */; };
|
||||
D59A6B7F2AA9226C00F61259 /* AppProcess.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59A6B7D2AA9226C00F61259 /* AppProcess.swift */; };
|
||||
D59A6B822AA92D1C00F61259 /* Process+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59A6B802AA92D1C00F61259 /* Process+Conveniences.swift */; };
|
||||
D59A6B842AA932F700F61259 /* Logger+AltServer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D59A6B832AA932F700F61259 /* Logger+AltServer.swift */; };
|
||||
D5A0537329B91DB400997551 /* SourceDetailContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A0537229B91DB400997551 /* SourceDetailContentViewController.swift */; };
|
||||
D5A1D2E42AA50EB60066CACC /* JITError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A1D2E32AA50EB60066CACC /* JITError.swift */; };
|
||||
D5A1D2E92AA512940066CACC /* RemoteServiceDiscoveryTunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A1D2E82AA512940066CACC /* RemoteServiceDiscoveryTunnel.swift */; };
|
||||
D5A1D2EB2AA513410066CACC /* URL+Tools.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A1D2EA2AA513410066CACC /* URL+Tools.swift */; };
|
||||
D5A1D2EC2AA51D490066CACC /* ProcessError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A1B2AA284ED00EF863D /* ProcessError.swift */; };
|
||||
D5A2193429B14F94002229FC /* DeprecatedAPIs.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A2193329B14F94002229FC /* DeprecatedAPIs.swift */; };
|
||||
D5ACE84528E3B8450021CAB9 /* ClearAppCacheOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */; };
|
||||
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4A280E141900469595 /* ManagedPatron.swift */; };
|
||||
@@ -414,6 +425,18 @@
|
||||
D5F99A1828D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */; };
|
||||
D5F99A1A28D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */; };
|
||||
D5FB7A0E2AA25A4E00EF863D /* Previews.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D5FB7A0D2AA25A4E00EF863D /* Previews.xcassets */; };
|
||||
D5FB7A212AA284ED00EF863D /* EnableJIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A1A2AA284ED00EF863D /* EnableJIT.swift */; };
|
||||
D5FB7A242AA284ED00EF863D /* Logger+AltJIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A1D2AA284ED00EF863D /* Logger+AltJIT.swift */; };
|
||||
D5FB7A252AA284ED00EF863D /* AltJIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A1E2AA284ED00EF863D /* AltJIT.swift */; };
|
||||
D5FB7A262AA284ED00EF863D /* MountDisk.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A1F2AA284ED00EF863D /* MountDisk.swift */; };
|
||||
D5FB7A272AA284ED00EF863D /* Task+Timeout.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A202AA284ED00EF863D /* Task+Timeout.swift */; };
|
||||
D5FB7A2A2AA2854100EF863D /* ALTLocalizedError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5DB145828F9DC1000A8F606 /* ALTLocalizedError.swift */; };
|
||||
D5FB7A2B2AA2854400EF863D /* UserInfoValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5189C002A01BC6800F44625 /* UserInfoValue.swift */; };
|
||||
D5FB7A2E2AA2859400EF863D /* ArgumentParser in Frameworks */ = {isa = PBXBuildFile; productRef = D5FB7A2D2AA2859400EF863D /* ArgumentParser */; };
|
||||
D5FB7A312AA28A2900EF863D /* NSError+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6C336124197D700034FD24 /* NSError+AltStore.swift */; };
|
||||
D5FB7A322AA28A4000EF863D /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
|
||||
D5FB7A392AA28D8300EF863D /* NSError+ALTServerError.m in Sources */ = {isa = PBXBuildFile; fileRef = BF1E314922A060F400370A3C /* NSError+ALTServerError.m */; };
|
||||
D5FB7A472AA293D000EF863D /* ALTErrorKeys.m in Sources */ = {isa = PBXBuildFile; fileRef = D5FB7A462AA293D000EF863D /* ALTErrorKeys.m */; };
|
||||
D5FD4EC52A952EAD0097BEE8 /* AltWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FD4EC42A952EAD0097BEE8 /* AltWidgetBundle.swift */; };
|
||||
D5FD4EC92A9530C00097BEE8 /* AppSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FD4EC82A9530C00097BEE8 /* AppSnapshot.swift */; };
|
||||
D5FD4ECB2A9532960097BEE8 /* DatabaseManager+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FD4ECA2A9532960097BEE8 /* DatabaseManager+Async.swift */; };
|
||||
@@ -546,6 +569,13 @@
|
||||
remoteGlobalIDString = BF66EE7D2501AE50007EE018;
|
||||
remoteInfo = AltStoreCore;
|
||||
};
|
||||
D537C8562AA94D4A009A1E08 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = BFD247622284B9A500981D42 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = D5FB7A122AA284BE00EF863D;
|
||||
remoteInfo = AltJIT;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -572,6 +602,28 @@
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
BFF7C910257844C900E55F36 /* Embed XPC Services */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "$(CONTENTS_FOLDER_PATH)/XPCServices";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
BFF7C90F257844C900E55F36 /* AltXPC.xpc in Embed XPC Services */,
|
||||
);
|
||||
name = "Embed XPC Services";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D52DD3602AAA89A700A7F2B6 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
D52DD35F2AAA89A700A7F2B6 /* AltSign-Dynamic in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D561B2EC28EF5A4F006752E4 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -583,6 +635,15 @@
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D5FB7A112AA284BE00EF863D /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /usr/share/man/man1/;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 1;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
@@ -935,6 +996,7 @@
|
||||
D533E8B82727B61400A9B5DD /* fragmentzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragmentzip.h; sourceTree = "<group>"; };
|
||||
D533E8BB2727BBEE00A9B5DD /* libfragmentzip.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libfragmentzip.a; path = Dependencies/fragmentzip/libfragmentzip.a; sourceTree = SOURCE_ROOT; };
|
||||
D533E8BD2727BBF800A9B5DD /* libcurl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcurl.a; path = Dependencies/libcurl/libcurl.a; sourceTree = SOURCE_ROOT; };
|
||||
D537C85A2AA95066009A1E08 /* libcorecrypto.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcorecrypto.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX14.0.sdk/usr/lib/system/libcorecrypto.tbd; sourceTree = DEVELOPER_DIR; };
|
||||
D53D84012A2158FC00543C3B /* Permissions.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Permissions.plist; sourceTree = "<group>"; };
|
||||
D54058B82A1D6269008CCC58 /* AppPermissionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppPermissionProtocol.swift; sourceTree = "<group>"; };
|
||||
D54058BA2A1D8FE3008CCC58 /* UIColor+AltStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIColor+AltStore.swift"; sourceTree = "<group>"; };
|
||||
@@ -970,7 +1032,13 @@
|
||||
D5935AEC29C39DE300C157EF /* SourceDetailsComponents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceDetailsComponents.swift; sourceTree = "<group>"; };
|
||||
D5935AEE29C3B23600C157EF /* Sources.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Sources.storyboard; sourceTree = "<group>"; };
|
||||
D593F1932717749A006E82DE /* PatchAppOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PatchAppOperation.swift; sourceTree = "<group>"; };
|
||||
D59A6B7A2AA91B8E00F61259 /* PythonCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PythonCommand.swift; sourceTree = "<group>"; };
|
||||
D59A6B7D2AA9226C00F61259 /* AppProcess.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppProcess.swift; sourceTree = "<group>"; };
|
||||
D59A6B802AA92D1C00F61259 /* Process+Conveniences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Process+Conveniences.swift"; sourceTree = "<group>"; };
|
||||
D5A0537229B91DB400997551 /* SourceDetailContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SourceDetailContentViewController.swift; sourceTree = "<group>"; };
|
||||
D5A1D2E32AA50EB60066CACC /* JITError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JITError.swift; sourceTree = "<group>"; };
|
||||
D5A1D2E82AA512940066CACC /* RemoteServiceDiscoveryTunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteServiceDiscoveryTunnel.swift; sourceTree = "<group>"; };
|
||||
D5A1D2EA2AA513410066CACC /* URL+Tools.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+Tools.swift"; sourceTree = "<group>"; };
|
||||
D5A2193329B14F94002229FC /* DeprecatedAPIs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeprecatedAPIs.swift; sourceTree = "<group>"; };
|
||||
D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearAppCacheOperation.swift; sourceTree = "<group>"; };
|
||||
D5CA0C4A280E141900469595 /* ManagedPatron.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManagedPatron.swift; sourceTree = "<group>"; };
|
||||
@@ -991,6 +1059,16 @@
|
||||
D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = AltStore10ToAltStore11.xcmappingmodel; sourceTree = "<group>"; };
|
||||
D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreApp10ToStoreApp11Policy.swift; sourceTree = "<group>"; };
|
||||
D5FB7A0D2AA25A4E00EF863D /* Previews.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Previews.xcassets; sourceTree = "<group>"; };
|
||||
D5FB7A132AA284BE00EF863D /* altjit */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = altjit; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
D5FB7A1A2AA284ED00EF863D /* EnableJIT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EnableJIT.swift; path = AltJIT/Commands/EnableJIT.swift; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A1B2AA284ED00EF863D /* ProcessError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProcessError.swift; path = Shared/Errors/ProcessError.swift; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A1D2AA284ED00EF863D /* Logger+AltJIT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Logger+AltJIT.swift"; path = "AltJIT/Extensions/Logger+AltJIT.swift"; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A1E2AA284ED00EF863D /* AltJIT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AltJIT.swift; path = AltJIT/AltJIT.swift; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A1F2AA284ED00EF863D /* MountDisk.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MountDisk.swift; path = AltJIT/Commands/MountDisk.swift; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A202AA284ED00EF863D /* Task+Timeout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Task+Timeout.swift"; path = "AltJIT/Extensions/Task+Timeout.swift"; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A382AA28AC700EF863D /* AltJIT-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "AltJIT-Bridging-Header.h"; path = "AltJIT/AltJIT-Bridging-Header.h"; sourceTree = SOURCE_ROOT; };
|
||||
D5FB7A452AA293D000EF863D /* ALTErrorKeys.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ALTErrorKeys.h; sourceTree = "<group>"; };
|
||||
D5FB7A462AA293D000EF863D /* ALTErrorKeys.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ALTErrorKeys.m; sourceTree = "<group>"; };
|
||||
D5FD4EC42A952EAD0097BEE8 /* AltWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltWidgetBundle.swift; sourceTree = "<group>"; };
|
||||
D5FD4EC82A9530C00097BEE8 /* AppSnapshot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppSnapshot.swift; sourceTree = "<group>"; };
|
||||
D5FD4ECA2A9532960097BEE8 /* DatabaseManager+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DatabaseManager+Async.swift"; sourceTree = "<group>"; };
|
||||
@@ -1087,6 +1165,16 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D5FB7A102AA284BE00EF863D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D52DD35E2AAA89A600A7F2B6 /* AltSign-Dynamic in Frameworks */,
|
||||
D537C85B2AA9507A009A1E08 /* libcorecrypto.tbd in Frameworks */,
|
||||
D5FB7A2E2AA2859400EF863D /* ArgumentParser in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -1249,6 +1337,7 @@
|
||||
0EE7FDBF2BE8BBBF00D1E390 /* Errors */,
|
||||
BFF767C32489A6800097E58C /* Extensions */,
|
||||
BFF767C42489A6980097E58C /* Categories */,
|
||||
D59A6B7C2AA9225C00F61259 /* Types */,
|
||||
);
|
||||
path = Shared;
|
||||
sourceTree = "<group>";
|
||||
@@ -1722,6 +1811,9 @@
|
||||
19104DB32909C06D00C49C7B /* EmotionalDamage */,
|
||||
191E5FAC290A5D92001A3B7C /* minimuxer */,
|
||||
B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */,
|
||||
BFF7C905257844C900E55F36 /* AltXPC */,
|
||||
D5FB7A142AA284BE00EF863D /* AltJIT */,
|
||||
D586D39928EF58B0000E101F /* AltTests */,
|
||||
BFD247852284BB3300981D42 /* Frameworks */,
|
||||
B3146EC6284F580500BBC3FD /* Roxas.xcodeproj */,
|
||||
BFD2476B2284B9A500981D42 /* Products */,
|
||||
@@ -1740,6 +1832,9 @@
|
||||
BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */,
|
||||
19104DB22909C06C00C49C7B /* libEmotionalDamage.a */,
|
||||
191E5FAB290A5D92001A3B7C /* libminimuxer.a */,
|
||||
BFF7C904257844C900E55F36 /* AltXPC.xpc */,
|
||||
D586D39828EF58B0000E101F /* AltTests.xctest */,
|
||||
D5FB7A132AA284BE00EF863D /* altjit */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -1782,6 +1877,7 @@
|
||||
children = (
|
||||
B343F86C295F759E002B1159 /* libresolv.tbd */,
|
||||
B39575F4284F29E20080B4FF /* Roxas.framework */,
|
||||
D537C85A2AA95066009A1E08 /* libcorecrypto.tbd */,
|
||||
D533E8B62727841800A9B5DD /* libAppleArchive.tbd */,
|
||||
BF580497246A3D19008AE704 /* UIKit.framework */,
|
||||
BF4588872298DD3F00BD7491 /* libxml2.tbd */,
|
||||
@@ -1940,6 +2036,7 @@
|
||||
BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */,
|
||||
BF6C336124197D700034FD24 /* NSError+AltStore.swift */,
|
||||
D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */,
|
||||
D59A6B802AA92D1C00F61259 /* Process+Conveniences.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@@ -2011,6 +2108,17 @@
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D522F9562AA509E9003E57D1 /* Types */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D5FB7A452AA293D000EF863D /* ALTErrorKeys.h */,
|
||||
D5FB7A462AA293D000EF863D /* ALTErrorKeys.m */,
|
||||
D5A1D2E82AA512940066CACC /* RemoteServiceDiscoveryTunnel.swift */,
|
||||
D59A6B7A2AA91B8E00F61259 /* PythonCommand.swift */,
|
||||
);
|
||||
path = Types;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D54058B72A1D6251008CCC58 /* Previews */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2065,6 +2173,14 @@
|
||||
path = "Error Log";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D59A6B7C2AA9225C00F61259 /* Types */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D59A6B7D2AA9226C00F61259 /* AppProcess.swift */,
|
||||
);
|
||||
path = Types;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5DB145728F9DC0300A8F606 /* Errors */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -2072,10 +2188,43 @@
|
||||
D5189C002A01BC6800F44625 /* UserInfoValue.swift */,
|
||||
D51AD27C29356B7B00967AAA /* ALTWrappedError.h */,
|
||||
D51AD27D29356B7B00967AAA /* ALTWrappedError.m */,
|
||||
D5FB7A1B2AA284ED00EF863D /* ProcessError.swift */,
|
||||
D5A1D2E32AA50EB60066CACC /* JITError.swift */,
|
||||
);
|
||||
path = Errors;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5FB7A142AA284BE00EF863D /* AltJIT */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D5FB7A1E2AA284ED00EF863D /* AltJIT.swift */,
|
||||
D5FB7A382AA28AC700EF863D /* AltJIT-Bridging-Header.h */,
|
||||
D5FB7A282AA2851200EF863D /* Commands */,
|
||||
D522F9562AA509E9003E57D1 /* Types */,
|
||||
D5FB7A292AA2851C00EF863D /* Extensions */,
|
||||
);
|
||||
path = AltJIT;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5FB7A282AA2851200EF863D /* Commands */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D5FB7A1A2AA284ED00EF863D /* EnableJIT.swift */,
|
||||
D5FB7A1F2AA284ED00EF863D /* MountDisk.swift */,
|
||||
);
|
||||
path = Commands;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D5FB7A292AA2851C00EF863D /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D5FB7A1D2AA284ED00EF863D /* Logger+AltJIT.swift */,
|
||||
D5A1D2EA2AA513410066CACC /* URL+Tools.swift */,
|
||||
D5FB7A202AA284ED00EF863D /* Task+Timeout.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
@@ -2298,6 +2447,28 @@
|
||||
productReference = BFD2476A2284B9A500981D42 /* SideStore.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
D5FB7A122AA284BE00EF863D /* AltJIT */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = D5FB7A172AA284BE00EF863D /* Build configuration list for PBXNativeTarget "AltJIT" */;
|
||||
buildPhases = (
|
||||
D5FB7A0F2AA284BE00EF863D /* Sources */,
|
||||
D5FB7A102AA284BE00EF863D /* Frameworks */,
|
||||
D5FB7A112AA284BE00EF863D /* CopyFiles */,
|
||||
D52DD3602AAA89A700A7F2B6 /* Embed Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = AltJIT;
|
||||
packageProductDependencies = (
|
||||
D5FB7A2D2AA2859400EF863D /* ArgumentParser */,
|
||||
D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */,
|
||||
);
|
||||
productName = AltJIT;
|
||||
productReference = D5FB7A132AA284BE00EF863D /* altjit */;
|
||||
productType = "com.apple.product-type.tool";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -2343,6 +2514,17 @@
|
||||
};
|
||||
};
|
||||
};
|
||||
BFF7C903257844C900E55F36 = {
|
||||
CreatedOnToolsVersion = 12.3;
|
||||
LastSwiftMigration = 1230;
|
||||
};
|
||||
D586D39728EF58B0000E101F = {
|
||||
CreatedOnToolsVersion = 14.0.1;
|
||||
TestTargetID = BFD247692284B9A500981D42;
|
||||
};
|
||||
D5FB7A122AA284BE00EF863D = {
|
||||
CreatedOnToolsVersion = 15.0;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = BFD247652284B9A500981D42 /* Build configuration list for PBXProject "AltStore" */;
|
||||
@@ -2365,6 +2547,7 @@
|
||||
4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */,
|
||||
99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */,
|
||||
9922FFEA29B501C50020F868 /* XCRemoteSwiftPackageReference "Starscream" */,
|
||||
D5FB7A2C2AA2859400EF863D /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
|
||||
);
|
||||
productRefGroup = BFD2476B2284B9A500981D42 /* Products */;
|
||||
projectDirPath = "";
|
||||
@@ -2396,6 +2579,9 @@
|
||||
BF989166250AABF3002ACF50 /* AltWidgetExtension */,
|
||||
19104DB12909C06C00C49C7B /* EmotionalDamage */,
|
||||
191E5FAA290A5D92001A3B7C /* minimuxer */,
|
||||
BFF7C903257844C900E55F36 /* AltXPC */,
|
||||
D5FB7A122AA284BE00EF863D /* AltJIT */,
|
||||
D586D39728EF58B0000E101F /* AltTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -2948,6 +3134,51 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
BFF7C900257844C900E55F36 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
BFF7C9342578492100E55F36 /* ALTAnisetteData.m in Sources */,
|
||||
BFF7C920257844FA00E55F36 /* ALTPluginService.m in Sources */,
|
||||
BF77A67E25795BBE00BFE477 /* main.swift in Sources */,
|
||||
BF77A67025795A5600BFE477 /* AltXPC.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D586D39428EF58B0000E101F /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D586D39B28EF58B0000E101F /* AltTests.swift in Sources */,
|
||||
D5F5AF2E28FDD2EC00C938F5 /* TestErrors.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
D5FB7A0F2AA284BE00EF863D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
D5A1D2EB2AA513410066CACC /* URL+Tools.swift in Sources */,
|
||||
D5FB7A212AA284ED00EF863D /* EnableJIT.swift in Sources */,
|
||||
D5FB7A312AA28A2900EF863D /* NSError+AltStore.swift in Sources */,
|
||||
D59A6B7B2AA91B8E00F61259 /* PythonCommand.swift in Sources */,
|
||||
D5A1D2EC2AA51D490066CACC /* ProcessError.swift in Sources */,
|
||||
D5FB7A262AA284ED00EF863D /* MountDisk.swift in Sources */,
|
||||
D5FB7A392AA28D8300EF863D /* NSError+ALTServerError.m in Sources */,
|
||||
D5FB7A472AA293D000EF863D /* ALTErrorKeys.m in Sources */,
|
||||
D59A6B7F2AA9226C00F61259 /* AppProcess.swift in Sources */,
|
||||
D5FB7A272AA284ED00EF863D /* Task+Timeout.swift in Sources */,
|
||||
D59A6B822AA92D1C00F61259 /* Process+Conveniences.swift in Sources */,
|
||||
D5FB7A2A2AA2854100EF863D /* ALTLocalizedError.swift in Sources */,
|
||||
D5A1D2E92AA512940066CACC /* RemoteServiceDiscoveryTunnel.swift in Sources */,
|
||||
D5FB7A2B2AA2854400EF863D /* UserInfoValue.swift in Sources */,
|
||||
D5FB7A242AA284ED00EF863D /* Logger+AltJIT.swift in Sources */,
|
||||
D5A1D2E42AA50EB60066CACC /* JITError.swift in Sources */,
|
||||
D5FB7A252AA284ED00EF863D /* AltJIT.swift in Sources */,
|
||||
D5FB7A322AA28A4000EF863D /* ALTWrappedError.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
@@ -3740,6 +3971,80 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
D5FB7A182AA284BE00EF863D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 6XVY5G3U44;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
"ALTJIT=1",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/system",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.AltJIT;
|
||||
PRODUCT_NAME = altjit;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "AltJIT/AltJIT-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
D5FB7A192AA284BE00EF863D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CREATE_INFOPLIST_SECTION_IN_BINARY = YES;
|
||||
DEVELOPMENT_TEAM = 6XVY5G3U44;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"$(inherited)",
|
||||
"ALTJIT=1",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
LIBRARY_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SDKROOT)/usr/lib/system",
|
||||
);
|
||||
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 13.0;
|
||||
OTHER_SWIFT_FLAGS = "";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.AltJIT;
|
||||
PRODUCT_NAME = altjit;
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SDKROOT = macosx;
|
||||
SKIP_INSTALL = NO;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "AltJIT/AltJIT-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@@ -3824,6 +4129,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
D5FB7A172AA284BE00EF863D /* Build configuration list for PBXNativeTarget "AltJIT" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
D5FB7A182AA284BE00EF863D /* Debug */,
|
||||
D5FB7A192AA284BE00EF863D /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCRemoteSwiftPackageReference section */
|
||||
@@ -3907,6 +4221,14 @@
|
||||
minimumVersion = 4.1.0;
|
||||
};
|
||||
};
|
||||
D5FB7A2C2AA2859400EF863D /* XCRemoteSwiftPackageReference "swift-argument-parser" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/apple/swift-argument-parser.git";
|
||||
requirement = {
|
||||
kind = upToNextMinorVersion;
|
||||
minimumVersion = 1.2.3;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
@@ -3925,7 +4247,11 @@
|
||||
package = 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */;
|
||||
productName = AltSign;
|
||||
};
|
||||
4879A9612861049C00FC1BBD /* OpenSSL */ = {
|
||||
D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = "AltSign-Dynamic";
|
||||
};
|
||||
D561B2EA28EF5A4F006752E4 /* AltSign-Dynamic */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */;
|
||||
productName = OpenSSL;
|
||||
@@ -3965,6 +4291,11 @@
|
||||
package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */;
|
||||
productName = AppCenterCrashes;
|
||||
};
|
||||
D5FB7A2D2AA2859400EF863D /* ArgumentParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = D5FB7A2C2AA2859400EF863D /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
|
||||
productName = ArgumentParser;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
|
||||
101
AltStore.xcodeproj/xcshareddata/xcschemes/AltJIT.xcscheme
Normal file
101
AltStore.xcodeproj/xcshareddata/xcschemes/AltJIT.xcscheme
Normal file
@@ -0,0 +1,101 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1500"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5FB7A122AA284BE00EF863D"
|
||||
BuildableName = "altjit"
|
||||
BlueprintName = "AltJIT"
|
||||
ReferencedContainer = "container:AltStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
shouldAutocreateTestPlan = "YES">
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
debugAsWhichUser = "root"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES"
|
||||
viewDebuggingEnabled = "No">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5FB7A122AA284BE00EF863D"
|
||||
BuildableName = "altjit"
|
||||
BlueprintName = "AltJIT"
|
||||
ReferencedContainer = "container:AltStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<CommandLineArguments>
|
||||
<CommandLineArgument
|
||||
argument = "enable"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "mount"
|
||||
isEnabled = "NO">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "DolphiniOS"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "--udid"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
<CommandLineArgument
|
||||
argument = "00008030-001948590202802E"
|
||||
isEnabled = "YES">
|
||||
</CommandLineArgument>
|
||||
</CommandLineArguments>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "D5FB7A122AA284BE00EF863D"
|
||||
BuildableName = "altjit"
|
||||
BlueprintName = "AltJIT"
|
||||
ReferencedContainer = "container:AltStore.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
@@ -14,7 +14,16 @@
|
||||
#import "AltStoreCore/AltStoreCore-Swift.h"
|
||||
#endif
|
||||
|
||||
#if ALTJIT
|
||||
#import "AltJIT-Swift.h"
|
||||
@import AltSign;
|
||||
#elif TARGET_OS_OSX
|
||||
#import "AltServer-Swift.h"
|
||||
@import AltSign;
|
||||
#elif !TARGET_OS_OSX
|
||||
#import <AltStoreCore/AltStoreCore-Swift.h>
|
||||
@import AltSign;
|
||||
#endif
|
||||
|
||||
NSErrorDomain const AltServerErrorDomain = @"AltServer.ServerError";
|
||||
NSErrorDomain const AltServerInstallationErrorDomain = @"AltServer.InstallationError";
|
||||
|
||||
@@ -7,7 +7,10 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
#if !ALTJIT
|
||||
import AltSign
|
||||
#endif
|
||||
|
||||
public let ALTLocalizedTitleErrorKey = "ALTLocalizedTitle"
|
||||
public let ALTLocalizedDescriptionKey = "ALTLocalizedDescription"
|
||||
|
||||
52
Shared/Errors/JITError.swift
Normal file
52
Shared/Errors/JITError.swift
Normal file
@@ -0,0 +1,52 @@
|
||||
//
|
||||
// JITError.swift
|
||||
// AltJIT
|
||||
//
|
||||
// Created by Riley Testut on 9/3/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension JITError
|
||||
{
|
||||
enum Code: Int, ALTErrorCode
|
||||
{
|
||||
typealias Error = JITError
|
||||
|
||||
case processNotRunning
|
||||
}
|
||||
|
||||
static func processNotRunning(_ process: AppProcess, file: StaticString = #file, line: Int = #line) -> JITError {
|
||||
JITError(code: .processNotRunning, process: process, sourceFile: file, sourceLine: UInt(line))
|
||||
}
|
||||
}
|
||||
|
||||
struct JITError: ALTLocalizedError
|
||||
{
|
||||
let code: Code
|
||||
|
||||
var errorTitle: String?
|
||||
var errorFailure: String?
|
||||
|
||||
@UserInfoValue var process: AppProcess?
|
||||
|
||||
var sourceFile: StaticString?
|
||||
var sourceLine: UInt?
|
||||
|
||||
var errorFailureReason: String {
|
||||
switch self.code
|
||||
{
|
||||
case .processNotRunning:
|
||||
let targetName = self.process?.description ?? NSLocalizedString("The target app", comment: "")
|
||||
return String(format: NSLocalizedString("%@ is not running.", comment: ""), targetName)
|
||||
}
|
||||
}
|
||||
|
||||
var recoverySuggestion: String? {
|
||||
switch self.code
|
||||
{
|
||||
case .processNotRunning: return NSLocalizedString("Make sure the app is running in the foreground on your device then try again.", comment: "")
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Shared/Errors/ProcessError.swift
Normal file
88
Shared/Errors/ProcessError.swift
Normal file
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// ProcessError.swift
|
||||
// AltPackage
|
||||
//
|
||||
// Created by Riley Testut on 9/1/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension ProcessError
|
||||
{
|
||||
enum Code: Int, ALTErrorCode
|
||||
{
|
||||
typealias Error = ProcessError
|
||||
|
||||
case failed
|
||||
case timedOut
|
||||
case unexpectedOutput
|
||||
case terminated
|
||||
}
|
||||
|
||||
static func failed(executableURL: URL, exitCode: Int32, output: String?, file: StaticString = #file, line: Int = #line) -> ProcessError {
|
||||
ProcessError(code: .failed, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
|
||||
}
|
||||
|
||||
static func timedOut(executableURL: URL, exitCode: Int32? = nil, output: String? = nil, file: StaticString = #file, line: Int = #line) -> ProcessError {
|
||||
ProcessError(code: .timedOut, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
|
||||
}
|
||||
|
||||
static func unexpectedOutput(executableURL: URL, output: String, exitCode: Int32? = nil, file: StaticString = #file, line: Int = #line) -> ProcessError {
|
||||
ProcessError(code: .unexpectedOutput, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
|
||||
}
|
||||
|
||||
static func terminated(executableURL: URL, exitCode: Int32, output: String, file: StaticString = #file, line: Int = #line) -> ProcessError {
|
||||
ProcessError(code: .terminated, executableURL: executableURL, exitCode: exitCode, output: output, sourceFile: file, sourceLine: UInt(line))
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcessError: ALTLocalizedError
|
||||
{
|
||||
let code: Code
|
||||
|
||||
var errorTitle: String?
|
||||
var errorFailure: String?
|
||||
|
||||
@UserInfoValue var executableURL: URL?
|
||||
@UserInfoValue var exitCode: Int32?
|
||||
@UserInfoValue var output: String?
|
||||
|
||||
var sourceFile: StaticString?
|
||||
var sourceLine: UInt?
|
||||
|
||||
var errorFailureReason: String {
|
||||
switch self.code
|
||||
{
|
||||
case .failed:
|
||||
guard let exitCode else { return String(format: NSLocalizedString("%@ failed.", comment: ""), self.processName) }
|
||||
|
||||
let baseMessage = String(format: NSLocalizedString("%@ failed with code %@.", comment: ""), self.processName, NSNumber(value: exitCode))
|
||||
guard let lastLine = self.lastOutputLine else { return baseMessage }
|
||||
|
||||
let failureReason = baseMessage + " " + lastLine
|
||||
return failureReason
|
||||
|
||||
case .timedOut: return String(format: NSLocalizedString("%@ timed out.", comment: ""), self.processName)
|
||||
case .terminated: return String(format: NSLocalizedString("%@ unexpectedly quit.", comment: ""), self.processName)
|
||||
case .unexpectedOutput:
|
||||
let baseMessage = String(format: NSLocalizedString("%@ returned unexpected output.", comment: ""), self.processName)
|
||||
guard let lastLine = self.lastOutputLine else { return baseMessage }
|
||||
|
||||
let failureReason = baseMessage + " " + lastLine
|
||||
return failureReason
|
||||
}
|
||||
}
|
||||
|
||||
private var processName: String {
|
||||
guard let executableName = self.executableURL?.lastPathComponent else { return NSLocalizedString("The process", comment: "") }
|
||||
return String(format: NSLocalizedString("The process '%@'", comment: ""), executableName)
|
||||
}
|
||||
|
||||
private var lastOutputLine: String? {
|
||||
guard let output else { return nil }
|
||||
|
||||
let lastLine = output.components(separatedBy: .newlines).last(where: { !$0.isEmpty })
|
||||
return lastLine
|
||||
}
|
||||
}
|
||||
151
Shared/Extensions/Process+Conveniences.swift
Normal file
151
Shared/Extensions/Process+Conveniences.swift
Normal file
@@ -0,0 +1,151 @@
|
||||
//
|
||||
// Process+Conveniences.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 9/6/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import OSLog
|
||||
import Combine
|
||||
|
||||
@available(macOS 12, *)
|
||||
extension Process
|
||||
{
|
||||
// Based loosely off of https://developer.apple.com/forums/thread/690310
|
||||
class func launch(_ toolURL: URL, arguments: [String] = [], environment: [String: String] = ProcessInfo.processInfo.environment) throws -> Process
|
||||
{
|
||||
let inputPipe = Pipe()
|
||||
let outputPipe = Pipe()
|
||||
|
||||
let process = Process()
|
||||
process.executableURL = toolURL
|
||||
process.arguments = arguments
|
||||
process.environment = environment
|
||||
process.standardInput = inputPipe
|
||||
process.standardOutput = outputPipe
|
||||
process.standardError = outputPipe
|
||||
|
||||
func posixErr(_ error: Int32) -> Error { NSError(domain: NSPOSIXErrorDomain, code: Int(error), userInfo: nil) }
|
||||
|
||||
// If you write to a pipe whose remote end has closed, the OS raises a
|
||||
// `SIGPIPE` signal whose default disposition is to terminate your
|
||||
// process. Helpful! `F_SETNOSIGPIPE` disables that feature, causing
|
||||
// the write to fail with `EPIPE` instead.
|
||||
|
||||
let fcntlResult = fcntl(inputPipe.fileHandleForWriting.fileDescriptor, F_SETNOSIGPIPE, 1)
|
||||
guard fcntlResult >= 0 else { throw posixErr(errno) }
|
||||
|
||||
// Actually run the process.
|
||||
try process.run()
|
||||
|
||||
let outputTask = Task {
|
||||
do
|
||||
{
|
||||
let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: toolURL.lastPathComponent)
|
||||
|
||||
// Automatically cancels when fileHandle closes.
|
||||
for try await line in outputPipe.fileHandleForReading.bytes.lines
|
||||
{
|
||||
process.output += line + "\n"
|
||||
process.outputPublisher.send(line)
|
||||
|
||||
logger.notice("\(line, privacy: .public)")
|
||||
}
|
||||
|
||||
try Task.checkCancellation()
|
||||
process.outputPublisher.send(completion: .finished)
|
||||
}
|
||||
catch let error as CancellationError
|
||||
{
|
||||
process.outputPublisher.send(completion: .failure(error))
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.main.error("Failed to read process output. \(error.localizedDescription, privacy: .public)")
|
||||
|
||||
try Task.checkCancellation()
|
||||
process.outputPublisher.send(completion: .failure(error))
|
||||
}
|
||||
}
|
||||
|
||||
process.terminationHandler = { process in
|
||||
Logger.main.notice("Process \(toolURL, privacy: .public) terminated with exit code \(process.terminationStatus).")
|
||||
|
||||
outputTask.cancel()
|
||||
process.outputPublisher.send(completion: .finished)
|
||||
}
|
||||
|
||||
return process
|
||||
}
|
||||
|
||||
class func launchAndWait(_ toolURL: URL, arguments: [String] = [], environment: [String: String] = ProcessInfo.processInfo.environment) async throws -> String
|
||||
{
|
||||
let process = try self.launch(toolURL, arguments: arguments, environment: environment)
|
||||
|
||||
await withCheckedContinuation { (continuation: CheckedContinuation<Void, Never>) in
|
||||
let previousHandler = process.terminationHandler
|
||||
process.terminationHandler = { process in
|
||||
previousHandler?(process)
|
||||
continuation.resume()
|
||||
}
|
||||
}
|
||||
|
||||
guard process.terminationStatus == 0 else {
|
||||
throw ProcessError.failed(executableURL: toolURL, exitCode: process.terminationStatus, output: process.output)
|
||||
}
|
||||
|
||||
return process.output
|
||||
}
|
||||
}
|
||||
|
||||
@available(macOS 12, *)
|
||||
extension Process
|
||||
{
|
||||
private static var outputKey: Int = 0
|
||||
private static var publisherKey: Int = 0
|
||||
|
||||
fileprivate(set) var output: String {
|
||||
get {
|
||||
let output = objc_getAssociatedObject(self, &Process.outputKey) as? String ?? ""
|
||||
return output
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &Process.outputKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
|
||||
}
|
||||
}
|
||||
|
||||
// Should be type-erased, but oh well.
|
||||
var outputLines: AsyncThrowingPublisher<some Publisher<String, Error>> {
|
||||
return self.outputPublisher
|
||||
.buffer(size: 100, prefetch: .byRequest, whenFull: .dropOldest)
|
||||
.values
|
||||
}
|
||||
|
||||
private var outputPublisher: PassthroughSubject<String, Error> {
|
||||
if let publisher = objc_getAssociatedObject(self, &Process.publisherKey) as? PassthroughSubject<String, Error>
|
||||
{
|
||||
return publisher
|
||||
}
|
||||
|
||||
let publisher = PassthroughSubject<String, Error>()
|
||||
objc_setAssociatedObject(self, &Process.publisherKey, publisher, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
return publisher
|
||||
}
|
||||
|
||||
// We must manually close outputPipe in order for us to read a second Process' standardOutput via async-await 🤷♂️
|
||||
func stopOutput()
|
||||
{
|
||||
guard let outputPipe = self.standardOutput as? Pipe else { return }
|
||||
|
||||
do
|
||||
{
|
||||
try outputPipe.fileHandleForReading.close()
|
||||
}
|
||||
catch
|
||||
{
|
||||
Logger.main.error("Failed to close \(self.executableURL?.lastPathComponent ?? "process", privacy: .public)'s standardOutput. \(error.localizedDescription, privacy: .public)")
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Shared/Types/AppProcess.swift
Normal file
35
Shared/Types/AppProcess.swift
Normal file
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// AppProcess.swift
|
||||
// AltStore
|
||||
//
|
||||
// Created by Riley Testut on 9/6/23.
|
||||
// Copyright © 2023 Riley Testut. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum AppProcess: CustomStringConvertible
|
||||
{
|
||||
case name(String)
|
||||
case pid(Int)
|
||||
|
||||
var description: String {
|
||||
switch self
|
||||
{
|
||||
case .name(let name): return name
|
||||
case .pid(let pid): return "Process \(pid)"
|
||||
}
|
||||
}
|
||||
|
||||
init(_ value: String)
|
||||
{
|
||||
if let pid = Int(value)
|
||||
{
|
||||
self = .pid(pid)
|
||||
}
|
||||
else
|
||||
{
|
||||
self = .name(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user