[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:
Riley Testut
2023-09-07 18:00:53 -05:00
committed by Magesh K
parent f83303a6b7
commit a7b28d5027
19 changed files with 1539 additions and 1 deletions

View 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
View 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])
}

View 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
}
}

View 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
}
}
}

View 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")
}

View 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()
// Weve 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
}
}

View 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")
}

View 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;

View 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";

View 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
}
}

View 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)"
}
}

View File

@@ -355,9 +355,12 @@
D51AD27F29356B7B00967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; }; D51AD27F29356B7B00967AAA /* ALTWrappedError.m in Sources */ = {isa = PBXBuildFile; fileRef = D51AD27D29356B7B00967AAA /* ALTWrappedError.m */; };
D51AD28029356B8000967AAA /* 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 */; }; 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 */; }; 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, ); }; }; 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 */; }; 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 */; }; D53D84022A2158FC00543C3B /* Permissions.plist in Resources */ = {isa = PBXBuildFile; fileRef = D53D84012A2158FC00543C3B /* Permissions.plist */; };
D54058B92A1D6269008CCC58 /* AppPermissionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54058B82A1D6269008CCC58 /* AppPermissionProtocol.swift */; }; D54058B92A1D6269008CCC58 /* AppPermissionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54058B82A1D6269008CCC58 /* AppPermissionProtocol.swift */; };
D54058BB2A1D8FE3008CCC58 /* UIColor+AltStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54058BA2A1D8FE3008CCC58 /* UIColor+AltStore.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 */; }; D5935AED29C39DE300C157EF /* SourceDetailsComponents.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5935AEC29C39DE300C157EF /* SourceDetailsComponents.swift */; };
D5935AEF29C3B23600C157EF /* Sources.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5935AEE29C3B23600C157EF /* Sources.storyboard */; }; D5935AEF29C3B23600C157EF /* Sources.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D5935AEE29C3B23600C157EF /* Sources.storyboard */; };
D593F1942717749A006E82DE /* PatchAppOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D593F1932717749A006E82DE /* PatchAppOperation.swift */; }; 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 */; }; 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 */; }; D5A2193429B14F94002229FC /* DeprecatedAPIs.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A2193329B14F94002229FC /* DeprecatedAPIs.swift */; };
D5ACE84528E3B8450021CAB9 /* ClearAppCacheOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */; }; D5ACE84528E3B8450021CAB9 /* ClearAppCacheOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5ACE84428E3B8450021CAB9 /* ClearAppCacheOperation.swift */; };
D5CA0C4B280E141900469595 /* ManagedPatron.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5CA0C4A280E141900469595 /* ManagedPatron.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 */; }; D5F99A1828D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1728D11DB500476A16 /* AltStore10ToAltStore11.xcmappingmodel */; };
D5F99A1A28D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */; }; D5F99A1A28D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F99A1928D12B1400476A16 /* StoreApp10ToStoreApp11Policy.swift */; };
D5FB7A0E2AA25A4E00EF863D /* Previews.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D5FB7A0D2AA25A4E00EF863D /* Previews.xcassets */; }; 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 */; }; D5FD4EC52A952EAD0097BEE8 /* AltWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FD4EC42A952EAD0097BEE8 /* AltWidgetBundle.swift */; };
D5FD4EC92A9530C00097BEE8 /* AppSnapshot.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FD4EC82A9530C00097BEE8 /* AppSnapshot.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 */; }; D5FD4ECB2A9532960097BEE8 /* DatabaseManager+Async.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5FD4ECA2A9532960097BEE8 /* DatabaseManager+Async.swift */; };
@@ -546,6 +569,13 @@
remoteGlobalIDString = BF66EE7D2501AE50007EE018; remoteGlobalIDString = BF66EE7D2501AE50007EE018;
remoteInfo = AltStoreCore; remoteInfo = AltStoreCore;
}; };
D537C8562AA94D4A009A1E08 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = BFD247622284B9A500981D42 /* Project object */;
proxyType = 1;
remoteGlobalIDString = D5FB7A122AA284BE00EF863D;
remoteInfo = AltJIT;
};
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -572,6 +602,28 @@
name = "Embed Foundation Extensions"; name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0; 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 */ = { D561B2EC28EF5A4F006752E4 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@@ -583,6 +635,15 @@
name = "Embed Frameworks"; name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
D5FB7A112AA284BE00EF863D /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = /usr/share/man/man1/;
dstSubfolderSpec = 0;
files = (
);
runOnlyForDeploymentPostprocessing = 1;
};
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@@ -935,6 +996,7 @@
D533E8B82727B61400A9B5DD /* fragmentzip.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = fragmentzip.h; sourceTree = "<group>"; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; D5FD4ECA2A9532960097BEE8 /* DatabaseManager+Async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DatabaseManager+Async.swift"; sourceTree = "<group>"; };
@@ -1087,6 +1165,16 @@
); );
runOnlyForDeploymentPostprocessing = 0; 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 */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
@@ -1249,6 +1337,7 @@
0EE7FDBF2BE8BBBF00D1E390 /* Errors */, 0EE7FDBF2BE8BBBF00D1E390 /* Errors */,
BFF767C32489A6800097E58C /* Extensions */, BFF767C32489A6800097E58C /* Extensions */,
BFF767C42489A6980097E58C /* Categories */, BFF767C42489A6980097E58C /* Categories */,
D59A6B7C2AA9225C00F61259 /* Types */,
); );
path = Shared; path = Shared;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1722,6 +1811,9 @@
19104DB32909C06D00C49C7B /* EmotionalDamage */, 19104DB32909C06D00C49C7B /* EmotionalDamage */,
191E5FAC290A5D92001A3B7C /* minimuxer */, 191E5FAC290A5D92001A3B7C /* minimuxer */,
B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */, B343F886295F7F9B002B1159 /* libfragmentzip.xcodeproj */,
BFF7C905257844C900E55F36 /* AltXPC */,
D5FB7A142AA284BE00EF863D /* AltJIT */,
D586D39928EF58B0000E101F /* AltTests */,
BFD247852284BB3300981D42 /* Frameworks */, BFD247852284BB3300981D42 /* Frameworks */,
B3146EC6284F580500BBC3FD /* Roxas.xcodeproj */, B3146EC6284F580500BBC3FD /* Roxas.xcodeproj */,
BFD2476B2284B9A500981D42 /* Products */, BFD2476B2284B9A500981D42 /* Products */,
@@ -1740,6 +1832,9 @@
BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */, BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */,
19104DB22909C06C00C49C7B /* libEmotionalDamage.a */, 19104DB22909C06C00C49C7B /* libEmotionalDamage.a */,
191E5FAB290A5D92001A3B7C /* libminimuxer.a */, 191E5FAB290A5D92001A3B7C /* libminimuxer.a */,
BFF7C904257844C900E55F36 /* AltXPC.xpc */,
D586D39828EF58B0000E101F /* AltTests.xctest */,
D5FB7A132AA284BE00EF863D /* altjit */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1782,6 +1877,7 @@
children = ( children = (
B343F86C295F759E002B1159 /* libresolv.tbd */, B343F86C295F759E002B1159 /* libresolv.tbd */,
B39575F4284F29E20080B4FF /* Roxas.framework */, B39575F4284F29E20080B4FF /* Roxas.framework */,
D537C85A2AA95066009A1E08 /* libcorecrypto.tbd */,
D533E8B62727841800A9B5DD /* libAppleArchive.tbd */, D533E8B62727841800A9B5DD /* libAppleArchive.tbd */,
BF580497246A3D19008AE704 /* UIKit.framework */, BF580497246A3D19008AE704 /* UIKit.framework */,
BF4588872298DD3F00BD7491 /* libxml2.tbd */, BF4588872298DD3F00BD7491 /* libxml2.tbd */,
@@ -1940,6 +2036,7 @@
BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */, BFF435D7255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift */,
BF6C336124197D700034FD24 /* NSError+AltStore.swift */, BF6C336124197D700034FD24 /* NSError+AltStore.swift */,
D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */, D5708416292448DA00D42D34 /* OperatingSystemVersion+Comparable.swift */,
D59A6B802AA92D1C00F61259 /* Process+Conveniences.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -2011,6 +2108,17 @@
path = Model; path = Model;
sourceTree = "<group>"; 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 */ = { D54058B72A1D6251008CCC58 /* Previews */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -2065,6 +2173,14 @@
path = "Error Log"; path = "Error Log";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D59A6B7C2AA9225C00F61259 /* Types */ = {
isa = PBXGroup;
children = (
D59A6B7D2AA9226C00F61259 /* AppProcess.swift */,
);
path = Types;
sourceTree = "<group>";
};
D5DB145728F9DC0300A8F606 /* Errors */ = { D5DB145728F9DC0300A8F606 /* Errors */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -2072,10 +2188,43 @@
D5189C002A01BC6800F44625 /* UserInfoValue.swift */, D5189C002A01BC6800F44625 /* UserInfoValue.swift */,
D51AD27C29356B7B00967AAA /* ALTWrappedError.h */, D51AD27C29356B7B00967AAA /* ALTWrappedError.h */,
D51AD27D29356B7B00967AAA /* ALTWrappedError.m */, D51AD27D29356B7B00967AAA /* ALTWrappedError.m */,
D5FB7A1B2AA284ED00EF863D /* ProcessError.swift */,
D5A1D2E32AA50EB60066CACC /* JITError.swift */,
); );
path = Errors; path = Errors;
sourceTree = "<group>"; 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 */ /* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */ /* Begin PBXHeadersBuildPhase section */
@@ -2298,6 +2447,28 @@
productReference = BFD2476A2284B9A500981D42 /* SideStore.app */; productReference = BFD2476A2284B9A500981D42 /* SideStore.app */;
productType = "com.apple.product-type.application"; 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 */ /* End PBXNativeTarget section */
/* Begin PBXProject 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" */; buildConfigurationList = BFD247652284B9A500981D42 /* Build configuration list for PBXProject "AltStore" */;
@@ -2365,6 +2547,7 @@
4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */, 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */,
99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */, 99C4EF472978D52400CB538D /* XCRemoteSwiftPackageReference "SemanticVersion" */,
9922FFEA29B501C50020F868 /* XCRemoteSwiftPackageReference "Starscream" */, 9922FFEA29B501C50020F868 /* XCRemoteSwiftPackageReference "Starscream" */,
D5FB7A2C2AA2859400EF863D /* XCRemoteSwiftPackageReference "swift-argument-parser" */,
); );
productRefGroup = BFD2476B2284B9A500981D42 /* Products */; productRefGroup = BFD2476B2284B9A500981D42 /* Products */;
projectDirPath = ""; projectDirPath = "";
@@ -2396,6 +2579,9 @@
BF989166250AABF3002ACF50 /* AltWidgetExtension */, BF989166250AABF3002ACF50 /* AltWidgetExtension */,
19104DB12909C06C00C49C7B /* EmotionalDamage */, 19104DB12909C06C00C49C7B /* EmotionalDamage */,
191E5FAA290A5D92001A3B7C /* minimuxer */, 191E5FAA290A5D92001A3B7C /* minimuxer */,
BFF7C903257844C900E55F36 /* AltXPC */,
D5FB7A122AA284BE00EF863D /* AltJIT */,
D586D39728EF58B0000E101F /* AltTests */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@@ -2948,6 +3134,51 @@
); );
runOnlyForDeploymentPostprocessing = 0; 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 */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
@@ -3740,6 +3971,80 @@
}; };
name = Release; 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 */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
@@ -3824,6 +4129,15 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
D5FB7A172AA284BE00EF863D /* Build configuration list for PBXNativeTarget "AltJIT" */ = {
isa = XCConfigurationList;
buildConfigurations = (
D5FB7A182AA284BE00EF863D /* Debug */,
D5FB7A192AA284BE00EF863D /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
@@ -3907,6 +4221,14 @@
minimumVersion = 4.1.0; 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 */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
@@ -3925,7 +4247,11 @@
package = 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */; package = 4879A95D2861046500FC1BBD /* XCRemoteSwiftPackageReference "AltSign" */;
productName = AltSign; productName = AltSign;
}; };
4879A9612861049C00FC1BBD /* OpenSSL */ = { D52DD35D2AAA89A600A7F2B6 /* AltSign-Dynamic */ = {
isa = XCSwiftPackageProductDependency;
productName = "AltSign-Dynamic";
};
D561B2EA28EF5A4F006752E4 /* AltSign-Dynamic */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */; package = 4879A9602861049C00FC1BBD /* XCRemoteSwiftPackageReference "OpenSSL" */;
productName = OpenSSL; productName = OpenSSL;
@@ -3965,6 +4291,11 @@
package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */; package = B3C395F5284F362400DA9E2F /* XCRemoteSwiftPackageReference "appcenter-sdk-apple" */;
productName = AppCenterCrashes; productName = AppCenterCrashes;
}; };
D5FB7A2D2AA2859400EF863D /* ArgumentParser */ = {
isa = XCSwiftPackageProductDependency;
package = D5FB7A2C2AA2859400EF863D /* XCRemoteSwiftPackageReference "swift-argument-parser" */;
productName = ArgumentParser;
};
/* End XCSwiftPackageProductDependency section */ /* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */ /* Begin XCVersionGroup section */

View 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>

View File

@@ -14,7 +14,16 @@
#import "AltStoreCore/AltStoreCore-Swift.h" #import "AltStoreCore/AltStoreCore-Swift.h"
#endif #endif
#if ALTJIT
#import "AltJIT-Swift.h"
@import AltSign; @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 AltServerErrorDomain = @"AltServer.ServerError";
NSErrorDomain const AltServerInstallationErrorDomain = @"AltServer.InstallationError"; NSErrorDomain const AltServerInstallationErrorDomain = @"AltServer.InstallationError";

View File

@@ -7,7 +7,10 @@
// //
import Foundation import Foundation
#if !ALTJIT
import AltSign import AltSign
#endif
public let ALTLocalizedTitleErrorKey = "ALTLocalizedTitle" public let ALTLocalizedTitleErrorKey = "ALTLocalizedTitle"
public let ALTLocalizedDescriptionKey = "ALTLocalizedDescription" public let ALTLocalizedDescriptionKey = "ALTLocalizedDescription"

View 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: "")
}
}
}

View 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
}
}

View 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)")
}
}
}

View 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)
}
}
}