mirror of
https://github.com/StikDebug/StikDebug.git
synced 2026-10-16 04:20:30 +00:00
Replace lockdown code with rppairing (#354)
This commit is contained in:
parent
f8697a0b83
commit
c780843105
25 changed files with 1706 additions and 568 deletions
|
|
@ -5,7 +5,6 @@
|
|||
#include "idevice/JITEnableContext.h"
|
||||
#import "Utilities/ProcessInspectorBridge.h"
|
||||
#include "idevice/idevice.h"
|
||||
#include "idevice/heartbeat.h"
|
||||
#include "JSSupport/JSSupport.h"
|
||||
#include "idevice/ideviceinfo.h"
|
||||
#include "idevice/location_simulation.h"
|
||||
|
|
|
|||
|
|
@ -117,17 +117,17 @@ class DNSChecker: ObservableObject {
|
|||
|
||||
// MARK: - Main App
|
||||
|
||||
// Global state variable for the heartbeat response.
|
||||
var pubHeartBeat = false
|
||||
private var heartbeatStartPending = false
|
||||
private var heartbeatStartInProgress = false
|
||||
private var heartbeatPendingShowUI = true
|
||||
// Global state variable for the tunnel connection.
|
||||
var pubTunnelConnected = false
|
||||
private var tunnelStartPending = false
|
||||
private var tunnelStartInProgress = false
|
||||
private var tunnelPendingShowUI = true
|
||||
|
||||
@main
|
||||
struct HeartbeatApp: App {
|
||||
@StateObject private var mount = MountingProgress.shared
|
||||
@Environment(\.scenePhase) private var scenePhase // Observe scene lifecycle
|
||||
@State private var shouldAttemptHeartbeatRestart = false
|
||||
@State private var shouldAttemptTunnelReconnect = false
|
||||
|
||||
init() {
|
||||
registerAdvancedOptionsDefault()
|
||||
|
|
@ -144,11 +144,11 @@ struct HeartbeatApp: App {
|
|||
private func handleScenePhaseChange(_ newPhase: ScenePhase) {
|
||||
switch newPhase {
|
||||
case .background:
|
||||
shouldAttemptHeartbeatRestart = true
|
||||
shouldAttemptTunnelReconnect = true
|
||||
case .active:
|
||||
if shouldAttemptHeartbeatRestart {
|
||||
shouldAttemptHeartbeatRestart = false
|
||||
startHeartbeatInBackground(showErrorUI: false)
|
||||
if shouldAttemptTunnelReconnect {
|
||||
shouldAttemptTunnelReconnect = false
|
||||
startTunnelInBackground(showErrorUI: false)
|
||||
}
|
||||
default:
|
||||
break
|
||||
|
|
@ -270,42 +270,42 @@ class MountingProgress: ObservableObject {
|
|||
|
||||
func isPairing() -> Bool {
|
||||
let pairingpath = URL.documentsDirectory.appendingPathComponent("pairingFile.plist").path
|
||||
var pairingFile: IdevicePairingFile?
|
||||
let err = idevice_pairing_file_read(pairingpath, &pairingFile)
|
||||
var pairingFile: RpPairingFileHandle?
|
||||
let err = rp_pairing_file_read(pairingpath, &pairingFile)
|
||||
if err != nil { return false }
|
||||
idevice_pairing_file_free(pairingFile)
|
||||
rp_pairing_file_free(pairingFile)
|
||||
return true
|
||||
}
|
||||
|
||||
func startHeartbeatInBackground(showErrorUI: Bool = true) {
|
||||
assert(Thread.isMainThread, "startHeartbeatInBackground must be called on the main thread")
|
||||
func startTunnelInBackground(showErrorUI: Bool = true) {
|
||||
assert(Thread.isMainThread, "startTunnelInBackground must be called on the main thread")
|
||||
let pairingFileURL = URL.documentsDirectory.appendingPathComponent("pairingFile.plist")
|
||||
|
||||
|
||||
guard FileManager.default.fileExists(atPath: pairingFileURL.path) else {
|
||||
heartbeatStartPending = false
|
||||
heartbeatPendingShowUI = true
|
||||
tunnelStartPending = false
|
||||
tunnelPendingShowUI = true
|
||||
return
|
||||
}
|
||||
|
||||
guard !heartbeatStartInProgress else {
|
||||
|
||||
guard !tunnelStartInProgress else {
|
||||
return
|
||||
}
|
||||
|
||||
heartbeatStartPending = false
|
||||
heartbeatPendingShowUI = true
|
||||
heartbeatStartInProgress = true
|
||||
|
||||
|
||||
tunnelStartPending = false
|
||||
tunnelPendingShowUI = true
|
||||
tunnelStartInProgress = true
|
||||
|
||||
DispatchQueue.global(qos: .userInteractive).async {
|
||||
defer {
|
||||
DispatchQueue.main.async {
|
||||
heartbeatStartInProgress = false
|
||||
tunnelStartInProgress = false
|
||||
}
|
||||
}
|
||||
do {
|
||||
try JITEnableContext.shared.startHeartbeat()
|
||||
LogManager.shared.addInfoLog("Heartbeat started successfully")
|
||||
pubHeartBeat = true
|
||||
|
||||
try JITEnableContext.shared.startTunnel()
|
||||
LogManager.shared.addInfoLog("Tunnel connected successfully")
|
||||
pubTunnelConnected = true
|
||||
|
||||
DispatchQueue.main.async {
|
||||
let trustcachePath = URL.documentsDirectory.appendingPathComponent("DDI/Image.dmg.trustcache").path
|
||||
guard FileManager.default.fileExists(atPath: trustcachePath),
|
||||
|
|
@ -326,7 +326,7 @@ func startHeartbeatInBackground(showErrorUI: Bool = true) {
|
|||
} catch {
|
||||
LogManager.shared.addErrorLog("Failed to remove invalid pairing file: \(error.localizedDescription)")
|
||||
}
|
||||
|
||||
|
||||
showAlert(
|
||||
title: "Invalid Pairing File",
|
||||
message: "The pairing file is invalid or expired. Please select a new pairing file.",
|
||||
|
|
@ -338,14 +338,14 @@ func startHeartbeatInBackground(showErrorUI: Bool = true) {
|
|||
}
|
||||
} else {
|
||||
showAlert(
|
||||
title: "Heartbeat Error",
|
||||
title: "Connection Error",
|
||||
message: "\(error.localizedDescription)\n\nMake sure Wi‑Fi and LocalDevVPN are connected and that the device is reachable.",
|
||||
showOk: false,
|
||||
showTryAgain: true
|
||||
) { shouldTryAgain in
|
||||
if shouldTryAgain {
|
||||
DispatchQueue.main.async {
|
||||
startHeartbeatInBackground()
|
||||
startTunnelInBackground()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ final class DeviceInfoManager: ObservableObject {
|
|||
busy = true
|
||||
Task.detached {
|
||||
do {
|
||||
try JITEnableContext.shared.ensureHeartbeat()
|
||||
try JITEnableContext.shared.ensureTunnel()
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
self.error = ("Initialization Failed", error.localizedDescription)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ struct InstalledAppQuery: EntityStringQuery {
|
|||
}
|
||||
|
||||
func suggestedEntities() async throws -> [InstalledAppEntity] {
|
||||
await ensureHeartbeat()
|
||||
await ensureTunnel()
|
||||
let allApps = (try? JITEnableContext.shared.getAppList()) ?? [:]
|
||||
return allApps.map { InstalledAppEntity(id: $0.key, displayName: $0.value) }
|
||||
.sorted { $0.displayName.localizedCaseInsensitiveCompare($1.displayName) == .orderedAscending }
|
||||
|
|
@ -94,7 +94,7 @@ struct RunningProcessEntity: AppEntity {
|
|||
struct RunningProcessQuery: EntityStringQuery {
|
||||
func entities(for identifiers: [String]) async throws -> [RunningProcessEntity] {
|
||||
// Always fetch fresh so PIDs are current
|
||||
await ensureHeartbeat()
|
||||
await ensureTunnel()
|
||||
let all = try fetchProcessEntities()
|
||||
let idSet = Set(identifiers)
|
||||
return all.filter { idSet.contains($0.id) }
|
||||
|
|
@ -112,7 +112,7 @@ struct RunningProcessQuery: EntityStringQuery {
|
|||
}
|
||||
|
||||
func suggestedEntities() async throws -> [RunningProcessEntity] {
|
||||
await ensureHeartbeat()
|
||||
await ensureTunnel()
|
||||
return try fetchProcessEntities()
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ struct EnableJITIntent: AppIntent, ForegroundContinuableIntent {
|
|||
return .result(value: "Select an app to enable JIT for.")
|
||||
}
|
||||
|
||||
await ensureHeartbeat()
|
||||
await ensureTunnel()
|
||||
|
||||
var scriptData: Data? = nil
|
||||
var scriptName: String? = nil
|
||||
|
|
@ -250,9 +250,9 @@ struct KillProcessIntent: AppIntent {
|
|||
if let pid {
|
||||
targetPID = pid
|
||||
targetName = "PID \(pid)"
|
||||
await ensureHeartbeat()
|
||||
await ensureTunnel()
|
||||
} else if let process {
|
||||
await ensureHeartbeat()
|
||||
await ensureTunnel()
|
||||
|
||||
// Always re-resolve to get the current PID — the stored one may be stale
|
||||
guard let resolved = process.resolveCurrentPID() else {
|
||||
|
|
@ -313,12 +313,12 @@ struct StikDebugShortcuts: AppShortcutsProvider {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: - Shared Heartbeat Helper
|
||||
// MARK: - Shared Tunnel Helper
|
||||
|
||||
func ensureHeartbeat() async {
|
||||
func ensureTunnel() async {
|
||||
await MainActor.run {
|
||||
pubHeartBeat = false
|
||||
startHeartbeatInBackground(showErrorUI: false)
|
||||
pubTunnelConnected = false
|
||||
startTunnelInBackground(showErrorUI: false)
|
||||
}
|
||||
try? await Task.sleep(nanoseconds: 1_000_000_000)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,9 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
typealias IdevicePairingFile = OpaquePointer
|
||||
typealias TcpProviderHandle = OpaquePointer
|
||||
typealias CoreDeviceProxyHandle = OpaquePointer
|
||||
typealias RpPairingFileHandle = OpaquePointer
|
||||
typealias AdapterHandle = OpaquePointer
|
||||
typealias RsdHandshakeHandle = OpaquePointer
|
||||
typealias ImageMounterHandle = OpaquePointer
|
||||
typealias LockdowndClientHandle = OpaquePointer
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ struct HomeView: View {
|
|||
startJITInBackground(bundleID: selectedBundle)
|
||||
}, showDoneButton: false, onImportPairingFile: { isShowingPairingFilePicker = true })
|
||||
.onAppear {
|
||||
startHeartbeatInBackground()
|
||||
startTunnelInBackground()
|
||||
MountingProgress.shared.checkforMounted()
|
||||
viewDidAppeared = true
|
||||
if let config = pendingJITEnableConfiguration {
|
||||
|
|
@ -94,8 +94,8 @@ struct HomeView: View {
|
|||
}
|
||||
case "kill-process":
|
||||
if let pidStr = components?.queryItems?.first(where: { $0.name == "pid" })?.value, let pid = Int(pidStr) {
|
||||
pubHeartBeat = false
|
||||
startHeartbeatInBackground(showErrorUI: false)
|
||||
pubTunnelConnected = false
|
||||
startTunnelInBackground(showErrorUI: false)
|
||||
DispatchQueue.global(qos: .userInitiated).async {
|
||||
sleep(1)
|
||||
do {
|
||||
|
|
@ -133,10 +133,10 @@ struct HomeView: View {
|
|||
try fileManager.removeItem(at: dest)
|
||||
}
|
||||
try fileManager.copyItem(at: url, to: dest)
|
||||
pubHeartBeat = false
|
||||
startHeartbeatInBackground()
|
||||
pubTunnelConnected = false
|
||||
startTunnelInBackground()
|
||||
NotificationCenter.default.post(name: .pairingFileImported, object: nil)
|
||||
// Dismiss any existing heartbeat error alert
|
||||
// Dismiss any existing connection error alert
|
||||
if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
||||
let root = scene.windows.first?.rootViewController {
|
||||
var top = root
|
||||
|
|
@ -268,8 +268,8 @@ struct HomeView: View {
|
|||
BackgroundLocationManager.shared.requestStart()
|
||||
|
||||
if triggeredByURLScheme {
|
||||
pubHeartBeat = false
|
||||
startHeartbeatInBackground(showErrorUI: false)
|
||||
pubTunnelConnected = false
|
||||
startTunnelInBackground(showErrorUI: false)
|
||||
}
|
||||
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ struct SettingsView: View {
|
|||
|
||||
RunLoop.current.add(progressTimer, forMode: .common)
|
||||
DispatchQueue.main.async {
|
||||
startHeartbeatInBackground()
|
||||
startTunnelInBackground()
|
||||
}
|
||||
|
||||
} catch { }
|
||||
|
|
|
|||
|
|
@ -8,35 +8,35 @@
|
|||
@import UIKit;
|
||||
#include "idevice.h"
|
||||
#include "jit.h"
|
||||
#include "heartbeat.h"
|
||||
#include "mount.h"
|
||||
|
||||
typedef void (^HeartbeatCompletionHandler)(int result, NSString *message);
|
||||
typedef void (^LogFuncC)(const char* message, ...);
|
||||
typedef void (^LogFunc)(NSString *message);
|
||||
typedef void (^SyslogLineHandler)(NSString *line);
|
||||
typedef void (^SyslogErrorHandler)(NSError *error);
|
||||
|
||||
@interface JITEnableContext : NSObject {
|
||||
// tunnel
|
||||
@protected AdapterHandle *adapter;
|
||||
@protected RsdHandshakeHandle *handshake;
|
||||
|
||||
// process
|
||||
@protected dispatch_queue_t processInspectorQueue;
|
||||
@protected IdeviceProviderHandle* provider;
|
||||
|
||||
|
||||
// syslog
|
||||
@protected dispatch_queue_t syslogQueue;
|
||||
@protected BOOL syslogStreaming;
|
||||
@protected SyslogRelayClientHandle *syslogClient;
|
||||
@protected SyslogLineHandler syslogLineHandler;
|
||||
@protected SyslogErrorHandler syslogErrorHandler;
|
||||
|
||||
|
||||
// ideviceInfo
|
||||
@protected LockdowndClientHandle * g_client;
|
||||
}
|
||||
@property (class, readonly)JITEnableContext* shared;
|
||||
- (IdevicePairingFile*)getPairingFileWithError:(NSError**)error;
|
||||
- (IdeviceProviderHandle*)getTcpProviderHandle;
|
||||
- (BOOL)ensureHeartbeatWithError:(NSError**)err;
|
||||
- (BOOL)startHeartbeat:(NSError**)err;
|
||||
- (RpPairingFileHandle*)getPairingFileWithError:(NSError**)error;
|
||||
- (BOOL)ensureTunnelWithError:(NSError**)err;
|
||||
- (BOOL)startTunnel:(NSError**)err;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@
|
|||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "heartbeat.h"
|
||||
#include "jit.h"
|
||||
#include "applist.h"
|
||||
#include "profiles.h"
|
||||
|
|
@ -21,13 +20,11 @@
|
|||
|
||||
static JITEnableContext* sharedJITContext = nil;
|
||||
|
||||
@implementation JITEnableContext {
|
||||
int heartbeatToken;
|
||||
NSError* lastHeartbeatError;
|
||||
os_unfair_lock heartbeatLock;
|
||||
BOOL heartbeatRunning;
|
||||
dispatch_semaphore_t heartbeatSemaphore;
|
||||
|
||||
@implementation JITEnableContext {
|
||||
NSError* lastTunnelError;
|
||||
os_unfair_lock tunnelLock;
|
||||
BOOL tunnelConnecting;
|
||||
dispatch_semaphore_t tunnelSemaphore;
|
||||
}
|
||||
|
||||
+ (instancetype)shared {
|
||||
|
|
@ -48,12 +45,11 @@ static JITEnableContext* sharedJITContext = nil;
|
|||
syslogClient = NULL;
|
||||
dispatch_queue_attr_t qosAttr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0);
|
||||
processInspectorQueue = dispatch_queue_create("com.stikdebug.processInspector", qosAttr);
|
||||
|
||||
heartbeatToken = 0;
|
||||
heartbeatLock = OS_UNFAIR_LOCK_INIT;
|
||||
heartbeatRunning = NO;
|
||||
heartbeatSemaphore = NULL;
|
||||
lastHeartbeatError = nil;
|
||||
|
||||
tunnelLock = OS_UNFAIR_LOCK_INIT;
|
||||
tunnelConnecting = NO;
|
||||
tunnelSemaphore = NULL;
|
||||
lastTunnelError = nil;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
|
@ -88,7 +84,7 @@ static JITEnableContext* sharedJITContext = nil;
|
|||
};
|
||||
}
|
||||
|
||||
- (IdevicePairingFile*)getPairingFileWithError:(NSError**)error {
|
||||
- (RpPairingFileHandle*)getPairingFileWithError:(NSError**)error {
|
||||
NSFileManager* fm = [NSFileManager defaultManager];
|
||||
NSURL* docPathUrl = [fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask].firstObject;
|
||||
NSURL* pairingFileURL = [docPathUrl URLByAppendingPathComponent:@"pairingFile.plist"];
|
||||
|
|
@ -98,112 +94,108 @@ static JITEnableContext* sharedJITContext = nil;
|
|||
return nil;
|
||||
}
|
||||
|
||||
IdevicePairingFile* pairingFile = NULL;
|
||||
IdeviceFfiError* err = idevice_pairing_file_read(pairingFileURL.fileSystemRepresentation, &pairingFile);
|
||||
RpPairingFileHandle* pairingFile = NULL;
|
||||
IdeviceFfiError* err = rp_pairing_file_read(pairingFileURL.fileSystemRepresentation, &pairingFile);
|
||||
if (err) {
|
||||
*error = [self errorWithStr:@"Failed to read pairing file!" code:err->code];
|
||||
idevice_error_free(err);
|
||||
return nil;
|
||||
}
|
||||
return pairingFile;
|
||||
}
|
||||
|
||||
- (IdeviceProviderHandle*)getTcpProviderHandle {
|
||||
return provider;
|
||||
}
|
||||
- (BOOL)startTunnel:(NSError**)err {
|
||||
os_unfair_lock_lock(&tunnelLock);
|
||||
|
||||
// If tunnel is already being created, wait for it to complete
|
||||
if (tunnelConnecting) {
|
||||
dispatch_semaphore_t waitSemaphore = tunnelSemaphore;
|
||||
os_unfair_lock_unlock(&tunnelLock);
|
||||
|
||||
// only block until first heartbeat is completed or failed.
|
||||
- (BOOL)startHeartbeat:(NSError**)err {
|
||||
os_unfair_lock_lock(&heartbeatLock);
|
||||
|
||||
// If heartbeat is already running, wait for it to complete
|
||||
if (heartbeatRunning) {
|
||||
dispatch_semaphore_t waitSemaphore = heartbeatSemaphore;
|
||||
os_unfair_lock_unlock(&heartbeatLock);
|
||||
|
||||
if (waitSemaphore) {
|
||||
dispatch_semaphore_wait(waitSemaphore, DISPATCH_TIME_FOREVER);
|
||||
dispatch_semaphore_signal(waitSemaphore);
|
||||
}
|
||||
*err = lastHeartbeatError;
|
||||
*err = lastTunnelError;
|
||||
return *err == nil;
|
||||
}
|
||||
|
||||
// Mark heartbeat as running
|
||||
heartbeatRunning = YES;
|
||||
heartbeatSemaphore = dispatch_semaphore_create(0);
|
||||
dispatch_semaphore_t completionSemaphore = heartbeatSemaphore;
|
||||
os_unfair_lock_unlock(&heartbeatLock);
|
||||
|
||||
IdevicePairingFile* pairingFile = [self getPairingFileWithError:err];
|
||||
|
||||
// Mark tunnel as connecting
|
||||
tunnelConnecting = YES;
|
||||
tunnelSemaphore = dispatch_semaphore_create(0);
|
||||
dispatch_semaphore_t completionSemaphore = tunnelSemaphore;
|
||||
os_unfair_lock_unlock(&tunnelLock);
|
||||
|
||||
RpPairingFileHandle* pairingFile = [self getPairingFileWithError:err];
|
||||
if (*err) {
|
||||
os_unfair_lock_lock(&heartbeatLock);
|
||||
heartbeatRunning = NO;
|
||||
heartbeatSemaphore = NULL;
|
||||
os_unfair_lock_unlock(&heartbeatLock);
|
||||
os_unfair_lock_lock(&tunnelLock);
|
||||
tunnelConnecting = NO;
|
||||
tunnelSemaphore = NULL;
|
||||
os_unfair_lock_unlock(&tunnelLock);
|
||||
dispatch_semaphore_signal(completionSemaphore);
|
||||
return NO;
|
||||
}
|
||||
|
||||
globalHeartbeatToken++;
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
__block bool completionCalled = false;
|
||||
HeartbeatCompletionHandlerC Ccompletion = ^(int result, const char *message) {
|
||||
if(completionCalled) {
|
||||
return;
|
||||
}
|
||||
if (result != 0) {
|
||||
*err = [self errorWithStr:[NSString stringWithCString:message
|
||||
encoding:NSASCIIStringEncoding] code:result];
|
||||
self->lastHeartbeatError = *err;
|
||||
} else {
|
||||
self->lastHeartbeatError = nil;
|
||||
}
|
||||
completionCalled = true;
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(49152);
|
||||
|
||||
dispatch_semaphore_signal(semaphore);
|
||||
};
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
startHeartbeat(
|
||||
pairingFile,
|
||||
&self->provider,
|
||||
globalHeartbeatToken,Ccompletion
|
||||
);
|
||||
});
|
||||
// allow 5 seconds for heartbeat, otherwise we declare timeout
|
||||
intptr_t isTimeout = dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(5 * NSEC_PER_SEC)));
|
||||
if(isTimeout) {
|
||||
Ccompletion(-1, "Heartbeat failed to complete in reasonable time.");
|
||||
NSString* deviceIP = [[NSUserDefaults standardUserDefaults] stringForKey:@"customTargetIP"];
|
||||
inet_pton(AF_INET, (deviceIP && deviceIP.length > 0) ? [deviceIP UTF8String] : "10.7.0.1", &addr.sin_addr);
|
||||
|
||||
AdapterHandle *newAdapter = NULL;
|
||||
RsdHandshakeHandle *newHandshake = NULL;
|
||||
IdeviceFfiError *ffiErr = tunnel_create_rppairing(
|
||||
(const idevice_sockaddr *)&addr,
|
||||
sizeof(addr),
|
||||
"StikDebug",
|
||||
pairingFile,
|
||||
NULL,
|
||||
NULL,
|
||||
&newAdapter,
|
||||
&newHandshake
|
||||
);
|
||||
rp_pairing_file_free(pairingFile);
|
||||
|
||||
if (ffiErr) {
|
||||
*err = [self errorWithStr:[NSString stringWithUTF8String:ffiErr->message ?: "Failed to create tunnel"]
|
||||
code:ffiErr->code];
|
||||
lastTunnelError = *err;
|
||||
idevice_error_free(ffiErr);
|
||||
} else {
|
||||
// Clean up old tunnel if any
|
||||
if (handshake) { rsd_handshake_free(handshake); }
|
||||
if (adapter) { adapter_free(adapter); }
|
||||
adapter = newAdapter;
|
||||
handshake = newHandshake;
|
||||
lastTunnelError = nil;
|
||||
}
|
||||
|
||||
os_unfair_lock_lock(&heartbeatLock);
|
||||
heartbeatRunning = NO;
|
||||
heartbeatSemaphore = NULL;
|
||||
os_unfair_lock_unlock(&heartbeatLock);
|
||||
os_unfair_lock_lock(&tunnelLock);
|
||||
tunnelConnecting = NO;
|
||||
tunnelSemaphore = NULL;
|
||||
os_unfair_lock_unlock(&tunnelLock);
|
||||
dispatch_semaphore_signal(completionSemaphore);
|
||||
|
||||
|
||||
return *err == nil;
|
||||
}
|
||||
|
||||
- (BOOL)ensureHeartbeatWithError:(NSError**)err {
|
||||
// if it's 15s after last heartbeat, we restart heartbeat.
|
||||
if((!lastHeartbeatDate || [[NSDate now] timeIntervalSinceDate:lastHeartbeatDate] > 15)) {
|
||||
return [self startHeartbeat:err];
|
||||
- (BOOL)ensureTunnelWithError:(NSError**)err {
|
||||
if (!adapter || !handshake) {
|
||||
return [self startTunnel:err];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
[self stopSyslogRelay];
|
||||
if (provider) {
|
||||
idevice_provider_free(provider);
|
||||
if (handshake) {
|
||||
rsd_handshake_free(handshake);
|
||||
}
|
||||
if (adapter) {
|
||||
adapter_free(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@
|
|||
@import Foundation;
|
||||
@import UIKit;
|
||||
|
||||
NSDictionary<NSString*, NSString*>* list_installed_apps(IdeviceProviderHandle* provider, NSString** error);
|
||||
NSDictionary<NSString*, NSString*>* list_all_apps(IdeviceProviderHandle* provider, NSString** error);
|
||||
NSDictionary<NSString*, NSString*>* list_hidden_system_apps(IdeviceProviderHandle* provider, NSString** error);
|
||||
UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSString** error);
|
||||
NSDictionary<NSString*, NSString*>* list_installed_apps(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString** error);
|
||||
NSDictionary<NSString*, NSString*>* list_all_apps(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString** error);
|
||||
NSDictionary<NSString*, NSString*>* list_hidden_system_apps(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString** error);
|
||||
UIImage* getAppIcon(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString* bundleID, NSString** error);
|
||||
|
||||
#endif /* APPLIST_H */
|
||||
|
|
|
|||
|
|
@ -149,10 +149,11 @@ static NSDictionary<NSString*, NSString*> *buildAppDictionary(void *apps,
|
|||
return result;
|
||||
}
|
||||
|
||||
static NSArray<NSDictionary*>* getSideloadedApps(IdeviceProviderHandle *provider,
|
||||
static NSArray<NSDictionary*>* getSideloadedApps(AdapterHandle *adapter,
|
||||
RsdHandshakeHandle *handshake,
|
||||
NSString **error) {
|
||||
InstallationProxyClientHandle *client = NULL;
|
||||
IdeviceFfiError* err = installation_proxy_connect(provider, &client);
|
||||
IdeviceFfiError* err = installation_proxy_connect_rsd(adapter, handshake, &client);
|
||||
if (err) {
|
||||
*error = [NSString stringWithFormat:@"Failed to connect to installation proxy: %s", err->message];
|
||||
idevice_error_free(err);
|
||||
|
|
@ -208,13 +209,14 @@ static NSArray<NSDictionary*>* getSideloadedApps(IdeviceProviderHandle *provider
|
|||
return result;
|
||||
}
|
||||
|
||||
static NSDictionary<NSString*, NSString*> *performAppQuery(IdeviceProviderHandle *provider,
|
||||
static NSDictionary<NSString*, NSString*> *performAppQuery(AdapterHandle *adapter,
|
||||
RsdHandshakeHandle *handshake,
|
||||
BOOL requireGetTaskAllow,
|
||||
NSString **error,
|
||||
BOOL (^filter)(plist_t app))
|
||||
{
|
||||
InstallationProxyClientHandle *client = NULL;
|
||||
IdeviceFfiError* err = installation_proxy_connect(provider, &client);
|
||||
IdeviceFfiError* err = installation_proxy_connect_rsd(adapter, handshake, &client);
|
||||
if (err) {
|
||||
*error = [NSString stringWithFormat:@"Failed to connect to installation proxy: %s", err->message];
|
||||
idevice_error_free(err);
|
||||
|
|
@ -240,23 +242,23 @@ static NSDictionary<NSString*, NSString*> *performAppQuery(IdeviceProviderHandle
|
|||
return result;
|
||||
}
|
||||
|
||||
NSDictionary<NSString*, NSString*>* list_installed_apps(IdeviceProviderHandle* provider, NSString** error) {
|
||||
return performAppQuery(provider, YES, error, nil);
|
||||
NSDictionary<NSString*, NSString*>* list_installed_apps(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString** error) {
|
||||
return performAppQuery(adapter, handshake, YES, error, nil);
|
||||
}
|
||||
|
||||
NSDictionary<NSString*, NSString*>* list_all_apps(IdeviceProviderHandle* provider, NSString** error) {
|
||||
return performAppQuery(provider, NO, error, nil);
|
||||
NSDictionary<NSString*, NSString*>* list_all_apps(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString** error) {
|
||||
return performAppQuery(adapter, handshake, NO, error, nil);
|
||||
}
|
||||
|
||||
NSDictionary<NSString*, NSString*>* list_hidden_system_apps(IdeviceProviderHandle* provider, NSString** error) {
|
||||
return performAppQuery(provider, NO, error, ^BOOL(plist_t app) {
|
||||
NSDictionary<NSString*, NSString*>* list_hidden_system_apps(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString** error) {
|
||||
return performAppQuery(adapter, handshake, NO, error, ^BOOL(plist_t app) {
|
||||
return isHiddenSystemApp(app);
|
||||
});
|
||||
}
|
||||
|
||||
UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSString** error) {
|
||||
UIImage* getAppIcon(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString* bundleID, NSString** error) {
|
||||
SpringBoardServicesClientHandle *client = NULL;
|
||||
IdeviceFfiError *err = springboard_services_connect(provider, &client);
|
||||
IdeviceFfiError *err = springboard_services_connect_rsd(adapter, handshake, &client);
|
||||
if (err) {
|
||||
*error = [NSString stringWithUTF8String:err->message ?: "Failed to connect to SpringBoard Services"];
|
||||
idevice_error_free(err);
|
||||
|
|
@ -284,13 +286,13 @@ UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSStrin
|
|||
@implementation JITEnableContext(App)
|
||||
|
||||
- (NSDictionary<NSString*, NSString*>*)getAppListWithError:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* errorStr = nil;
|
||||
NSDictionary<NSString*, NSString*>* apps = list_installed_apps(provider, &errorStr);
|
||||
NSDictionary<NSString*, NSString*>* apps = list_installed_apps(adapter, handshake, &errorStr);
|
||||
if (errorStr) {
|
||||
*error = [self errorWithStr:errorStr code:-17];
|
||||
return nil;
|
||||
|
|
@ -299,13 +301,13 @@ UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSStrin
|
|||
}
|
||||
|
||||
- (NSDictionary<NSString*, NSString*>*)getAllAppsWithError:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* errorStr = nil;
|
||||
NSDictionary<NSString*, NSString*>* apps = list_all_apps(provider, &errorStr);
|
||||
NSDictionary<NSString*, NSString*>* apps = list_all_apps(adapter, handshake, &errorStr);
|
||||
if (errorStr) {
|
||||
*error = [self errorWithStr:errorStr code:-17];
|
||||
return nil;
|
||||
|
|
@ -314,13 +316,13 @@ UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSStrin
|
|||
}
|
||||
|
||||
- (NSDictionary<NSString*, NSString*>*)getHiddenSystemAppsWithError:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* errorStr = nil;
|
||||
NSDictionary<NSString*, NSString*>* apps = list_hidden_system_apps(provider, &errorStr);
|
||||
NSDictionary<NSString*, NSString*>* apps = list_hidden_system_apps(adapter, handshake, &errorStr);
|
||||
if (errorStr) {
|
||||
*error = [self errorWithStr:errorStr code:-17];
|
||||
return nil;
|
||||
|
|
@ -329,13 +331,13 @@ UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSStrin
|
|||
}
|
||||
|
||||
- (NSArray<NSDictionary*>*)getSideloadedAppsWithError:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* errorStr = nil;
|
||||
NSArray<NSDictionary*>* apps = getSideloadedApps(provider, &errorStr);
|
||||
NSArray<NSDictionary*>* apps = getSideloadedApps(adapter, handshake, &errorStr);
|
||||
if (errorStr) {
|
||||
*error = [self errorWithStr:errorStr code:-17];
|
||||
return nil;
|
||||
|
|
@ -344,13 +346,13 @@ UIImage* getAppIcon(IdeviceProviderHandle* provider, NSString* bundleID, NSStrin
|
|||
}
|
||||
|
||||
- (UIImage*)getAppIconWithBundleId:(NSString*)bundleId error:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString* errorStr = nil;
|
||||
UIImage* icon = getAppIcon(provider, bundleId, &errorStr);
|
||||
UIImage* icon = getAppIcon(adapter, handshake, bundleId, &errorStr);
|
||||
if (errorStr) {
|
||||
*error = [self errorWithStr:errorStr code:-17];
|
||||
return nil;
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// heartbeat.h
|
||||
// StikJIT
|
||||
//
|
||||
// Created by Stephen on 3/27/25.
|
||||
//
|
||||
|
||||
// heartbeat.h
|
||||
#ifndef HEARTBEAT_H
|
||||
#define HEARTBEAT_H
|
||||
#include "idevice.h"
|
||||
@import Foundation;
|
||||
|
||||
typedef void (^HeartbeatCompletionHandlerC)(int result, const char *message);
|
||||
typedef void (^LogFuncC)(const char* message, ...);
|
||||
|
||||
extern int globalHeartbeatToken;
|
||||
extern NSDate* lastHeartbeatDate;
|
||||
|
||||
void startHeartbeat(IdevicePairingFile* pairing_file, IdeviceProviderHandle** provider, int heartbeatToken, HeartbeatCompletionHandlerC completion);
|
||||
#endif /* HEARTBEAT_H */
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
// Jackson Coxson
|
||||
// heartbeat.c
|
||||
|
||||
#include "idevice.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/_types/_u_int64_t.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <limits.h>
|
||||
#include "heartbeat.h"
|
||||
#include <pthread.h>
|
||||
@import Foundation;
|
||||
|
||||
int globalHeartbeatToken = 0;
|
||||
NSDate* lastHeartbeatDate = nil;
|
||||
|
||||
void startHeartbeat(IdevicePairingFile* pairing_file, IdeviceProviderHandle** provider, int heartbeatToken, HeartbeatCompletionHandlerC completion) {
|
||||
IdeviceProviderHandle* newProvider = *provider;
|
||||
IdeviceFfiError* err = nil;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(LOCKDOWN_PORT);
|
||||
|
||||
NSString* deviceIP = [[NSUserDefaults standardUserDefaults] stringForKey:@"customTargetIP"];
|
||||
inet_pton(AF_INET, (deviceIP && deviceIP.length > 0) ? [deviceIP UTF8String] : "10.7.0.1", &addr.sin_addr);
|
||||
|
||||
err = idevice_tcp_provider_new((struct sockaddr *)&addr, pairing_file,
|
||||
"ExampleProvider", &newProvider);
|
||||
if (err != NULL) {
|
||||
completion(err->code, err->message);
|
||||
idevice_pairing_file_free(pairing_file);
|
||||
idevice_error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
HeartbeatClientHandle *client = NULL;
|
||||
err = heartbeat_connect(newProvider, &client);
|
||||
if (err != NULL) {
|
||||
completion(err->code, err->message);
|
||||
idevice_provider_free(newProvider);
|
||||
idevice_error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
*provider = newProvider;
|
||||
|
||||
bool completionCalled = false;
|
||||
u_int64_t current_interval = 15;
|
||||
|
||||
while (1) {
|
||||
u_int64_t new_interval = 0;
|
||||
err = heartbeat_get_marco(client, current_interval, &new_interval);
|
||||
if (err != NULL) {
|
||||
if (!completionCalled) {
|
||||
completion(err->code, err->message);
|
||||
}
|
||||
heartbeat_client_free(client);
|
||||
idevice_error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// If a newer heartbeat thread has started, yield to it
|
||||
if (heartbeatToken != globalHeartbeatToken) {
|
||||
heartbeat_client_free(client);
|
||||
return;
|
||||
}
|
||||
|
||||
current_interval = new_interval + 5;
|
||||
|
||||
err = heartbeat_send_polo(client);
|
||||
if (err != NULL) {
|
||||
if (!completionCalled) {
|
||||
completion(err->code, err->message);
|
||||
}
|
||||
heartbeat_client_free(client);
|
||||
idevice_error_free(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastHeartbeatDate && [[NSDate now] timeIntervalSinceDate:lastHeartbeatDate] > current_interval) {
|
||||
lastHeartbeatDate = nil;
|
||||
return;
|
||||
}
|
||||
lastHeartbeatDate = [NSDate now];
|
||||
|
||||
if (!completionCalled) {
|
||||
completion(0, "Heartbeat succeeded");
|
||||
completionCalled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -14,25 +14,16 @@
|
|||
@import Foundation;
|
||||
|
||||
NSError* makeError(int code, NSString* msg);
|
||||
LockdowndClientHandle* ideviceinfo_c_init(IdeviceProviderHandle* g_provider, IdevicePairingFile* g_sess_pf, NSError** error) {
|
||||
LockdowndClientHandle* ideviceinfo_c_init(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSError** error) {
|
||||
LockdowndClientHandle *g_client = NULL;
|
||||
IdeviceFfiError *err = lockdownd_connect(g_provider, &g_client);
|
||||
IdeviceFfiError *err = lockdownd_connect_rsd(adapter, handshake, &g_client);
|
||||
if (err) {
|
||||
*error = makeError(err->code, @(err->message));
|
||||
idevice_pairing_file_free(g_sess_pf);
|
||||
idevice_error_free(err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = lockdownd_start_session(g_client, g_sess_pf);
|
||||
idevice_pairing_file_free(g_sess_pf);
|
||||
if (err) {
|
||||
*error = makeError(err->code, @(err->message));
|
||||
idevice_error_free(err);
|
||||
lockdownd_client_free(g_client);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// No session start needed - RSD tunnel handles authentication
|
||||
return g_client;
|
||||
}
|
||||
|
||||
|
|
@ -62,15 +53,13 @@ char *ideviceinfo_c_get_xml(LockdowndClientHandle* g_client, NSError** error) {
|
|||
@implementation JITEnableContext(DeviceInfo)
|
||||
|
||||
- (LockdowndClientHandle*)ideviceInfoInit:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return nil; }
|
||||
IdevicePairingFile *pf = [self getPairingFileWithError:error];
|
||||
if (*error) { return nil; }
|
||||
return ideviceinfo_c_init(provider, pf, error);
|
||||
return ideviceinfo_c_init(adapter, handshake, error);
|
||||
}
|
||||
|
||||
- (char*)ideviceInfoGetXMLWithLockdownClient:(LockdowndClientHandle*)lockdownClient error:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return NULL; }
|
||||
return ideviceinfo_c_get_xml(lockdownClient, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,14 +9,15 @@
|
|||
#ifndef JIT_H
|
||||
#define JIT_H
|
||||
#include "idevice.h"
|
||||
#include <dispatch/dispatch.h>
|
||||
|
||||
typedef void (^LogFuncC)(const char* message, ...);
|
||||
typedef void (^DebugAppCallback)(int pid,
|
||||
struct DebugProxyHandle* debug_proxy,
|
||||
struct RemoteServerHandle* remote_server,
|
||||
dispatch_semaphore_t semaphore);
|
||||
int debug_app(IdeviceProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger, DebugAppCallback callback);
|
||||
int debug_app_pid(IdeviceProviderHandle* tcp_provider, int pid, LogFuncC logger, DebugAppCallback callback);
|
||||
int launch_app_via_proxy(IdeviceProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger);
|
||||
int debug_app(AdapterHandle* adapter, RsdHandshakeHandle* handshake, const char *bundle_id, LogFuncC logger, DebugAppCallback callback);
|
||||
int debug_app_pid(AdapterHandle* adapter, RsdHandshakeHandle* handshake, int pid, LogFuncC logger, DebugAppCallback callback);
|
||||
int launch_app_via_proxy(AdapterHandle* adapter, RsdHandshakeHandle* handshake, const char *bundle_id, LogFuncC logger);
|
||||
|
||||
#endif /* JIT_H */
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
// MARK: - Shared debug session
|
||||
|
||||
typedef struct {
|
||||
AdapterHandle *adapter;
|
||||
RsdHandshakeHandle *handshake;
|
||||
RemoteServerHandle *remote_server;
|
||||
DebugProxyHandle *debug_proxy;
|
||||
} DebugSession;
|
||||
|
|
@ -32,40 +30,18 @@ typedef struct {
|
|||
static void debug_session_free(DebugSession *s) {
|
||||
if (s->debug_proxy) { debug_proxy_free(s->debug_proxy); s->debug_proxy = NULL; }
|
||||
if (s->remote_server) { remote_server_free(s->remote_server); s->remote_server = NULL; }
|
||||
if (s->handshake) { rsd_handshake_free(s->handshake); s->handshake = NULL; }
|
||||
if (s->adapter) { adapter_free(s->adapter); s->adapter = NULL; }
|
||||
}
|
||||
|
||||
// Connects to the device, performs the RSD handshake, and sets up the debug proxy.
|
||||
// Connects to the device using the existing adapter+handshake and sets up the debug proxy.
|
||||
// Returns 0 on success; cleans up any partial state and returns 1 on failure.
|
||||
static int connect_debug_session(IdeviceProviderHandle *tcp_provider, DebugSession *out) {
|
||||
static int connect_debug_session(AdapterHandle *adapter, RsdHandshakeHandle *handshake, DebugSession *out) {
|
||||
memset(out, 0, sizeof(*out));
|
||||
IdeviceFfiError *err = NULL;
|
||||
|
||||
CoreDeviceProxyHandle *core_device = NULL;
|
||||
err = core_device_proxy_connect(tcp_provider, &core_device);
|
||||
err = remote_server_connect_rsd(adapter, handshake, &out->remote_server);
|
||||
if (err) { idevice_error_free(err); return 1; }
|
||||
|
||||
uint16_t rsd_port = 0;
|
||||
err = core_device_proxy_get_server_rsd_port(core_device, &rsd_port);
|
||||
if (err) { idevice_error_free(err); core_device_proxy_free(core_device); return 1; }
|
||||
|
||||
err = core_device_proxy_create_tcp_adapter(core_device, &out->adapter);
|
||||
if (err) { idevice_error_free(err); core_device_proxy_free(core_device); return 1; }
|
||||
core_device = NULL; // ownership transferred to adapter
|
||||
|
||||
AdapterStreamHandle *stream = NULL;
|
||||
err = adapter_connect(out->adapter, rsd_port, (ReadWriteOpaque **)&stream);
|
||||
if (err) { idevice_error_free(err); debug_session_free(out); return 1; }
|
||||
|
||||
err = rsd_handshake_new((ReadWriteOpaque *)stream, &out->handshake);
|
||||
if (err) { idevice_error_free(err); adapter_close(stream); debug_session_free(out); return 1; }
|
||||
stream = NULL; // consumed by handshake
|
||||
|
||||
err = remote_server_connect_rsd(out->adapter, out->handshake, &out->remote_server);
|
||||
if (err) { idevice_error_free(err); debug_session_free(out); return 1; }
|
||||
|
||||
err = debug_proxy_connect_rsd(out->adapter, out->handshake, &out->debug_proxy);
|
||||
err = debug_proxy_connect_rsd(adapter, handshake, &out->debug_proxy);
|
||||
if (err) { idevice_error_free(err); debug_session_free(out); return 1; }
|
||||
|
||||
return 0;
|
||||
|
|
@ -137,9 +113,9 @@ void runDebugServerCommand(int pid,
|
|||
|
||||
// MARK: - Public entry points
|
||||
|
||||
int debug_app(IdeviceProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger, DebugAppCallback callback) {
|
||||
int debug_app(AdapterHandle* adapter, RsdHandshakeHandle* handshake, const char *bundle_id, LogFuncC logger, DebugAppCallback callback) {
|
||||
DebugSession session;
|
||||
if (connect_debug_session(tcp_provider, &session) != 0) return 1;
|
||||
if (connect_debug_session(adapter, handshake, &session) != 0) return 1;
|
||||
|
||||
ProcessControlHandle *process_control = NULL;
|
||||
IdeviceFfiError *err = process_control_new(session.remote_server, &process_control);
|
||||
|
|
@ -166,9 +142,9 @@ int debug_app(IdeviceProviderHandle* tcp_provider, const char *bundle_id, LogFun
|
|||
return 0;
|
||||
}
|
||||
|
||||
int debug_app_pid(IdeviceProviderHandle* tcp_provider, int pid, LogFuncC logger, DebugAppCallback callback) {
|
||||
int debug_app_pid(AdapterHandle* adapter, RsdHandshakeHandle* handshake, int pid, LogFuncC logger, DebugAppCallback callback) {
|
||||
DebugSession session;
|
||||
if (connect_debug_session(tcp_provider, &session) != 0) return 1;
|
||||
if (connect_debug_session(adapter, handshake, &session) != 0) return 1;
|
||||
|
||||
runDebugServerCommand(pid, session.debug_proxy, session.remote_server, logger, callback);
|
||||
|
||||
|
|
@ -177,36 +153,14 @@ int debug_app_pid(IdeviceProviderHandle* tcp_provider, int pid, LogFuncC logger,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int launch_app_via_proxy(IdeviceProviderHandle* tcp_provider, const char *bundle_id, LogFuncC logger) {
|
||||
int launch_app_via_proxy(AdapterHandle* adapter, RsdHandshakeHandle* handshake, const char *bundle_id, LogFuncC logger) {
|
||||
IdeviceFfiError* err = NULL;
|
||||
|
||||
CoreDeviceProxyHandle *core_device = NULL;
|
||||
AdapterHandle *adapter = NULL;
|
||||
AdapterStreamHandle *stream = NULL;
|
||||
RsdHandshakeHandle *handshake = NULL;
|
||||
RemoteServerHandle *remote_server = NULL;
|
||||
ProcessControlHandle *process_control = NULL;
|
||||
uint64_t pid = 0;
|
||||
int result = 1;
|
||||
|
||||
err = core_device_proxy_connect(tcp_provider, &core_device);
|
||||
if (err) { idevice_error_free(err); goto cleanup; }
|
||||
|
||||
uint16_t rsd_port = 0;
|
||||
err = core_device_proxy_get_server_rsd_port(core_device, &rsd_port);
|
||||
if (err) { idevice_error_free(err); goto cleanup; }
|
||||
|
||||
err = core_device_proxy_create_tcp_adapter(core_device, &adapter);
|
||||
if (err) { idevice_error_free(err); goto cleanup; }
|
||||
core_device = NULL; // ownership transferred to adapter
|
||||
|
||||
err = adapter_connect(adapter, rsd_port, (ReadWriteOpaque **)&stream);
|
||||
if (err) { idevice_error_free(err); goto cleanup; }
|
||||
|
||||
err = rsd_handshake_new((ReadWriteOpaque *)stream, &handshake);
|
||||
if (err) { idevice_error_free(err); goto cleanup; }
|
||||
stream = NULL; // consumed by handshake/adapter stack
|
||||
|
||||
err = remote_server_connect_rsd(adapter, handshake, &remote_server);
|
||||
if (err) { idevice_error_free(err); goto cleanup; }
|
||||
|
||||
|
|
@ -226,10 +180,6 @@ int launch_app_via_proxy(IdeviceProviderHandle* tcp_provider, const char *bundle
|
|||
cleanup:
|
||||
if (process_control) process_control_free(process_control);
|
||||
if (remote_server) remote_server_free(remote_server);
|
||||
if (handshake) rsd_handshake_free(handshake);
|
||||
if (stream) adapter_close(stream);
|
||||
if (adapter) adapter_free(adapter);
|
||||
if (core_device) core_device_proxy_free(core_device);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -238,32 +188,32 @@ cleanup:
|
|||
|
||||
- (BOOL)debugAppWithBundleID:(NSString*)bundleID logger:(LogFunc)logger jsCallback:(DebugAppCallback)jsCallback {
|
||||
NSError* err = nil;
|
||||
[self ensureHeartbeatWithError:&err];
|
||||
[self ensureTunnelWithError:&err];
|
||||
if (err) {
|
||||
logger(err.localizedDescription);
|
||||
return NO;
|
||||
}
|
||||
return debug_app(provider, [bundleID UTF8String], [self createCLogger:logger], jsCallback) == 0;
|
||||
return debug_app(adapter, handshake, [bundleID UTF8String], [self createCLogger:logger], jsCallback) == 0;
|
||||
}
|
||||
|
||||
- (BOOL)debugAppWithPID:(int)pid logger:(LogFunc)logger jsCallback:(DebugAppCallback)jsCallback {
|
||||
NSError* err = nil;
|
||||
[self ensureHeartbeatWithError:&err];
|
||||
[self ensureTunnelWithError:&err];
|
||||
if (err) {
|
||||
logger(err.localizedDescription);
|
||||
return NO;
|
||||
}
|
||||
return debug_app_pid(provider, pid, [self createCLogger:logger], jsCallback) == 0;
|
||||
return debug_app_pid(adapter, handshake, pid, [self createCLogger:logger], jsCallback) == 0;
|
||||
}
|
||||
|
||||
- (BOOL)launchAppWithoutDebug:(NSString*)bundleID logger:(LogFunc)logger {
|
||||
NSError* err = nil;
|
||||
[self ensureHeartbeatWithError:&err];
|
||||
[self ensureTunnelWithError:&err];
|
||||
if (err) {
|
||||
logger(err.localizedDescription);
|
||||
return NO;
|
||||
}
|
||||
return launch_app_via_proxy(provider, [bundleID UTF8String], [self createCLogger:logger]) == 0;
|
||||
return launch_app_via_proxy(adapter, handshake, [bundleID UTF8String], [self createCLogger:logger]) == 0;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -13,9 +13,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static IdevicePairingFile *g_pairing = NULL;
|
||||
static IdeviceProviderHandle *g_provider = NULL;
|
||||
static CoreDeviceProxyHandle *g_core_device = NULL;
|
||||
static AdapterHandle *g_adapter = NULL;
|
||||
static RsdHandshakeHandle *g_handshake = NULL;
|
||||
static RemoteServerHandle *g_remote_server = NULL;
|
||||
|
|
@ -26,9 +23,6 @@ static void cleanup_on_error(void) {
|
|||
if (g_remote_server) { remote_server_free(g_remote_server); g_remote_server = NULL; }
|
||||
if (g_handshake) { rsd_handshake_free(g_handshake); g_handshake = NULL; }
|
||||
if (g_adapter) { adapter_free(g_adapter); g_adapter = NULL; }
|
||||
if (g_core_device) { core_device_proxy_free(g_core_device); g_core_device = NULL; }
|
||||
if (g_provider) { idevice_provider_free(g_provider); g_provider = NULL; }
|
||||
if (g_pairing) { idevice_pairing_file_free(g_pairing); g_pairing = NULL; }
|
||||
}
|
||||
|
||||
int simulate_location(const char *device_ip,
|
||||
|
|
@ -37,7 +31,7 @@ int simulate_location(const char *device_ip,
|
|||
const char *pairing_file)
|
||||
{
|
||||
IdeviceFfiError *err = NULL;
|
||||
|
||||
|
||||
if (g_location_sim) {
|
||||
if ((err = location_simulation_set(g_location_sim, latitude, longitude))) {
|
||||
idevice_error_free(err);
|
||||
|
|
@ -53,68 +47,28 @@ int simulate_location(const char *device_ip,
|
|||
return IPA_ERR_INVALID_IP;
|
||||
}
|
||||
|
||||
if (g_pairing) {
|
||||
idevice_pairing_file_free(g_pairing);
|
||||
g_pairing = NULL;
|
||||
}
|
||||
|
||||
if ((err = idevice_pairing_file_read(pairing_file, &g_pairing))) {
|
||||
RpPairingFileHandle *rp_pairing = NULL;
|
||||
if ((err = rp_pairing_file_read(pairing_file, &rp_pairing))) {
|
||||
idevice_error_free(err);
|
||||
return IPA_ERR_PAIRING_READ;
|
||||
}
|
||||
|
||||
if ((err = idevice_tcp_provider_new((struct sockaddr *)&addr,
|
||||
g_pairing,
|
||||
"LocationSimCLI",
|
||||
&g_provider)))
|
||||
if ((err = tunnel_create_rppairing(
|
||||
(const idevice_sockaddr *)&addr,
|
||||
sizeof(addr),
|
||||
"StikDebugLocation",
|
||||
rp_pairing,
|
||||
NULL,
|
||||
NULL,
|
||||
&g_adapter,
|
||||
&g_handshake)))
|
||||
{
|
||||
idevice_error_free(err);
|
||||
rp_pairing_file_free(rp_pairing);
|
||||
cleanup_on_error();
|
||||
return IPA_ERR_PROVIDER_CREATE;
|
||||
}
|
||||
|
||||
if ((err = core_device_proxy_connect(g_provider, &g_core_device))) {
|
||||
idevice_error_free(err);
|
||||
cleanup_on_error();
|
||||
return IPA_ERR_CORE_DEVICE;
|
||||
}
|
||||
idevice_provider_free(g_provider);
|
||||
g_provider = NULL;
|
||||
|
||||
uint16_t rsd_port;
|
||||
if ((err = core_device_proxy_get_server_rsd_port(g_core_device,
|
||||
&rsd_port)))
|
||||
{
|
||||
idevice_error_free(err);
|
||||
cleanup_on_error();
|
||||
return IPA_ERR_RSD_PORT;
|
||||
}
|
||||
|
||||
if ((err = core_device_proxy_create_tcp_adapter(g_core_device,
|
||||
&g_adapter)))
|
||||
{
|
||||
idevice_error_free(err);
|
||||
cleanup_on_error();
|
||||
return IPA_ERR_ADAPTER_CREATE;
|
||||
}
|
||||
// core_device_proxy_create_tcp_adapter takes ownership of g_core_device
|
||||
// (Rust moves it into the adapter). Null the pointer so cleanup_on_error
|
||||
// does not attempt a second free.
|
||||
g_core_device = NULL;
|
||||
|
||||
AdapterStreamHandle *stream = NULL;
|
||||
if ((err = adapter_connect(g_adapter, rsd_port, (ReadWriteOpaque **)&stream))) {
|
||||
idevice_error_free(err);
|
||||
cleanup_on_error();
|
||||
return IPA_ERR_STREAM;
|
||||
}
|
||||
|
||||
if ((err = rsd_handshake_new((ReadWriteOpaque *)stream, &g_handshake))) {
|
||||
idevice_error_free(err);
|
||||
adapter_stream_close(stream);
|
||||
cleanup_on_error();
|
||||
return IPA_ERR_HANDSHAKE;
|
||||
}
|
||||
rp_pairing_file_free(rp_pairing);
|
||||
|
||||
if ((err = remote_server_connect_rsd(g_adapter,
|
||||
g_handshake,
|
||||
|
|
@ -124,9 +78,6 @@ int simulate_location(const char *device_ip,
|
|||
cleanup_on_error();
|
||||
return IPA_ERR_REMOTE_SERVER;
|
||||
}
|
||||
// remote_server_connect_rsd takes ownership of g_adapter and g_handshake.
|
||||
g_adapter = NULL;
|
||||
g_handshake = NULL;
|
||||
|
||||
if ((err = location_simulation_new(g_remote_server,
|
||||
&g_location_sim))) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@
|
|||
#define MOUNT_H
|
||||
#include "idevice.h"
|
||||
#include <Foundation/Foundation.h>
|
||||
size_t getMountedDeviceCount(IdeviceProviderHandle* provider, NSError** error);
|
||||
int mountPersonalDDI(IdeviceProviderHandle* provider, IdevicePairingFile* pairingFile2, NSString* imagePath, NSString* trustcachePath, NSString* manifestPath, NSError** error);
|
||||
size_t getMountedDeviceCount(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSError** error);
|
||||
int mountPersonalDDI(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString* imagePath, NSString* trustcachePath, NSString* manifestPath, NSError** error);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
|
||||
NSError* makeError(int code, NSString* msg);
|
||||
|
||||
size_t getMountedDeviceCount(IdeviceProviderHandle* provider, NSError** error) {
|
||||
size_t getMountedDeviceCount(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSError** error) {
|
||||
ImageMounterHandle *client = NULL;
|
||||
IdeviceFfiError *err = image_mounter_connect(provider, &client);
|
||||
IdeviceFfiError *err = image_mounter_connect_rsd(adapter, handshake, &client);
|
||||
if (err) {
|
||||
*error = makeError(err->code, @(err->message));
|
||||
idevice_error_free(err);
|
||||
|
|
@ -37,34 +37,24 @@ size_t getMountedDeviceCount(IdeviceProviderHandle* provider, NSError** error) {
|
|||
return deviceLength;
|
||||
}
|
||||
|
||||
int mountPersonalDDI(IdeviceProviderHandle* provider, IdevicePairingFile* pairingFile2, NSString* imagePath, NSString* trustcachePath, NSString* manifestPath, NSError** error) {
|
||||
int mountPersonalDDI(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString* imagePath, NSString* trustcachePath, NSString* manifestPath, NSError** error) {
|
||||
NSData *image = [NSData dataWithContentsOfFile:imagePath];
|
||||
NSData *trustcache = [NSData dataWithContentsOfFile:trustcachePath];
|
||||
NSData *buildManifest = [NSData dataWithContentsOfFile:manifestPath];
|
||||
if (!image || !trustcache || !buildManifest) {
|
||||
idevice_pairing_file_free(pairingFile2);
|
||||
*error = makeError(1, @"Failed to read one or more files");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Get UniqueChipID via lockdownd over RSD (no session start needed - tunnel handles auth)
|
||||
LockdowndClientHandle *lockdownClient = NULL;
|
||||
IdeviceFfiError *err = lockdownd_connect(provider, &lockdownClient);
|
||||
IdeviceFfiError *err = lockdownd_connect_rsd(adapter, handshake, &lockdownClient);
|
||||
if (err) {
|
||||
*error = makeError(6, @(err->message));
|
||||
idevice_pairing_file_free(pairingFile2);
|
||||
idevice_error_free(err);
|
||||
return 6;
|
||||
}
|
||||
|
||||
err = lockdownd_start_session(lockdownClient, pairingFile2);
|
||||
idevice_pairing_file_free(pairingFile2);
|
||||
if (err) {
|
||||
*error = makeError(7, @(err->message));
|
||||
idevice_error_free(err);
|
||||
lockdownd_client_free(lockdownClient);
|
||||
return 7;
|
||||
}
|
||||
|
||||
plist_t uniqueChipIDPlist = NULL;
|
||||
err = lockdownd_get_value(lockdownClient, "UniqueChipID", NULL, &uniqueChipIDPlist);
|
||||
lockdownd_client_free(lockdownClient);
|
||||
|
|
@ -79,50 +69,33 @@ int mountPersonalDDI(IdeviceProviderHandle* provider, IdevicePairingFile* pairin
|
|||
plist_free(uniqueChipIDPlist);
|
||||
|
||||
ImageMounterHandle *mounterClient = NULL;
|
||||
err = image_mounter_connect(provider, &mounterClient);
|
||||
err = image_mounter_connect_rsd(adapter, handshake, &mounterClient);
|
||||
if (err) {
|
||||
*error = makeError(9, @(err->message));
|
||||
idevice_error_free(err);
|
||||
return 9;
|
||||
}
|
||||
|
||||
err = image_mounter_mount_personalized(
|
||||
mounterClient,
|
||||
provider,
|
||||
[image bytes],
|
||||
[image length],
|
||||
[trustcache bytes],
|
||||
[trustcache length],
|
||||
[buildManifest bytes],
|
||||
[buildManifest length],
|
||||
NULL,
|
||||
uniqueChipID
|
||||
);
|
||||
// TODO: image_mounter_mount_personalized still requires an IdeviceProviderHandle.
|
||||
// The FFI needs an RSD variant (e.g. image_mounter_mount_personalized_rsd) that
|
||||
// takes an AdapterHandle instead.
|
||||
*error = makeError(10, @"mount_personalized not yet available over RSD tunnels");
|
||||
image_mounter_free(mounterClient);
|
||||
|
||||
if (err) {
|
||||
*error = makeError(10, @(err->message));
|
||||
idevice_error_free(err);
|
||||
return 10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 10;
|
||||
}
|
||||
|
||||
@implementation JITEnableContext(DDI)
|
||||
|
||||
- (NSUInteger)getMountedDeviceCount:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return 0; }
|
||||
return getMountedDeviceCount(provider, error);
|
||||
return getMountedDeviceCount(adapter, handshake, error);
|
||||
}
|
||||
|
||||
- (NSInteger)mountPersonalDDIWithImagePath:(NSString*)imagePath trustcachePath:(NSString*)trustcachePath manifestPath:(NSString*)manifestPath error:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return 0; }
|
||||
IdevicePairingFile *pairing = [self getPairingFileWithError:error];
|
||||
if (*error) { return 0; }
|
||||
return mountPersonalDDI(provider, pairing, imagePath, trustcachePath, manifestPath, error);
|
||||
return mountPersonalDDI(adapter, handshake, imagePath, trustcachePath, manifestPath, error);
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
|||
|
|
@ -12,20 +12,17 @@
|
|||
// MARK: - Shared AppService session
|
||||
|
||||
typedef struct {
|
||||
AdapterHandle *adapter;
|
||||
RsdHandshakeHandle *handshake;
|
||||
AppServiceHandle *appService;
|
||||
} AppServiceSession;
|
||||
|
||||
static void app_service_session_free(AppServiceSession *s) {
|
||||
if (s->appService) { app_service_free(s->appService); s->appService = NULL; }
|
||||
if (s->handshake) { rsd_handshake_free(s->handshake); s->handshake = NULL; }
|
||||
if (s->adapter) { adapter_free(s->adapter); s->adapter = NULL; }
|
||||
}
|
||||
|
||||
// Connects to the device via CoreDeviceProxy → Adapter → RSD → AppService.
|
||||
// Connects to the device via the existing adapter+handshake → AppService.
|
||||
// Returns 0 on success; cleans up any partial state and returns 1 on failure.
|
||||
static int connect_app_service(IdeviceProviderHandle *provider,
|
||||
static int connect_app_service(AdapterHandle *adapter,
|
||||
RsdHandshakeHandle *handshake,
|
||||
AppServiceSession *out,
|
||||
JITEnableContext *ctx,
|
||||
NSError **outError)
|
||||
|
|
@ -33,62 +30,11 @@ static int connect_app_service(IdeviceProviderHandle *provider,
|
|||
memset(out, 0, sizeof(*out));
|
||||
IdeviceFfiError *ffiError = NULL;
|
||||
|
||||
CoreDeviceProxyHandle *coreProxy = NULL;
|
||||
ffiError = core_device_proxy_connect(provider, &coreProxy);
|
||||
if (ffiError) {
|
||||
*outError = [ctx errorWithStr:[NSString stringWithUTF8String:ffiError->message ?: "Failed to connect CoreDeviceProxy"]
|
||||
code:ffiError->code];
|
||||
idevice_error_free(ffiError);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint16_t rsdPort = 0;
|
||||
ffiError = core_device_proxy_get_server_rsd_port(coreProxy, &rsdPort);
|
||||
if (ffiError) {
|
||||
*outError = [ctx errorWithStr:[NSString stringWithUTF8String:ffiError->message ?: "Unable to resolve RSD port"]
|
||||
code:ffiError->code];
|
||||
idevice_error_free(ffiError);
|
||||
core_device_proxy_free(coreProxy);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ffiError = core_device_proxy_create_tcp_adapter(coreProxy, &out->adapter);
|
||||
if (ffiError) {
|
||||
*outError = [ctx errorWithStr:[NSString stringWithUTF8String:ffiError->message ?: "Failed to create adapter"]
|
||||
code:ffiError->code];
|
||||
idevice_error_free(ffiError);
|
||||
core_device_proxy_free(coreProxy);
|
||||
return 1;
|
||||
}
|
||||
coreProxy = NULL; // ownership transferred to adapter
|
||||
|
||||
AdapterStreamHandle *stream = NULL;
|
||||
ffiError = adapter_connect(out->adapter, rsdPort, (ReadWriteOpaque **)&stream);
|
||||
if (ffiError) {
|
||||
*outError = [ctx errorWithStr:[NSString stringWithUTF8String:ffiError->message ?: "Adapter connect failed"]
|
||||
code:ffiError->code];
|
||||
idevice_error_free(ffiError);
|
||||
app_service_session_free(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ffiError = rsd_handshake_new((ReadWriteOpaque *)stream, &out->handshake);
|
||||
if (ffiError) {
|
||||
*outError = [ctx errorWithStr:[NSString stringWithUTF8String:ffiError->message ?: "RSD handshake failed"]
|
||||
code:ffiError->code];
|
||||
idevice_error_free(ffiError);
|
||||
adapter_stream_close(stream);
|
||||
app_service_session_free(out);
|
||||
return 1;
|
||||
}
|
||||
stream = NULL; // consumed by handshake
|
||||
|
||||
ffiError = app_service_connect_rsd(out->adapter, out->handshake, &out->appService);
|
||||
ffiError = app_service_connect_rsd(adapter, handshake, &out->appService);
|
||||
if (ffiError) {
|
||||
*outError = [ctx errorWithStr:[NSString stringWithUTF8String:ffiError->message ?: "Unable to open AppService"]
|
||||
code:ffiError->code];
|
||||
idevice_error_free(ffiError);
|
||||
app_service_session_free(out);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -100,11 +46,11 @@ static int connect_app_service(IdeviceProviderHandle *provider,
|
|||
@implementation JITEnableContext(Process)
|
||||
|
||||
- (NSArray<NSDictionary*>*)fetchProcessesViaAppServiceWithError:(NSError **)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return nil; }
|
||||
|
||||
AppServiceSession session;
|
||||
if (connect_app_service(provider, &session, self, error) != 0) { return nil; }
|
||||
if (connect_app_service(adapter, handshake, &session, self, error) != 0) { return nil; }
|
||||
|
||||
ProcessTokenC *processes = NULL;
|
||||
uintptr_t count = 0;
|
||||
|
|
@ -138,7 +84,7 @@ static int connect_app_service(IdeviceProviderHandle *provider,
|
|||
}
|
||||
|
||||
- (NSArray<NSDictionary*>*)_fetchProcessListLocked:(NSError**)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return nil; }
|
||||
return [self fetchProcessesViaAppServiceWithError:error];
|
||||
}
|
||||
|
|
@ -156,11 +102,11 @@ static int connect_app_service(IdeviceProviderHandle *provider,
|
|||
}
|
||||
|
||||
- (BOOL)killProcessWithPID:(int)pid error:(NSError **)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if (*error) { return NO; }
|
||||
|
||||
AppServiceSession session;
|
||||
if (connect_app_service(provider, &session, self, error) != 0) { return NO; }
|
||||
if (connect_app_service(adapter, handshake, &session, self, error) != 0) { return NO; }
|
||||
|
||||
SignalResponseC *signalResponse = NULL;
|
||||
IdeviceFfiError *ffiError = app_service_send_signal(session.appService, (uint32_t)pid, SIGKILL, &signalResponse);
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@
|
|||
#define PROFILES_H
|
||||
#include "idevice.h"
|
||||
#include <Foundation/Foundation.h>
|
||||
NSArray<NSData*>* _Nullable fetchAppProfiles(IdeviceProviderHandle* _Nonnull provider, NSError* _Nullable * _Nullable error);
|
||||
bool removeProfile(IdeviceProviderHandle* _Nonnull provider, NSString* _Nonnull uuid, NSError* _Nullable * _Nullable error);
|
||||
bool addProfile(IdeviceProviderHandle* _Nonnull provider, NSData* _Nonnull profile, NSError* _Nullable * _Nullable error);
|
||||
NSArray<NSData*>* _Nullable fetchAppProfiles(AdapterHandle* _Nonnull adapter, RsdHandshakeHandle* _Nonnull handshake, NSError* _Nullable * _Nullable error);
|
||||
bool removeProfile(AdapterHandle* _Nonnull adapter, RsdHandshakeHandle* _Nonnull handshake, NSString* _Nonnull uuid, NSError* _Nullable * _Nullable error);
|
||||
bool addProfile(AdapterHandle* _Nonnull adapter, RsdHandshakeHandle* _Nonnull handshake, NSData* _Nonnull profile, NSError* _Nullable * _Nullable error);
|
||||
|
||||
@interface CMSDecoderHelper : NSObject
|
||||
// Decode CMS/PKCS7 data and return decoded payload and any embedded certs
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ NSError* makeError(int code, NSString* msg) {
|
|||
}
|
||||
|
||||
|
||||
NSArray<NSData*>* fetchAppProfiles(IdeviceProviderHandle* provider, NSError** error) {
|
||||
NSArray<NSData*>* fetchAppProfiles(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSError** error) {
|
||||
MisagentClientHandle *misagentHandle = NULL;
|
||||
IdeviceFfiError *err = misagent_connect(provider, &misagentHandle);
|
||||
IdeviceFfiError *err = misagent_connect_rsd(adapter, handshake, &misagentHandle);
|
||||
if (err) {
|
||||
*error = makeError(err->code, @(err->message));
|
||||
idevice_error_free(err);
|
||||
|
|
@ -50,9 +50,9 @@ NSArray<NSData*>* fetchAppProfiles(IdeviceProviderHandle* provider, NSError** er
|
|||
return ans;
|
||||
}
|
||||
|
||||
bool removeProfile(IdeviceProviderHandle* provider, NSString* uuid, NSError** error) {
|
||||
bool removeProfile(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSString* uuid, NSError** error) {
|
||||
MisagentClientHandle *misagentHandle = NULL;
|
||||
IdeviceFfiError * err = misagent_connect(provider, &misagentHandle);
|
||||
IdeviceFfiError * err = misagent_connect_rsd(adapter, handshake, &misagentHandle);
|
||||
if (err) {
|
||||
*error = makeError(err->code, @(err->message));
|
||||
idevice_error_free(err);
|
||||
|
|
@ -71,9 +71,9 @@ bool removeProfile(IdeviceProviderHandle* provider, NSString* uuid, NSError** er
|
|||
return true;
|
||||
}
|
||||
|
||||
bool addProfile(IdeviceProviderHandle* provider, NSData* profile, NSError** error) {
|
||||
bool addProfile(AdapterHandle* adapter, RsdHandshakeHandle* handshake, NSData* profile, NSError** error) {
|
||||
MisagentClientHandle *misagentHandle = NULL;
|
||||
IdeviceFfiError * err = misagent_connect(provider, &misagentHandle);
|
||||
IdeviceFfiError * err = misagent_connect_rsd(adapter, handshake, &misagentHandle);
|
||||
if (err) {
|
||||
*error = makeError(err->code, @(err->message));
|
||||
idevice_error_free(err);
|
||||
|
|
@ -141,29 +141,29 @@ bool addProfile(IdeviceProviderHandle* provider, NSData* profile, NSError** erro
|
|||
@implementation JITEnableContext(Profile)
|
||||
|
||||
- (NSArray<NSData*>*)fetchAllProfiles:(NSError **)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
return fetchAppProfiles(provider, error);
|
||||
return fetchAppProfiles(adapter, handshake, error);
|
||||
}
|
||||
|
||||
- (BOOL)removeProfileWithUUID:(NSString*)uuid error:(NSError **)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
return removeProfile(provider, uuid, error);
|
||||
return removeProfile(adapter, handshake, uuid, error);
|
||||
}
|
||||
|
||||
- (BOOL)addProfile:(NSData*)profile error:(NSError **)error {
|
||||
[self ensureHeartbeatWithError:error];
|
||||
[self ensureTunnelWithError:error];
|
||||
if(*error) {
|
||||
return NO;
|
||||
}
|
||||
return addProfile(provider, profile, error);
|
||||
return addProfile(adapter, handshake, profile, error);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
onError:(SyslogErrorHandler)errorHandler
|
||||
{
|
||||
NSError* error = nil;
|
||||
[self ensureHeartbeatWithError:&error];
|
||||
[self ensureTunnelWithError:&error];
|
||||
if(error) {
|
||||
errorHandler(error);
|
||||
return;
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
if (!strongSelf) { return; }
|
||||
|
||||
SyslogRelayClientHandle *client = NULL;
|
||||
IdeviceFfiError *err = syslog_relay_connect_tcp(strongSelf->provider, &client);
|
||||
IdeviceFfiError *err = syslog_relay_connect_rsd(strongSelf->adapter, strongSelf->handshake, &client);
|
||||
if (err != NULL) {
|
||||
NSString *message = err->message ? [NSString stringWithCString:err->message encoding:NSASCIIStringEncoding] : @"Failed to connect to syslog relay";
|
||||
NSError *nsError = [strongSelf errorWithStr:message code:err->code];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue