diff --git a/AltServer/Devices/ALTDeviceManager.h b/AltServer/Devices/ALTDeviceManager.h index df1dfb9b..12295a2b 100644 --- a/AltServer/Devices/ALTDeviceManager.h +++ b/AltServer/Devices/ALTDeviceManager.h @@ -13,6 +13,8 @@ @class ALTNotificationConnection; @class ALTDebugConnection; +@class ALTInstalledApp; + NS_ASSUME_NONNULL_BEGIN extern NSNotificationName const ALTDeviceManagerDeviceDidConnectNotification NS_SWIFT_NAME(deviceManagerDeviceDidConnect); @@ -41,6 +43,9 @@ extern NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification - (void)installDeveloperDiskImageAtURL:(NSURL *)diskURL signatureURL:(NSURL *)signatureURL toDevice:(ALTDevice *)device completionHandler:(void (^)(BOOL success, NSError *_Nullable error))completionHandler; +/* Apps */ +- (void)fetchInstalledAppsOnDevice:(ALTDevice *)altDevice completionHandler:(void (^)(NSSet *_Nullable installedApps, NSError *_Nullable error))completionHandler; + /* Connections */ - (void)startWiredConnectionToDevice:(ALTDevice *)device completionHandler:(void (^)(ALTWiredConnection *_Nullable connection, NSError *_Nullable error))completionHandler; - (void)startNotificationConnectionToDevice:(ALTDevice *)device completionHandler:(void (^)(ALTNotificationConnection *_Nullable connection, NSError *_Nullable error))completionHandler; diff --git a/AltServer/Devices/ALTDeviceManager.mm b/AltServer/Devices/ALTDeviceManager.mm index 630fd760..23be4260 100644 --- a/AltServer/Devices/ALTDeviceManager.mm +++ b/AltServer/Devices/ALTDeviceManager.mm @@ -16,6 +16,10 @@ #import "NSError+ALTServerError.h" #import "NSError+libimobiledevice.h" +#import +#import +#import "AltServer-Swift.h" + #include #include #include @@ -38,7 +42,9 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT @property (nonatomic, readonly) NSMutableDictionary *deletionCompletionHandlers; @property (nonatomic, readonly) NSMutableDictionary *installationProgress; + @property (nonatomic, readonly) dispatch_queue_t installationQueue; +@property (nonatomic, readonly) dispatch_queue_t devicesQueue; @property (nonatomic, readonly) NSMutableSet *cachedDevices; @@ -66,7 +72,9 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT _deletionCompletionHandlers = [NSMutableDictionary dictionary]; _installationProgress = [NSMutableDictionary dictionary]; - _installationQueue = dispatch_queue_create("com.rileytestut.AltServer.InstallationQueue", DISPATCH_QUEUE_SERIAL); + + _installationQueue = dispatch_queue_create("com.rileytestut.AltServer.Installation", DISPATCH_QUEUE_SERIAL); + _devicesQueue = dispatch_queue_create("com.rileytestut.AltServer.Devices", DISPATCH_QUEUE_CONCURRENT_WITH_AUTORELEASE_POOL); _cachedDevices = [NSMutableSet set]; } @@ -1195,6 +1203,113 @@ NSNotificationName const ALTDeviceManagerDeviceDidDisconnectNotification = @"ALT }); } +#pragma mark - Apps - + +- (void)fetchInstalledAppsOnDevice:(ALTDevice *)altDevice completionHandler:(void (^)(NSSet *_Nullable installedApps, NSError *_Nullable error))completionHandler +{ + __block idevice_t device = NULL; + __block instproxy_client_t ipc = NULL; + __block lockdownd_client_t client = NULL; + __block lockdownd_service_descriptor_t service = NULL; + __block plist_t options = NULL; + + void (^finish)(NSSet *, NSError *) = ^(NSSet *installedApps, NSError *error) { + if (error != nil) { + NSLog(@"Notification Connection Error: %@", error); + } + + if (options) { + instproxy_client_options_free(options); + } + + if (service) { + lockdownd_service_descriptor_free(service); + } + + if (client) { + lockdownd_client_free(client); + } + + if (ipc) { + instproxy_client_free(ipc); + } + + if (device) { + idevice_free(device); + } + + completionHandler(installedApps, error); + }; + + // Don't use installationQueue since this operation can potentially take a very long time and will block other operations. + // dispatch_async(self.installationQueue, ^{ + dispatch_async(self.devicesQueue, ^{ + /* Find Device */ + if (idevice_new_with_options(&device, altDevice.identifier.UTF8String, (enum idevice_options)((int)IDEVICE_LOOKUP_NETWORK | (int)IDEVICE_LOOKUP_USBMUX)) != IDEVICE_E_SUCCESS) + { + return finish(nil, [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorDeviceNotFound userInfo:nil]); + } + + if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &client, "AltServer")) + { + return finish(nil, [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + if ((lockdownd_start_service(client, "com.apple.mobile.installation_proxy", &service) != LOCKDOWN_E_SUCCESS) || !service) + { + return finish(nil, [NSError errorWithDomain:AltServerErrorDomain code:ALTServerErrorConnectionFailed userInfo:nil]); + } + + instproxy_error_t err = instproxy_client_new(device, service, &ipc); + if (err != INSTPROXY_E_SUCCESS) + { + return finish(nil, [NSError errorWithInstallationProxyError:err device:altDevice]); + } + + options = instproxy_client_options_new(); + instproxy_client_options_add(options, "ApplicationType", "User", NULL); + + plist_t plist = NULL; + err = instproxy_browse(ipc, options, &plist); + if (err != INSTPROXY_E_SUCCESS) + { + return finish(nil, [NSError errorWithInstallationProxyError:err device:altDevice]); + } + + char *plistXML = NULL; + uint32_t length = 0; + plist_to_xml(plist, &plistXML, &length); + + NSData *plistData = [@(plistXML) dataUsingEncoding:NSUTF8StringEncoding]; + free(plistXML); + plist_free(plist); + + NSError *error = nil; + NSArray *appDictionaries = [NSPropertyListSerialization propertyListWithData:plistData options:0 format:nil error:&error]; + if (appDictionaries == nil) + { + return finish(nil, error); + } + + NSMutableSet *installedApps = [NSMutableSet set]; + for (NSDictionary *appInfo in appDictionaries) + { + if (appInfo[@"ALTBundleIdentifier"] != nil) + { + // Only return apps installed with AltStore. + + ALTInstalledApp *installedApp = [[ALTInstalledApp alloc] initWithDictionary:appInfo]; + if (installedApp) + { + [installedApps addObject:installedApp]; + } + } + } + + finish(installedApps, nil); + }); +} + #pragma mark - Connections - - (void)startWiredConnectionToDevice:(ALTDevice *)altDevice completionHandler:(void (^)(ALTWiredConnection * _Nullable, NSError * _Nullable))completionHandler diff --git a/AltServer/InstalledApp.swift b/AltServer/InstalledApp.swift new file mode 100644 index 00000000..003dcbf6 --- /dev/null +++ b/AltServer/InstalledApp.swift @@ -0,0 +1,29 @@ +// +// InstalledApp.swift +// AltServer +// +// Created by Riley Testut on 5/25/21. +// Copyright © 2021 Riley Testut. All rights reserved. +// + +import Foundation + +@objc(ALTInstalledApp) @objcMembers +class InstalledApp: NSObject, MenuDisplayable +{ + let name: String + let bundleIdentifier: String + let executableName: String + + init?(dictionary: [String: Any]) + { + guard let name = dictionary[kCFBundleNameKey as String] as? String, + let bundleIdentifier = dictionary[kCFBundleIdentifierKey as String] as? String, + let executableName = dictionary[kCFBundleExecutableKey as String] as? String + else { return nil } + + self.name = name + self.bundleIdentifier = bundleIdentifier + self.executableName = executableName + } +} diff --git a/AltStore.xcodeproj/project.pbxproj b/AltStore.xcodeproj/project.pbxproj index 103952d6..e930b9cf 100644 --- a/AltStore.xcodeproj/project.pbxproj +++ b/AltStore.xcodeproj/project.pbxproj @@ -199,6 +199,7 @@ BF8CAE4E248AEABA004D6CCE /* UIDevice+Jailbreak.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */; }; BF8F69C222E659F700049BA1 /* AppContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C122E659F700049BA1 /* AppContentViewController.swift */; }; BF8F69C422E662D300049BA1 /* AppViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF8F69C322E662D300049BA1 /* AppViewController.swift */; }; + BF904DEA265DAE9A00E86C2A /* InstalledApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF904DE9265DAE9A00E86C2A /* InstalledApp.swift */; }; BF989171250AABF4002ACF50 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF989170250AABF4002ACF50 /* Assets.xcassets */; }; BF989177250AABF4002ACF50 /* AltWidgetExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; BF98917E250AAC4F002ACF50 /* Countdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF98917C250AAC4F002ACF50 /* Countdown.swift */; }; @@ -667,6 +668,7 @@ BF8CAE4D248AEABA004D6CCE /* UIDevice+Jailbreak.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Jailbreak.swift"; sourceTree = ""; }; BF8F69C122E659F700049BA1 /* AppContentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppContentViewController.swift; sourceTree = ""; }; BF8F69C322E662D300049BA1 /* AppViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppViewController.swift; sourceTree = ""; }; + BF904DE9265DAE9A00E86C2A /* InstalledApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstalledApp.swift; sourceTree = ""; }; BF989167250AABF3002ACF50 /* AltWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = AltWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; BF989170250AABF4002ACF50 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; BF989172250AABF4002ACF50 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -978,6 +980,7 @@ BFC712BA2512B9CF00AB5EBE /* PluginManager.swift */, BFAD67A225E0854500D4C4D1 /* DeveloperDiskManager.swift */, BFF0394A25F0551600BE607D /* MenuController.swift */, + BF904DE9265DAE9A00E86C2A /* InstalledApp.swift */, BF703195229F36FF006E110F /* Devices */, BFD52BDC22A0A659000B7ED1 /* Connections */, BF055B4A233B528B0086DEA9 /* Extensions */, @@ -2295,6 +2298,7 @@ BFECAC8124FD950B0077C41F /* ALTServerError+Conveniences.swift in Sources */, BFECAC7F24FD950B0077C41F /* CodableServerError.swift in Sources */, BFECAC8624FD950B0077C41F /* Result+Conveniences.swift in Sources */, + BF904DEA265DAE9A00E86C2A /* InstalledApp.swift in Sources */, BFF435D9255CBDAB00DD724F /* ALTApplication+AltStoreApp.swift in Sources */, BF718BD523C928A300A89F2D /* ALTNotificationConnection.mm in Sources */, BF1E312B229F474900370A3C /* RequestHandler.swift in Sources */,