From 5d474901a2ccf32561462c577fd89c802f52ac3c Mon Sep 17 00:00:00 2001 From: opa334 Date: Fri, 9 Sep 2022 20:22:34 +0200 Subject: [PATCH] 1.0.8 --- Helper/CoreServices.h | 8 +- Helper/control | 2 +- Helper/main.m | 262 +++++++++++++++------ Helper/uicache.m | 2 + PersistenceHelper/Resources/Info.plist | 2 +- PersistenceHelper/TSPHRootViewController.m | 8 +- PersistenceHelper/control | 2 +- Store/Resources/Info.plist | 2 +- Store/TSAppTableViewController.m | 96 +++++++- Store/TSApplicationsManager.h | 3 +- Store/TSApplicationsManager.m | 54 ++++- Store/TSSceneDelegate.m | 249 +++++++++++--------- Store/TSSettingsListController.m | 10 +- Store/TSUtil.h | 3 +- Store/TSUtil.m | 63 ++++- Store/control | 2 +- 16 files changed, 533 insertions(+), 235 deletions(-) diff --git a/Helper/CoreServices.h b/Helper/CoreServices.h index bc0fd1b..a2bb4fe 100644 --- a/Helper/CoreServices.h +++ b/Helper/CoreServices.h @@ -13,7 +13,8 @@ @property (nonatomic,readonly) NSArray* plugInKitPlugins; @property (getter=isInstalled,nonatomic,readonly) BOOL installed; @property (getter=isPlaceholder,nonatomic,readonly) BOOL placeholder; -@property (getter=isRestricted,nonatomic,readonly) BOOL restricted; +@property (getter=isRestricted,nonatomic,readonly) BOOL restricted; +@property (nonatomic,readonly) NSSet * claimedURLSchemes; @end @interface LSApplicationWorkspace : NSObject @@ -25,6 +26,11 @@ - (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy*))block; @end +@interface LSEnumerator : NSEnumerator +@property (nonatomic,copy) NSPredicate * predicate; ++ (instancetype)enumeratorForApplicationProxiesWithOptions:(NSUInteger)options; +@end + @interface LSPlugInKitProxy : LSBundleProxy @property (nonatomic,readonly) NSString* pluginIdentifier; @property (nonatomic,readonly) NSDictionary * pluginKitDictionary; diff --git a/Helper/control b/Helper/control index be35717..15258ce 100644 --- a/Helper/control +++ b/Helper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstoreroothelper Name: trollstoreroothelper -Version: 1.0.6 +Version: 1.0.8 Architecture: iphoneos-arm Description: An awesome tool of some sort!! Maintainer: opa334 diff --git a/Helper/main.m b/Helper/main.m index 6228fa7..24e8240 100644 --- a/Helper/main.m +++ b/Helper/main.m @@ -54,6 +54,28 @@ typedef CFDictionaryRef (*_CFPreferencesCopyMultipleWithContainerType)(CFArrayRe BOOL _installPersistenceHelper(LSApplicationProxy* appProxy, NSString* sourcePersistenceHelper, NSString* sourceRootHelper); +NSArray* applicationsWithGroupId(NSString* groupId) +{ + LSEnumerator* enumerator = [LSEnumerator enumeratorForApplicationProxiesWithOptions:0]; + enumerator.predicate = [NSPredicate predicateWithFormat:@"groupContainerURLs[%@] != nil", groupId]; + return enumerator.allObjects; +} + +NSSet* appleURLSchemes(void) +{ + LSEnumerator* enumerator = [LSEnumerator enumeratorForApplicationProxiesWithOptions:0]; + enumerator.predicate = [NSPredicate predicateWithFormat:@"bundleIdentifier BEGINSWITH 'com.apple'"]; + + NSMutableSet* systemURLSchemes = [NSMutableSet new]; + LSApplicationProxy* proxy; + while(proxy = [enumerator nextObject]) + { + [systemURLSchemes unionSet:proxy.claimedURLSchemes]; + } + + return systemURLSchemes.copy; +} + extern char*** _NSGetArgv(); NSString* safe_getExecutablePath() { @@ -72,7 +94,12 @@ NSString* appIdForAppPath(NSString* appPath) return infoDictionaryForAppPath(appPath)[@"CFBundleIdentifier"]; } -NSString* appPathForAppId(NSString* appId, NSError** error) +NSString* appMainExecutablePathForAppPath(NSString* appPath) +{ + return [appPath stringByAppendingPathComponent:infoDictionaryForAppPath(appPath)[@"CFBundleExecutable"]]; +} + +NSString* appPathForAppId(NSString* appId) { for(NSString* appPath in trollStoreInstalledAppBundlePaths()) { @@ -411,15 +438,15 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef) return evaluatesToCustomAnchor; } -BOOL signApp(NSString* appPath, NSError** error) +int signApp(NSString* appPath) { - NSDictionary* appInfoDict = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]]; - if(!appInfoDict) return NO; + NSDictionary* appInfoDict = infoDictionaryForAppPath(appPath); + if(!appInfoDict) return 172; - NSString* executable = appInfoDict[@"CFBundleExecutable"]; - NSString* executablePath = [appPath stringByAppendingPathComponent:executable]; + NSString* executablePath = appMainExecutablePathForAppPath(appPath); + if(!executablePath) return 176; - if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO; + if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return 174; NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) @@ -430,7 +457,7 @@ BOOL signApp(NSString* appPath, NSError** error) if([tsBundleIsPreSignedNum boolValue] == YES) { NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); - return YES; + return 0; } } @@ -441,7 +468,7 @@ BOOL signApp(NSString* appPath, NSError** error) { NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath); CFRelease(codeRef); - return YES; + return 0; } } else @@ -449,7 +476,7 @@ BOOL signApp(NSString* appPath, NSError** error) NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@, continuing anways...", executablePath); } - if(!isLdidInstalled()) return NO; + if(!isLdidInstalled()) return 173; NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; @@ -481,7 +508,14 @@ BOOL signApp(NSString* appPath, NSError** error) NSLog(@"- ldid error output end -"); - return ldidRet == 0; + if(ldidRet == 0) + { + return 0; + } + else + { + return 175; + } } void applyPatchesToInfoDictionary(NSString* appPath) @@ -491,9 +525,34 @@ void applyPatchesToInfoDictionary(NSString* appPath) NSMutableDictionary* infoDictM = [[NSDictionary dictionaryWithContentsOfURL:infoPlistURL error:nil] mutableCopy]; if(!infoDictM) return; - // enable notifications + // Enable Notifications infoDictM[@"SBAppUsesLocalNotifications"] = @1; + // Remove system claimed URL schemes if existant + NSSet* appleSchemes = appleURLSchemes(); + NSArray* CFBundleURLTypes = infoDictM[@"CFBundleURLTypes"]; + if([CFBundleURLTypes isKindOfClass:[NSArray class]]) + { + NSMutableArray* CFBundleURLTypesM = [NSMutableArray new]; + + for(NSDictionary* URLType in CFBundleURLTypes) + { + if(![URLType isKindOfClass:[NSDictionary class]]) continue; + + NSMutableDictionary* modifiedURLType = URLType.mutableCopy; + NSArray* URLSchemes = URLType[@"CFBundleURLSchemes"]; + if(URLSchemes) + { + NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray:URLSchemes]; + [URLSchemesSet minusSet:appleSchemes]; + modifiedURLType[@"CFBundleURLSchemes"] = [URLSchemesSet allObjects]; + } + [CFBundleURLTypesM addObject:modifiedURLType.copy]; + } + + infoDictM[@"CFBundleURLTypes"] = CFBundleURLTypesM.copy; + } + [infoDictM writeToURL:infoPlistURL error:nil]; } @@ -501,33 +560,45 @@ void applyPatchesToInfoDictionary(NSString* appPath) // 171: a non trollstore app with the same identifier is already installled // 172: no info.plist found in app // 173: app is not signed and cannot be signed because ldid not installed or didn't work -int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) +// 174: +int installApp(NSString* appPath, BOOL sign, BOOL force) { NSLog(@"[installApp force = %d]", force); + if(!infoDictionaryForAppPath(appPath)) return 172; + NSString* appId = appIdForAppPath(appPath); - if(!appId) return 172; + if(!appId) return 176; applyPatchesToInfoDictionary(appPath); if(sign) { - if(!signApp(appPath, error)) return 173; + int signRet = signApp(appPath); + if(signRet != 0) return signRet; } BOOL existed; NSError* mcmError; MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError]; - NSLog(@"[installApp] appContainer: %@, mcmError: %@", appContainer, mcmError); if(!appContainer || mcmError) { - if(error) *error = mcmError; + NSLog(@"[installApp] failed to create app container for %@: %@", appId, mcmError); return 170; } + if(existed) + { + NSLog(@"[installApp] got existing app container: %@", appContainer); + } + else + { + NSLog(@"[installApp] created app container: %@", appContainer); + } + // check if the bundle is empty BOOL isEmpty = YES; - NSArray* bundleItems = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appContainer.url.path error:error]; + NSArray* bundleItems = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appContainer.url.path error:nil]; for(NSString* bundleItem in bundleItems) { if([bundleItem.pathExtension isEqualToString:@"app"]) @@ -537,6 +608,8 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) } } + NSLog(@"[installApp] container is empty? %d", isEmpty); + // Make sure there isn't already an app store app installed with the same identifier NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"]; if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force) @@ -546,7 +619,12 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) } // Mark app as TrollStore app - [[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil]; + BOOL marked = [[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil]; + if(!marked) + { + NSLog(@"[installApp] failed to mark %@ as TrollStore app", appId); + return 177; + } // Apply correct permissions (First run, set everything to 644, owner 33) NSURL* fileURL; @@ -556,6 +634,7 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) NSString* filePath = fileURL.path; chown(filePath.UTF8String, 33, 33); chmod(filePath.UTF8String, 0644); + NSLog(@"[installApp] setting %@ to chown(33,33) chmod(0644)", filePath); } // Apply correct permissions (Second run, set executables and directories to 0755) @@ -571,10 +650,28 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) { NSDictionary* infoDictionary = [NSDictionary dictionaryWithContentsOfFile:filePath]; NSString* executable = infoDictionary[@"CFBundleExecutable"]; - if(executable) + if(executable && [executable isKindOfClass:[NSString class]]) { NSString* executablePath = [[filePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:executable]; chmod(executablePath.UTF8String, 0755); + NSLog(@"[installApp] applied permissions for bundle executable %@", executablePath); + } + NSArray* tsRootBinaries = infoDictionary[@"TSRootBinaries"]; + if(tsRootBinaries && [tsRootBinaries isKindOfClass:[NSArray class]]) + { + for(NSString* rootBinary in tsRootBinaries) + { + if([rootBinary isKindOfClass:[NSString class]]) + { + NSString* rootBinaryPath = [[filePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:rootBinary]; + if([[NSFileManager defaultManager] fileExistsAtPath:rootBinaryPath]) + { + chmod(rootBinaryPath.UTF8String, 0755); + chown(rootBinaryPath.UTF8String, 0, 0); + NSLog(@"[installApp] applied permissions for root binary %@", rootBinaryPath); + } + } + } } } else if(!isDir && [filePath.pathExtension isEqualToString:@"dylib"]) @@ -588,28 +685,9 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) } } - // chown 0 all root binaries - NSDictionary* mainInfoDictionary = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]]; - if(!mainInfoDictionary) return 172; - NSObject* tsRootBinaries = mainInfoDictionary[@"TSRootBinaries"]; - if([tsRootBinaries isKindOfClass:[NSArray class]]) - { - NSArray* tsRootBinariesArr = (NSArray*)tsRootBinaries; - for(NSObject* rootBinary in tsRootBinariesArr) - { - if([rootBinary isKindOfClass:[NSString class]]) - { - NSString* rootBinaryStr = (NSString*)rootBinary; - NSString* rootBinaryPath = [appPath stringByAppendingPathComponent:rootBinaryStr]; - if([[NSFileManager defaultManager] fileExistsAtPath:rootBinaryPath]) - { - chmod(rootBinaryPath.UTF8String, 0755); - chown(rootBinaryPath.UTF8String, 0, 0); - NSLog(@"[installApp] applying permissions for root binary %@", rootBinaryPath); - } - } - } - } + // Set .app directory permissions too + chmod(appPath.UTF8String, 0755); + chown(appPath.UTF8String, 33, 33); // Wipe old version if needed if(existed) @@ -634,35 +712,45 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error) NSString* newAppPath = [appContainer.url.path stringByAppendingPathComponent:appPath.lastPathComponent]; NSLog(@"[installApp] new app path: %@", newAppPath); - BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appPath toPath:newAppPath error:error]; + NSError* copyError; + BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appPath toPath:newAppPath error:©Error]; if(suc) { - NSLog(@"[installApp] app installed, adding to icon cache now..."); + NSLog(@"[installApp] App %@ installed, adding to icon cache now...", appId); registerPath((char*)newAppPath.UTF8String, 0); return 0; } else { - return 1; + NSLog(@"[installApp] Failed to copy app bundle for app %@, error: %@", appId, copyError); + return 178; } } -int uninstallApp(NSString* appPath, NSString* appId, NSError** error) +int uninstallApp(NSString* appPath, NSString* appId) { LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId]; MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil]; NSString *containerPath = [appContainer url].path; if(containerPath) { - NSLog(@"deleting %@", containerPath); + NSLog(@"[uninstallApp] deleting %@", containerPath); // delete app container path - [[NSFileManager defaultManager] removeItemAtPath:containerPath error:error]; + [[NSFileManager defaultManager] removeItemAtPath:containerPath error:nil]; } // delete group container paths - [[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupID, NSURL* groupURL, BOOL* stop) + [[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupId, NSURL* groupURL, BOOL* stop) { - NSLog(@"deleting %@", groupURL); + // If another app still has this group, don't delete it + NSArray* appsWithGroup = applicationsWithGroupId(groupId); + if(appsWithGroup.count > 1) + { + NSLog(@"[uninstallApp] not deleting %@, appsWithGroup.count:%lu", groupURL, appsWithGroup.count); + return; + } + + NSLog(@"[uninstallApp] deleting %@", groupURL); [[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil]; }]; @@ -672,17 +760,17 @@ int uninstallApp(NSString* appPath, NSString* appId, NSError** error) NSURL* pluginURL = pluginProxy.dataContainerURL; if(pluginURL) { - NSLog(@"deleting %@", pluginURL); - [[NSFileManager defaultManager] removeItemAtURL:pluginURL error:error]; + NSLog(@"[uninstallApp] deleting %@", pluginURL); + [[NSFileManager defaultManager] removeItemAtURL:pluginURL error:nil]; } } // unregister app registerPath((char*)appPath.UTF8String, 1); - NSLog(@"deleting %@", [appPath stringByDeletingLastPathComponent]); + NSLog(@"[uninstallApp] deleting %@", [appPath stringByDeletingLastPathComponent]); // delete app - BOOL deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:error]; + BOOL deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:nil]; if(deleteSuc) { return 0; @@ -693,40 +781,65 @@ int uninstallApp(NSString* appPath, NSString* appId, NSError** error) } } -int uninstallAppByPath(NSString* appPath, NSError** error) +/*int detachApp(NSString* appId) +{ + NSString* appPath = appPathForAppId(appId); + NSString* executablePath = appMainExecutablePathForAppPath(appPath); + NSString* trollStoreMarkPath = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"]; + + // Not attached to TrollStore + if(![[NSFileManager defaultManager] fileExistsAtPath:trollStoreMarkPath]) return 0; + + // Refuse to detach app if it's still signed with fake root cert + SecStaticCodeRef codeRef = getStaticCodeRef(executablePath); + if(codeRef != NULL) + { + if(codeCertChainContainsFakeAppStoreExtensions(codeRef)) + { + CFRelease(codeRef); + return 184; + } + } + + // Deleting TrollStore mark to detach app + BOOL suc = [[NSFileManager defaultManager] removeItemAtPath:trollStoreMarkPath error:nil]; + return !suc; +}*/ + +int uninstallAppByPath(NSString* appPath) { if(!appPath) return 1; NSString* appId = appIdForAppPath(appPath); if(!appId) return 1; - return uninstallApp(appPath, appId, error); + return uninstallApp(appPath, appId); } -int uninstallAppById(NSString* appId, NSError** error) +int uninstallAppById(NSString* appId) { if(!appId) return 1; - NSString* appPath = appPathForAppId(appId, error); + NSString* appPath = appPathForAppId(appId); if(!appPath) return 1; - return uninstallApp(appPath, appId, error); + return uninstallApp(appPath, appId); } // 166: IPA does not exist or is not accessible // 167: IPA does not appear to contain an app -int installIpa(NSString* ipaPath, BOOL force, NSError** error) +int installIpa(NSString* ipaPath, BOOL force) { if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166; BOOL suc = NO; NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString]; - suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:error]; + suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:nil]; if(!suc) return 1; extract(ipaPath, tmpPath); NSString* tmpPayloadPath = [tmpPath stringByAppendingPathComponent:@"Payload"]; - NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpPayloadPath error:error]; + NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpPayloadPath error:nil]; if(!items) return 167; NSString* tmpAppPath; @@ -740,7 +853,7 @@ int installIpa(NSString* ipaPath, BOOL force, NSError** error) } if(!tmpAppPath) return 167; - int ret = installApp(tmpAppPath, YES, force, error); + int ret = installApp(tmpAppPath, YES, force); [[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil]; @@ -751,7 +864,7 @@ void uninstallAllApps(void) { for(NSString* appPath in trollStoreInstalledAppBundlePaths()) { - uninstallAppById(appIdForAppPath(appPath), nil); + uninstallAppById(appIdForAppPath(appPath)); } } @@ -815,7 +928,7 @@ BOOL installTrollStore(NSString* pathToTar) _installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper); } - return installApp(tmpTrollStore, NO, YES, nil);; + return installApp(tmpTrollStore, NO, YES);; } void refreshAppRegistrations() @@ -943,7 +1056,6 @@ int main(int argc, char *argv[], char *envp[]) { [mcmBundle load]; int ret = 0; - NSError* error; NSString* cmd = [NSString stringWithUTF8String:argv[1]]; if([cmd isEqualToString:@"install"]) @@ -960,17 +1072,22 @@ int main(int argc, char *argv[], char *envp[]) { } } NSString* ipaPath = [NSString stringWithUTF8String:argv[2]]; - ret = installIpa(ipaPath, force, &error); + ret = installIpa(ipaPath, force); } else if([cmd isEqualToString:@"uninstall"]) { if(argc <= 2) return -3; NSString* appId = [NSString stringWithUTF8String:argv[2]]; - ret = uninstallAppById(appId, &error); - } else if([cmd isEqualToString:@"uninstall-path"]) + ret = uninstallAppById(appId); + } /*else if([cmd isEqualToString:@"detach"]) + { + if(argc <= 2) return -3; + NSString* appId = [NSString stringWithUTF8String:argv[2]]; + ret = detachApp(appId); + } */else if([cmd isEqualToString:@"uninstall-path"]) { if(argc <= 2) return -3; NSString* appPath = [NSString stringWithUTF8String:argv[2]]; - ret = uninstallAppByPath(appPath, &error); + ret = uninstallAppByPath(appPath); }else if([cmd isEqualToString:@"install-trollstore"]) { if(argc <= 2) return -3; @@ -1003,11 +1120,6 @@ int main(int argc, char *argv[], char *envp[]) { uninstallPersistenceHelper(); } - if(error) - { - NSLog(@"error: %@", error); - } - NSLog(@"returning %d", ret); return ret; diff --git a/Helper/uicache.m b/Helper/uicache.m index 6b5aa9a..73eb782 100644 --- a/Helper/uicache.m +++ b/Helper/uicache.m @@ -142,6 +142,8 @@ void registerPath(char* cPath, int unregister) dictToRegister[@"SignerOrganization"] = @"Apple Inc."; dictToRegister[@"SignatureVersion"] = @132352; dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; + dictToRegister[@"IsAdHocSigned"] = @YES; + dictToRegister[@"LSInstallType"] = @1; NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements); if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier; diff --git a/PersistenceHelper/Resources/Info.plist b/PersistenceHelper/Resources/Info.plist index 15e42bc..610e4b8 100644 --- a/PersistenceHelper/Resources/Info.plist +++ b/PersistenceHelper/Resources/Info.plist @@ -52,7 +52,7 @@ iPhoneOS CFBundleVersion - 1.0.7 + 1.0.8 LSRequiresIPhoneOS UIDeviceFamily diff --git a/PersistenceHelper/TSPHRootViewController.m b/PersistenceHelper/TSPHRootViewController.m index 4fcbfb7..503e8f5 100644 --- a/PersistenceHelper/TSPHRootViewController.m +++ b/PersistenceHelper/TSPHRootViewController.m @@ -149,7 +149,7 @@ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ { - spawnRoot(helperPath(), @[@"refresh"]); + spawnRoot(helperPath(), @[@"refresh"], nil, nil); respring(); dispatch_async(dispatch_get_main_queue(), ^ @@ -187,7 +187,7 @@ NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"]; [[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil]; - int ret = spawnRoot(helperPath(), @[@"install-trollstore", tarTmpPath]); + int ret = spawnRoot(helperPath(), @[@"install-trollstore", tarTmpPath], nil, nil); dispatch_async(dispatch_get_main_queue(), ^ { [[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil]; @@ -223,7 +223,7 @@ UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) { - spawnRoot(helperPath(), @[@"uninstall-trollstore"]); + spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil); [self reloadSpecifiers]; }]; [uninstallWarningAlert addAction:continueAction]; @@ -240,7 +240,7 @@ UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) { - spawnRoot(helperPath(), @[@"uninstall-persistence-helper"]); + spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil); exit(0); }]; [uninstallWarningAlert addAction:continueAction]; diff --git a/PersistenceHelper/control b/PersistenceHelper/control index 79688ea..923af5d 100644 --- a/PersistenceHelper/control +++ b/PersistenceHelper/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstorehelper Name: TrollStore Helper -Version: 1.0.7 +Version: 1.0.8 Architecture: iphoneos-arm Description: Helper utility to install and manage TrollStore! Maintainer: opa334 diff --git a/Store/Resources/Info.plist b/Store/Resources/Info.plist index 4ad618f..919dd4c 100644 --- a/Store/Resources/Info.plist +++ b/Store/Resources/Info.plist @@ -50,7 +50,7 @@ iPhoneOS CFBundleVersion - 1.0.7 + 1.0.8 LSRequiresIPhoneOS UIDeviceFamily diff --git a/Store/TSAppTableViewController.m b/Store/TSAppTableViewController.m index 72549ce..cb466e8 100644 --- a/Store/TSAppTableViewController.m +++ b/Store/TSAppTableViewController.m @@ -28,6 +28,48 @@ self.tableView.allowsMultipleSelectionDuringEditing = NO; } +- (void)showError:(NSError*)error +{ + UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Error %ld", error.code] message:error.localizedDescription preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil]; + [errorAlert addAction:closeAction]; + [self presentViewController:errorAlert animated:YES completion:nil]; +} + +- (void)uninstallPressedForRowAtIndexPath:(NSIndexPath*)indexPath +{ + TSApplicationsManager* appsManager = [TSApplicationsManager sharedInstance]; + + NSString* appPath = [appsManager installedAppPaths][indexPath.row]; + NSString* appId = [appsManager appIdForAppPath:appPath]; + NSString* appName = [appsManager displayNameForAppPath:appPath]; + + UIAlertController* confirmAlert = [UIAlertController alertControllerWithTitle:@"Confirm Uninstallation" message:[NSString stringWithFormat:@"Uninstalling the app '%@' will delete the app and all data associated to it.", appName] preferredStyle:UIAlertControllerStyleAlert]; + + UIAlertAction* uninstallAction = [UIAlertAction actionWithTitle:@"Uninstall" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) + { + if(appId) + { + [appsManager uninstallApp:appId]; + } + else + { + [appsManager uninstallAppByPath:appPath]; + } + }]; + [confirmAlert addAction:uninstallAction]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]; + [confirmAlert addAction:cancelAction]; + + [self presentViewController:confirmAlert animated:YES completion:nil]; +} + +- (void)deselectRow +{ + [self.tableView deselectRowAtIndexPath:[self.tableView indexPathForSelectedRow] animated:YES]; +} + #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { @@ -51,20 +93,50 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { - if (editingStyle == UITableViewCellEditingStyleDelete) + if(editingStyle == UITableViewCellEditingStyleDelete) { - NSString* appPath = [[TSApplicationsManager sharedInstance] installedAppPaths][indexPath.row]; - NSString* appId = [[TSApplicationsManager sharedInstance] appIdForAppPath:appPath]; - - if(appId) - { - [[TSApplicationsManager sharedInstance] uninstallApp:appId]; - } - else - { - [[TSApplicationsManager sharedInstance] uninstallAppByPath:appPath]; - } + [self uninstallPressedForRowAtIndexPath:indexPath]; } } +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + TSApplicationsManager* appsManager = [TSApplicationsManager sharedInstance]; + + NSString* appPath = [appsManager installedAppPaths][indexPath.row]; + NSString* appId = [appsManager appIdForAppPath:appPath]; + NSString* appName = [appsManager displayNameForAppPath:appPath]; + + UIAlertController* appSelectAlert = [UIAlertController alertControllerWithTitle:appName message:appId preferredStyle:UIAlertControllerStyleActionSheet]; + + /*UIAlertAction* detachAction = [UIAlertAction actionWithTitle:@"Detach from TrollStore" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) + { + int detachRet = [appsManager detachFromApp:appId]; + if(detachRet != 0) + { + [self showError:[appsManager errorForCode:detachRet]]; + } + [self deselectRow]; + }]; + [appSelectAlert addAction:detachAction];*/ + + UIAlertAction* uninstallAction = [UIAlertAction actionWithTitle:@"Uninstall App" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) + { + [self uninstallPressedForRowAtIndexPath:indexPath]; + [self deselectRow]; + }]; + [appSelectAlert addAction:uninstallAction]; + + UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action) + { + [self deselectRow]; + }]; + [appSelectAlert addAction:cancelAction]; + + appSelectAlert.popoverPresentationController.sourceView = tableView; + appSelectAlert.popoverPresentationController.sourceRect = [tableView rectForRowAtIndexPath:indexPath]; + + [self presentViewController:appSelectAlert animated:YES completion:nil]; +} + @end \ No newline at end of file diff --git a/Store/TSApplicationsManager.h b/Store/TSApplicationsManager.h index b8f8a41..ac37385 100644 --- a/Store/TSApplicationsManager.h +++ b/Store/TSApplicationsManager.h @@ -14,9 +14,10 @@ - (NSString*)displayNameForAppPath:(NSString*)appPath; - (NSError*)errorForCode:(int)code; -- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force; +- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut; - (int)installIpa:(NSString*)pathToIpa; - (int)uninstallApp:(NSString*)appId; - (int)uninstallAppByPath:(NSString*)path; +//- (int)detachFromApp:(NSString*)appId; @end \ No newline at end of file diff --git a/Store/TSApplicationsManager.m b/Store/TSApplicationsManager.m index 328c7f9..9ac0f79 100644 --- a/Store/TSApplicationsManager.m +++ b/Store/TSApplicationsManager.m @@ -24,7 +24,13 @@ - (NSDictionary*)infoDictionaryForAppPath:(NSString*)appPath { NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"]; - return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath]; + NSError* error; + NSDictionary* infoDict = [NSDictionary dictionaryWithContentsOfURL:[NSURL fileURLWithPath:infoPlistPath] error:&error]; + if(error) + { + NSLog(@"error getting info dict: %@", error); + } + return infoDict; } - (NSString*)appIdForAppPath:(NSString*)appPath @@ -35,7 +41,6 @@ - (NSString*)displayNameForAppPath:(NSString*)appPath { NSDictionary* infoDict = [self infoDictionaryForAppPath:appPath]; - NSString* displayName = infoDict[@"CFBundleDisplayName"]; if(![displayName isKindOfClass:[NSString class]]) displayName = nil; if(!displayName || [displayName isEqualToString:@""]) @@ -57,12 +62,14 @@ NSString* errorDescription = @"Unknown Error"; switch(code) { + // IPA install errors case 166: errorDescription = @"The IPA file does not exist or is not accessible."; break; case 167: errorDescription = @"The IPA file does not appear to contain an app."; break; + // App install errors case 170: errorDescription = @"Failed to create container for app bundle."; break; @@ -70,27 +77,46 @@ errorDescription = @"A non-TrollStore app with the same identifier is already installed. If you are absolutely sure it is not, you can force install it."; break; case 172: - errorDescription = @"The app does not seem to contain an Info.plist"; + errorDescription = @"The app does not contain an Info.plist file."; break; case 173: - errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid does not seem to be installed. Make sure ldid is installed in the settings tab and try again."; + errorDescription = @"The app is not signed with a fake CoreTrust certificate and ldid is not installed. Install ldid in the settings tab and try again."; break; + case 174: + errorDescription = @"The apps main executable does not exists."; + break; + case 175: + errorDescription = @"Failed to sign the app. ldid returned a non zero status code."; + break; + case 176: + errorDescription = @"The apps Info.plist is missing required values."; + break; + case 177: + errorDescription = @"Failed to mark app as TrollStore app."; + break; + case 178: + errorDescription = @"Failed to copy app bundle."; + break; + // App detach errors + /*case 184: + errorDescription = @"Refusing to detach, the app is still signed with a fake root certificate. The detach option is only for when you have installed an App Store app on top of a TrollStore app."; + break;*/ } NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}]; return error; } -- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force +- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut { int ret; if(force) { - ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"]); + ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"], nil, logOut); } else { - ret = spawnRoot(helperPath(), @[@"install", pathToIpa]); + ret = spawnRoot(helperPath(), @[@"install", pathToIpa], nil, logOut); } [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; return ret; @@ -98,13 +124,13 @@ - (int)installIpa:(NSString*)pathToIpa { - return [self installIpa:pathToIpa force:NO]; + return [self installIpa:pathToIpa force:NO log:nil]; } - (int)uninstallApp:(NSString*)appId { if(!appId) return -200; - int ret = spawnRoot(helperPath(), @[@"uninstall", appId]); + int ret = spawnRoot(helperPath(), @[@"uninstall", appId], nil, nil); [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; return ret; } @@ -112,9 +138,17 @@ - (int)uninstallAppByPath:(NSString*)path { if(!path) return -200; - int ret = spawnRoot(helperPath(), @[@"uninstall-path", path]); + int ret = spawnRoot(helperPath(), @[@"uninstall-path", path], nil, nil); [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; return ret; } +/*- (int)detachFromApp:(NSString*)appId +{ + if(!appId) return -200; + int ret = spawnRoot(helperPath(), @[@"detach", appId], nil, nil); + [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; + return ret; +}*/ + @end \ No newline at end of file diff --git a/Store/TSSceneDelegate.m b/Store/TSSceneDelegate.m index a09325c..59f8667 100644 --- a/Store/TSSceneDelegate.m +++ b/Store/TSSceneDelegate.m @@ -7,163 +7,180 @@ - (void)doIPAInstall:(NSString*)ipaPath scene:(UIWindowScene*)scene force:(BOOL)force completion:(void (^)(void))completion { - UIWindow* keyWindow = nil; - for(UIWindow* window in scene.windows) - { - if(window.isKeyWindow) - { - keyWindow = window; - break; - } - } + UIWindow* keyWindow = nil; + for(UIWindow* window in scene.windows) + { + if(window.isKeyWindow) + { + keyWindow = window; + break; + } + } - UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert]; - UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)]; - activityIndicator.hidesWhenStopped = YES; - activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium; - [activityIndicator startAnimating]; - [infoAlert.view addSubview:activityIndicator]; + UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert]; + UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)]; + activityIndicator.hidesWhenStopped = YES; + activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium; + [activityIndicator startAnimating]; + [infoAlert.view addSubview:activityIndicator]; - [keyWindow.rootViewController presentViewController:infoAlert animated:YES completion:nil]; + [keyWindow.rootViewController presentViewController:infoAlert animated:YES completion:nil]; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ - { - // Install IPA - int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force]; - NSError* error = [[TSApplicationsManager sharedInstance] errorForCode:ret]; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ + { + // Install IPA + //NSString* log; + int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force log:nil]; - NSLog(@"installed app! ret:%d, error: %@", ret, error); - dispatch_async(dispatch_get_main_queue(), ^ - { - [infoAlert dismissViewControllerAnimated:YES completion:^ - { - if(ret != 0) - { - UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) - { - if(ret == 171) - { - completion(); - } - }]; - if(ret == 171) - { - UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) - { - [self doIPAInstall:ipaPath scene:scene force:YES completion:completion]; - }]; - [errorAlert addAction:forceInstallAction]; - } - [errorAlert addAction:closeAction]; + NSError* error; + if(ret != 0) + { + error = [[TSApplicationsManager sharedInstance] errorForCode:ret]; + } - [keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil]; - } + NSLog(@"installed app! ret:%d, error: %@", ret, error); - if(ret != 171) - { - completion(); - } - }]; - }); - }); + dispatch_async(dispatch_get_main_queue(), ^ + { + [infoAlert dismissViewControllerAnimated:YES completion:^ + { + if(ret != 0) + { + UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) + { + if(ret == 171) + { + completion(); + } + }]; + [errorAlert addAction:closeAction]; + + if(ret == 171) + { + UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) + { + [self doIPAInstall:ipaPath scene:scene force:YES completion:completion]; + }]; + [errorAlert addAction:forceInstallAction]; + } + else + { + /*UIAlertAction* copyLogAction = [UIAlertAction actionWithTitle:@"Copy Log" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) + { + UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = log; + }]; + [errorAlert addAction:copyLogAction];*/ + } + + [keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil]; + } + + if(ret != 171) + { + completion(); + } + }]; + }); + }); } - (void)handleURLContexts:(NSSet *)URLContexts scene:(UIWindowScene*)scene { - for(UIOpenURLContext* context in URLContexts) - { - NSLog(@"openURLContexts %@", context.URL); - NSURL* url = context.URL; - if (url != nil && [url isFileURL]) { - [url startAccessingSecurityScopedResource]; - void (^doneBlock)(BOOL) = ^(BOOL shouldExit) - { - [url stopAccessingSecurityScopedResource]; - [[NSFileManager defaultManager] removeItemAtURL:url error:nil]; + for(UIOpenURLContext* context in URLContexts) + { + NSLog(@"openURLContexts %@", context.URL); + NSURL* url = context.URL; + if (url != nil && [url isFileURL]) { + [url startAccessingSecurityScopedResource]; + void (^doneBlock)(BOOL) = ^(BOOL shouldExit) + { + [url stopAccessingSecurityScopedResource]; + [[NSFileManager defaultManager] removeItemAtURL:url error:nil]; - if(shouldExit) - { - NSLog(@"Respring + Exit"); - respring(); - exit(0); - } - }; - - if ([url.pathExtension isEqualToString:@"ipa"]) - { - [self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{ - doneBlock(NO); - }]; - } - else if([url.pathExtension isEqualToString:@"tar"]) - { - // Update TrollStore itself - NSLog(@"Updating TrollStore..."); - int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path]); - doneBlock(ret == 0); - NSLog(@"Updated TrollStore!"); - } - } - } + if(shouldExit) + { + NSLog(@"Respring + Exit"); + respring(); + exit(0); + } + }; + + if ([url.pathExtension isEqualToString:@"ipa"]) + { + [self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{ + doneBlock(NO); + }]; + } + else if([url.pathExtension isEqualToString:@"tar"]) + { + // Update TrollStore itself + NSLog(@"Updating TrollStore..."); + int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path], nil, nil); + doneBlock(ret == 0); + NSLog(@"Updated TrollStore!"); + } + } + } } - (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { - // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. - // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. - // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - - NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions); - UIWindowScene* windowScene = (UIWindowScene*)scene; - _window = [[UIWindow alloc] initWithWindowScene:windowScene]; - _rootViewController = [[TSRootViewController alloc] init]; - _window.rootViewController = _rootViewController; + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + + NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions); + UIWindowScene* windowScene = (UIWindowScene*)scene; + _window = [[UIWindow alloc] initWithWindowScene:windowScene]; + _rootViewController = [[TSRootViewController alloc] init]; + _window.rootViewController = _rootViewController; [_window makeKeyAndVisible]; - if(connectionOptions.URLContexts.count) - { - [self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene]; - } + if(connectionOptions.URLContexts.count) + { + [self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene]; + } } - (void)sceneDidDisconnect:(UIScene *)scene { - // Called as the scene is being released by the system. - // This occurs shortly after the scene enters the background, or when its session is discarded. - // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } - (void)sceneDidBecomeActive:(UIScene *)scene { - // Called when the scene has moved from an inactive state to an active state. - // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } - (void)sceneWillResignActive:(UIScene *)scene { - // Called when the scene will move from an active state to an inactive state. - // This may occur due to temporary interruptions (ex. an incoming phone call). + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). } - (void)sceneWillEnterForeground:(UIScene *)scene { - // Called as the scene transitions from the background to the foreground. - // Use this method to undo the changes made on entering the background. + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. } - (void)sceneDidEnterBackground:(UIScene *)scene { - // Called as the scene transitions from the foreground to the background. - // Use this method to save data, release shared resources, and store enough scene-specific state information - // to restore the scene back to its current state. + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. } - (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts { - NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts); - [self handleURLContexts:URLContexts scene:(UIWindowScene*)scene]; + NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts); + [self handleURLContexts:URLContexts scene:(UIWindowScene*)scene]; } @end \ No newline at end of file diff --git a/Store/TSSettingsListController.m b/Store/TSSettingsListController.m index 2885116..758253e 100644 --- a/Store/TSSettingsListController.m +++ b/Store/TSSettingsListController.m @@ -225,7 +225,7 @@ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ { - spawnRoot(helperPath(), @[@"refresh-all"]); + spawnRoot(helperPath(), @[@"refresh-all"], nil, nil); dispatch_async(dispatch_get_main_queue(), ^ { @@ -259,7 +259,7 @@ } else { - spawnRoot(helperPath(), @[@"install-ldid", location.path]); + spawnRoot(helperPath(), @[@"install-ldid", location.path], nil, nil); dispatch_async(dispatch_get_main_queue(), ^ { [self stopActivityWithCompletion:nil]; @@ -294,7 +294,7 @@ { UIAlertAction* installAction = [UIAlertAction actionWithTitle:[appProxy localizedName] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) { - spawnRoot(helperPath(), @[@"install-persistence-helper", appProxy.bundleIdentifier]); + spawnRoot(helperPath(), @[@"install-persistence-helper", appProxy.bundleIdentifier], nil, nil); [self reloadSpecifiers]; }]; @@ -314,7 +314,7 @@ - (void)uninstallPersistenceHelperPressed { - spawnRoot(helperPath(), @[@"uninstall-persistence-helper"]); + spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil); [self reloadSpecifiers]; } @@ -327,7 +327,7 @@ UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) { - spawnRoot(helperPath(), @[@"uninstall-trollstore"]); + spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil); exit(0); }]; [uninstallWarningAlert addAction:continueAction]; diff --git a/Store/TSUtil.h b/Store/TSUtil.h index fc2ab3e..55afe23 100644 --- a/Store/TSUtil.h +++ b/Store/TSUtil.h @@ -1,6 +1,7 @@ @import Foundation; extern NSString* helperPath(void); -extern int spawnRoot(NSString* path, NSArray* args); +extern void printMultilineNSString(NSString* stringToPrint); +extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr); extern void respring(void); extern NSString* getTrollStoreVersion(void); \ No newline at end of file diff --git a/Store/TSUtil.m b/Store/TSUtil.m index cf5e1ee..aee6b86 100644 --- a/Store/TSUtil.m +++ b/Store/TSUtil.m @@ -14,7 +14,29 @@ NSString* helperPath(void) return [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"trollstorehelper"]; } -int spawnRoot(NSString* path, NSArray* args) +NSString* getNSStringFromFile(int fd) +{ + NSMutableString* ms = [NSMutableString new]; + ssize_t num_read; + char c; + while((num_read = read(fd, &c, sizeof(c)))) + { + [ms appendString:[NSString stringWithFormat:@"%c", c]]; + } + return ms.copy; +} + +void printMultilineNSString(NSString* stringToPrint) +{ + NSCharacterSet *separator = [NSCharacterSet newlineCharacterSet]; + NSArray* lines = [stringToPrint componentsSeparatedByCharactersInSet:separator]; + for(NSString* line in lines) + { + NSLog(@"%@", line); + } +} + +int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdErr) { NSMutableArray* argsM = args.mutableCopy ?: [NSMutableArray new]; [argsM insertObject:path.lastPathComponent atIndex:0]; @@ -28,18 +50,35 @@ int spawnRoot(NSString* path, NSArray* args) } argsC[argCount] = NULL; - int rv; posix_spawnattr_t attr; - rv = posix_spawnattr_init(&attr); - if(rv != 0) return rv; + posix_spawnattr_init(&attr); posix_spawnattr_set_persona_np(&attr, 99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE); posix_spawnattr_set_persona_uid_np(&attr, 0); posix_spawnattr_set_persona_gid_np(&attr, 0); + + posix_spawn_file_actions_t action; + posix_spawn_file_actions_init(&action); + + int outErr[2]; + if(stdErr) + { + pipe(outErr); + posix_spawn_file_actions_adddup2(&action, outErr[1], STDERR_FILENO); + posix_spawn_file_actions_addclose(&action, outErr[0]); + } + + int out[2]; + if(stdOut) + { + pipe(out); + posix_spawn_file_actions_adddup2(&action, out[1], STDOUT_FILENO); + posix_spawn_file_actions_addclose(&action, out[0]); + } pid_t task_pid; int status = -200; - int spawnError = posix_spawn(&task_pid, [path UTF8String], NULL, &attr, (char* const*)argsC, NULL); + int spawnError = posix_spawn(&task_pid, [path UTF8String], &action, &attr, (char* const*)argsC, NULL); posix_spawnattr_destroy(&attr); for (NSUInteger i = 0; i < argCount; i++) { @@ -63,6 +102,20 @@ int spawnRoot(NSString* path, NSArray* args) return -222; } } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + + if(stdOut) + { + close(out[1]); + NSString* output = getNSStringFromFile(out[0]); + *stdOut = output; + } + + if(stdErr) + { + close(outErr[1]); + NSString* errorOutput = getNSStringFromFile(outErr[0]); + *stdErr = errorOutput; + } return WEXITSTATUS(status); } diff --git a/Store/control b/Store/control index c215f6c..58382ff 100644 --- a/Store/control +++ b/Store/control @@ -1,6 +1,6 @@ Package: com.opa334.trollstore Name: TrollStore -Version: 1.0.7 +Version: 1.0.8 Architecture: iphoneos-arm Description: An awesome application! Maintainer: opa334