This commit is contained in:
opa334 2022-09-09 20:22:34 +02:00
parent ab3261f0f2
commit 5d474901a2
16 changed files with 533 additions and 235 deletions

View File

@ -14,6 +14,7 @@
@property (getter=isInstalled,nonatomic,readonly) BOOL installed; @property (getter=isInstalled,nonatomic,readonly) BOOL installed;
@property (getter=isPlaceholder,nonatomic,readonly) BOOL placeholder; @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 @end
@interface LSApplicationWorkspace : NSObject @interface LSApplicationWorkspace : NSObject
@ -25,6 +26,11 @@
- (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy*))block; - (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy*))block;
@end @end
@interface LSEnumerator : NSEnumerator
@property (nonatomic,copy) NSPredicate * predicate;
+ (instancetype)enumeratorForApplicationProxiesWithOptions:(NSUInteger)options;
@end
@interface LSPlugInKitProxy : LSBundleProxy @interface LSPlugInKitProxy : LSBundleProxy
@property (nonatomic,readonly) NSString* pluginIdentifier; @property (nonatomic,readonly) NSString* pluginIdentifier;
@property (nonatomic,readonly) NSDictionary * pluginKitDictionary; @property (nonatomic,readonly) NSDictionary * pluginKitDictionary;

View File

@ -1,6 +1,6 @@
Package: com.opa334.trollstoreroothelper Package: com.opa334.trollstoreroothelper
Name: trollstoreroothelper Name: trollstoreroothelper
Version: 1.0.6 Version: 1.0.8
Architecture: iphoneos-arm Architecture: iphoneos-arm
Description: An awesome tool of some sort!! Description: An awesome tool of some sort!!
Maintainer: opa334 Maintainer: opa334

View File

@ -54,6 +54,28 @@ typedef CFDictionaryRef (*_CFPreferencesCopyMultipleWithContainerType)(CFArrayRe
BOOL _installPersistenceHelper(LSApplicationProxy* appProxy, NSString* sourcePersistenceHelper, NSString* sourceRootHelper); BOOL _installPersistenceHelper(LSApplicationProxy* appProxy, NSString* sourcePersistenceHelper, NSString* sourceRootHelper);
NSArray<LSApplicationProxy*>* applicationsWithGroupId(NSString* groupId)
{
LSEnumerator* enumerator = [LSEnumerator enumeratorForApplicationProxiesWithOptions:0];
enumerator.predicate = [NSPredicate predicateWithFormat:@"groupContainerURLs[%@] != nil", groupId];
return enumerator.allObjects;
}
NSSet<NSString*>* 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(); extern char*** _NSGetArgv();
NSString* safe_getExecutablePath() NSString* safe_getExecutablePath()
{ {
@ -72,7 +94,12 @@ NSString* appIdForAppPath(NSString* appPath)
return infoDictionaryForAppPath(appPath)[@"CFBundleIdentifier"]; 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()) for(NSString* appPath in trollStoreInstalledAppBundlePaths())
{ {
@ -411,15 +438,15 @@ BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef)
return evaluatesToCustomAnchor; return evaluatesToCustomAnchor;
} }
BOOL signApp(NSString* appPath, NSError** error) int signApp(NSString* appPath)
{ {
NSDictionary* appInfoDict = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]]; NSDictionary* appInfoDict = infoDictionaryForAppPath(appPath);
if(!appInfoDict) return NO; if(!appInfoDict) return 172;
NSString* executable = appInfoDict[@"CFBundleExecutable"]; NSString* executablePath = appMainExecutablePathForAppPath(appPath);
NSString* executablePath = [appPath stringByAppendingPathComponent:executable]; if(!executablePath) return 176;
if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO; if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return 174;
NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"];
if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]])
@ -430,7 +457,7 @@ BOOL signApp(NSString* appPath, NSError** error)
if([tsBundleIsPreSignedNum boolValue] == YES) if([tsBundleIsPreSignedNum boolValue] == YES)
{ {
NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath); 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); NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath);
CFRelease(codeRef); CFRelease(codeRef);
return YES; return 0;
} }
} }
else 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); 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* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"];
NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath]; NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath];
@ -481,7 +508,14 @@ BOOL signApp(NSString* appPath, NSError** error)
NSLog(@"- ldid error output end -"); NSLog(@"- ldid error output end -");
return ldidRet == 0; if(ldidRet == 0)
{
return 0;
}
else
{
return 175;
}
} }
void applyPatchesToInfoDictionary(NSString* appPath) void applyPatchesToInfoDictionary(NSString* appPath)
@ -491,9 +525,34 @@ void applyPatchesToInfoDictionary(NSString* appPath)
NSMutableDictionary* infoDictM = [[NSDictionary dictionaryWithContentsOfURL:infoPlistURL error:nil] mutableCopy]; NSMutableDictionary* infoDictM = [[NSDictionary dictionaryWithContentsOfURL:infoPlistURL error:nil] mutableCopy];
if(!infoDictM) return; if(!infoDictM) return;
// enable notifications // Enable Notifications
infoDictM[@"SBAppUsesLocalNotifications"] = @1; 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]; [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 // 171: a non trollstore app with the same identifier is already installled
// 172: no info.plist found in app // 172: no info.plist found in app
// 173: app is not signed and cannot be signed because ldid not installed or didn't work // 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); NSLog(@"[installApp force = %d]", force);
if(!infoDictionaryForAppPath(appPath)) return 172;
NSString* appId = appIdForAppPath(appPath); NSString* appId = appIdForAppPath(appPath);
if(!appId) return 172; if(!appId) return 176;
applyPatchesToInfoDictionary(appPath); applyPatchesToInfoDictionary(appPath);
if(sign) if(sign)
{ {
if(!signApp(appPath, error)) return 173; int signRet = signApp(appPath);
if(signRet != 0) return signRet;
} }
BOOL existed; BOOL existed;
NSError* mcmError; NSError* mcmError;
MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError]; MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError];
NSLog(@"[installApp] appContainer: %@, mcmError: %@", appContainer, mcmError);
if(!appContainer || mcmError) if(!appContainer || mcmError)
{ {
if(error) *error = mcmError; NSLog(@"[installApp] failed to create app container for %@: %@", appId, mcmError);
return 170; return 170;
} }
if(existed)
{
NSLog(@"[installApp] got existing app container: %@", appContainer);
}
else
{
NSLog(@"[installApp] created app container: %@", appContainer);
}
// check if the bundle is empty // check if the bundle is empty
BOOL isEmpty = YES; 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) for(NSString* bundleItem in bundleItems)
{ {
if([bundleItem.pathExtension isEqualToString:@"app"]) 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 // Make sure there isn't already an app store app installed with the same identifier
NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"]; NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"];
if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force) 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 // 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) // Apply correct permissions (First run, set everything to 644, owner 33)
NSURL* fileURL; NSURL* fileURL;
@ -556,6 +634,7 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error)
NSString* filePath = fileURL.path; NSString* filePath = fileURL.path;
chown(filePath.UTF8String, 33, 33); chown(filePath.UTF8String, 33, 33);
chmod(filePath.UTF8String, 0644); 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) // 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]; NSDictionary* infoDictionary = [NSDictionary dictionaryWithContentsOfFile:filePath];
NSString* executable = infoDictionary[@"CFBundleExecutable"]; NSString* executable = infoDictionary[@"CFBundleExecutable"];
if(executable) if(executable && [executable isKindOfClass:[NSString class]])
{ {
NSString* executablePath = [[filePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:executable]; NSString* executablePath = [[filePath stringByDeletingLastPathComponent] stringByAppendingPathComponent:executable];
chmod(executablePath.UTF8String, 0755); 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"]) 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 // Set .app directory permissions too
NSDictionary* mainInfoDictionary = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]]; chmod(appPath.UTF8String, 0755);
if(!mainInfoDictionary) return 172; chown(appPath.UTF8String, 33, 33);
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);
}
}
}
}
// Wipe old version if needed // Wipe old version if needed
if(existed) if(existed)
@ -634,35 +712,45 @@ int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error)
NSString* newAppPath = [appContainer.url.path stringByAppendingPathComponent:appPath.lastPathComponent]; NSString* newAppPath = [appContainer.url.path stringByAppendingPathComponent:appPath.lastPathComponent];
NSLog(@"[installApp] new app path: %@", newAppPath); 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:&copyError];
if(suc) 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); registerPath((char*)newAppPath.UTF8String, 0);
return 0; return 0;
} }
else 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]; LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil]; MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
NSString *containerPath = [appContainer url].path; NSString *containerPath = [appContainer url].path;
if(containerPath) if(containerPath)
{ {
NSLog(@"deleting %@", containerPath); NSLog(@"[uninstallApp] deleting %@", containerPath);
// delete app container path // delete app container path
[[NSFileManager defaultManager] removeItemAtPath:containerPath error:error]; [[NSFileManager defaultManager] removeItemAtPath:containerPath error:nil];
} }
// delete group container paths // 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<LSApplicationProxy*>* 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]; [[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil];
}]; }];
@ -672,17 +760,17 @@ int uninstallApp(NSString* appPath, NSString* appId, NSError** error)
NSURL* pluginURL = pluginProxy.dataContainerURL; NSURL* pluginURL = pluginProxy.dataContainerURL;
if(pluginURL) if(pluginURL)
{ {
NSLog(@"deleting %@", pluginURL); NSLog(@"[uninstallApp] deleting %@", pluginURL);
[[NSFileManager defaultManager] removeItemAtURL:pluginURL error:error]; [[NSFileManager defaultManager] removeItemAtURL:pluginURL error:nil];
} }
} }
// unregister app // unregister app
registerPath((char*)appPath.UTF8String, 1); registerPath((char*)appPath.UTF8String, 1);
NSLog(@"deleting %@", [appPath stringByDeletingLastPathComponent]); NSLog(@"[uninstallApp] deleting %@", [appPath stringByDeletingLastPathComponent]);
// delete app // delete app
BOOL deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:error]; BOOL deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:nil];
if(deleteSuc) if(deleteSuc)
{ {
return 0; 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; if(!appPath) return 1;
NSString* appId = appIdForAppPath(appPath); NSString* appId = appIdForAppPath(appPath);
if(!appId) return 1; 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; if(!appId) return 1;
NSString* appPath = appPathForAppId(appId, error); NSString* appPath = appPathForAppId(appId);
if(!appPath) return 1; if(!appPath) return 1;
return uninstallApp(appPath, appId, error); return uninstallApp(appPath, appId);
} }
// 166: IPA does not exist or is not accessible // 166: IPA does not exist or is not accessible
// 167: IPA does not appear to contain an app // 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; if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166;
BOOL suc = NO; BOOL suc = NO;
NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString]; 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; if(!suc) return 1;
extract(ipaPath, tmpPath); extract(ipaPath, tmpPath);
NSString* tmpPayloadPath = [tmpPath stringByAppendingPathComponent:@"Payload"]; 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; if(!items) return 167;
NSString* tmpAppPath; NSString* tmpAppPath;
@ -740,7 +853,7 @@ int installIpa(NSString* ipaPath, BOOL force, NSError** error)
} }
if(!tmpAppPath) return 167; if(!tmpAppPath) return 167;
int ret = installApp(tmpAppPath, YES, force, error); int ret = installApp(tmpAppPath, YES, force);
[[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil];
@ -751,7 +864,7 @@ void uninstallAllApps(void)
{ {
for(NSString* appPath in trollStoreInstalledAppBundlePaths()) for(NSString* appPath in trollStoreInstalledAppBundlePaths())
{ {
uninstallAppById(appIdForAppPath(appPath), nil); uninstallAppById(appIdForAppPath(appPath));
} }
} }
@ -815,7 +928,7 @@ BOOL installTrollStore(NSString* pathToTar)
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper); _installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
} }
return installApp(tmpTrollStore, NO, YES, nil);; return installApp(tmpTrollStore, NO, YES);;
} }
void refreshAppRegistrations() void refreshAppRegistrations()
@ -943,7 +1056,6 @@ int main(int argc, char *argv[], char *envp[]) {
[mcmBundle load]; [mcmBundle load];
int ret = 0; int ret = 0;
NSError* error;
NSString* cmd = [NSString stringWithUTF8String:argv[1]]; NSString* cmd = [NSString stringWithUTF8String:argv[1]];
if([cmd isEqualToString:@"install"]) if([cmd isEqualToString:@"install"])
@ -960,17 +1072,22 @@ int main(int argc, char *argv[], char *envp[]) {
} }
} }
NSString* ipaPath = [NSString stringWithUTF8String:argv[2]]; NSString* ipaPath = [NSString stringWithUTF8String:argv[2]];
ret = installIpa(ipaPath, force, &error); ret = installIpa(ipaPath, force);
} else if([cmd isEqualToString:@"uninstall"]) } else if([cmd isEqualToString:@"uninstall"])
{ {
if(argc <= 2) return -3; if(argc <= 2) return -3;
NSString* appId = [NSString stringWithUTF8String:argv[2]]; NSString* appId = [NSString stringWithUTF8String:argv[2]];
ret = uninstallAppById(appId, &error); ret = uninstallAppById(appId);
} else if([cmd isEqualToString:@"uninstall-path"]) } /*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; if(argc <= 2) return -3;
NSString* appPath = [NSString stringWithUTF8String:argv[2]]; NSString* appPath = [NSString stringWithUTF8String:argv[2]];
ret = uninstallAppByPath(appPath, &error); ret = uninstallAppByPath(appPath);
}else if([cmd isEqualToString:@"install-trollstore"]) }else if([cmd isEqualToString:@"install-trollstore"])
{ {
if(argc <= 2) return -3; if(argc <= 2) return -3;
@ -1003,11 +1120,6 @@ int main(int argc, char *argv[], char *envp[]) {
uninstallPersistenceHelper(); uninstallPersistenceHelper();
} }
if(error)
{
NSLog(@"error: %@", error);
}
NSLog(@"returning %d", ret); NSLog(@"returning %d", ret);
return ret; return ret;

View File

@ -142,6 +142,8 @@ void registerPath(char* cPath, int unregister)
dictToRegister[@"SignerOrganization"] = @"Apple Inc."; dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
dictToRegister[@"SignatureVersion"] = @132352; dictToRegister[@"SignatureVersion"] = @132352;
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing"; dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
dictToRegister[@"IsAdHocSigned"] = @YES;
dictToRegister[@"LSInstallType"] = @1;
NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements); NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier; if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;

View File

@ -52,7 +52,7 @@
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0.7</string> <string>1.0.8</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>

View File

@ -149,7 +149,7 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{ {
spawnRoot(helperPath(), @[@"refresh"]); spawnRoot(helperPath(), @[@"refresh"], nil, nil);
respring(); respring();
dispatch_async(dispatch_get_main_queue(), ^ dispatch_async(dispatch_get_main_queue(), ^
@ -187,7 +187,7 @@
NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"]; NSString* tarTmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"TrollStore.tar"];
[[NSFileManager defaultManager] copyItemAtPath:location.path toPath:tarTmpPath error:nil]; [[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(), ^ dispatch_async(dispatch_get_main_queue(), ^
{ {
[[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:tarTmpPath error:nil];
@ -223,7 +223,7 @@
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{ {
spawnRoot(helperPath(), @[@"uninstall-trollstore"]); spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
[self reloadSpecifiers]; [self reloadSpecifiers];
}]; }];
[uninstallWarningAlert addAction:continueAction]; [uninstallWarningAlert addAction:continueAction];
@ -240,7 +240,7 @@
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{ {
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"]); spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
exit(0); exit(0);
}]; }];
[uninstallWarningAlert addAction:continueAction]; [uninstallWarningAlert addAction:continueAction];

View File

@ -1,6 +1,6 @@
Package: com.opa334.trollstorehelper Package: com.opa334.trollstorehelper
Name: TrollStore Helper Name: TrollStore Helper
Version: 1.0.7 Version: 1.0.8
Architecture: iphoneos-arm Architecture: iphoneos-arm
Description: Helper utility to install and manage TrollStore! Description: Helper utility to install and manage TrollStore!
Maintainer: opa334 Maintainer: opa334

View File

@ -50,7 +50,7 @@
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0.7</string> <string>1.0.8</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>
<true/> <true/>
<key>UIDeviceFamily</key> <key>UIDeviceFamily</key>

View File

@ -28,6 +28,48 @@
self.tableView.allowsMultipleSelectionDuringEditing = NO; 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 #pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
@ -51,20 +93,50 @@
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{ {
if (editingStyle == UITableViewCellEditingStyleDelete) if(editingStyle == UITableViewCellEditingStyleDelete)
{ {
NSString* appPath = [[TSApplicationsManager sharedInstance] installedAppPaths][indexPath.row]; [self uninstallPressedForRowAtIndexPath:indexPath];
NSString* appId = [[TSApplicationsManager sharedInstance] appIdForAppPath:appPath];
if(appId)
{
[[TSApplicationsManager sharedInstance] uninstallApp:appId];
}
else
{
[[TSApplicationsManager sharedInstance] uninstallAppByPath:appPath];
}
} }
} }
- (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 @end

View File

@ -14,9 +14,10 @@
- (NSString*)displayNameForAppPath:(NSString*)appPath; - (NSString*)displayNameForAppPath:(NSString*)appPath;
- (NSError*)errorForCode:(int)code; - (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)installIpa:(NSString*)pathToIpa;
- (int)uninstallApp:(NSString*)appId; - (int)uninstallApp:(NSString*)appId;
- (int)uninstallAppByPath:(NSString*)path; - (int)uninstallAppByPath:(NSString*)path;
//- (int)detachFromApp:(NSString*)appId;
@end @end

View File

@ -24,7 +24,13 @@
- (NSDictionary*)infoDictionaryForAppPath:(NSString*)appPath - (NSDictionary*)infoDictionaryForAppPath:(NSString*)appPath
{ {
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"]; 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 - (NSString*)appIdForAppPath:(NSString*)appPath
@ -35,7 +41,6 @@
- (NSString*)displayNameForAppPath:(NSString*)appPath - (NSString*)displayNameForAppPath:(NSString*)appPath
{ {
NSDictionary* infoDict = [self infoDictionaryForAppPath:appPath]; NSDictionary* infoDict = [self infoDictionaryForAppPath:appPath];
NSString* displayName = infoDict[@"CFBundleDisplayName"]; NSString* displayName = infoDict[@"CFBundleDisplayName"];
if(![displayName isKindOfClass:[NSString class]]) displayName = nil; if(![displayName isKindOfClass:[NSString class]]) displayName = nil;
if(!displayName || [displayName isEqualToString:@""]) if(!displayName || [displayName isEqualToString:@""])
@ -57,12 +62,14 @@
NSString* errorDescription = @"Unknown Error"; NSString* errorDescription = @"Unknown Error";
switch(code) switch(code)
{ {
// IPA install errors
case 166: case 166:
errorDescription = @"The IPA file does not exist or is not accessible."; errorDescription = @"The IPA file does not exist or is not accessible.";
break; break;
case 167: case 167:
errorDescription = @"The IPA file does not appear to contain an app."; errorDescription = @"The IPA file does not appear to contain an app.";
break; break;
// App install errors
case 170: case 170:
errorDescription = @"Failed to create container for app bundle."; errorDescription = @"Failed to create container for app bundle.";
break; 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."; 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; break;
case 172: case 172:
errorDescription = @"The app does not seem to contain an Info.plist"; errorDescription = @"The app does not contain an Info.plist file.";
break; break;
case 173: 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; 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}]; NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
return error; return error;
} }
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force - (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut
{ {
int ret; int ret;
if(force) if(force)
{ {
ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"]); ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"], nil, logOut);
} }
else else
{ {
ret = spawnRoot(helperPath(), @[@"install", pathToIpa]); ret = spawnRoot(helperPath(), @[@"install", pathToIpa], nil, logOut);
} }
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret; return ret;
@ -98,13 +124,13 @@
- (int)installIpa:(NSString*)pathToIpa - (int)installIpa:(NSString*)pathToIpa
{ {
return [self installIpa:pathToIpa force:NO]; return [self installIpa:pathToIpa force:NO log:nil];
} }
- (int)uninstallApp:(NSString*)appId - (int)uninstallApp:(NSString*)appId
{ {
if(!appId) return -200; if(!appId) return -200;
int ret = spawnRoot(helperPath(), @[@"uninstall", appId]); int ret = spawnRoot(helperPath(), @[@"uninstall", appId], nil, nil);
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret; return ret;
} }
@ -112,9 +138,17 @@
- (int)uninstallAppByPath:(NSString*)path - (int)uninstallAppByPath:(NSString*)path
{ {
if(!path) return -200; 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]; [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret; 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 @end

View File

@ -7,163 +7,180 @@
- (void)doIPAInstall:(NSString*)ipaPath scene:(UIWindowScene*)scene force:(BOOL)force completion:(void (^)(void))completion - (void)doIPAInstall:(NSString*)ipaPath scene:(UIWindowScene*)scene force:(BOOL)force completion:(void (^)(void))completion
{ {
UIWindow* keyWindow = nil; UIWindow* keyWindow = nil;
for(UIWindow* window in scene.windows) for(UIWindow* window in scene.windows)
{ {
if(window.isKeyWindow) if(window.isKeyWindow)
{ {
keyWindow = window; keyWindow = window;
break; break;
} }
} }
UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)]; UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
activityIndicator.hidesWhenStopped = YES; activityIndicator.hidesWhenStopped = YES;
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium; activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
[activityIndicator startAnimating]; [activityIndicator startAnimating];
[infoAlert.view addSubview:activityIndicator]; [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), ^ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{ {
// Install IPA // Install IPA
int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force]; //NSString* log;
NSError* error = [[TSApplicationsManager sharedInstance] errorForCode:ret]; int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force log:nil];
NSLog(@"installed app! ret:%d, error: %@", ret, error); NSError* error;
dispatch_async(dispatch_get_main_queue(), ^ if(ret != 0)
{ {
[infoAlert dismissViewControllerAnimated:YES completion:^ error = [[TSApplicationsManager sharedInstance] errorForCode:ret];
{ }
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];
[keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil]; NSLog(@"installed app! ret:%d, error: %@", ret, error);
}
if(ret != 171) dispatch_async(dispatch_get_main_queue(), ^
{ {
completion(); [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<UIOpenURLContext *> *)URLContexts scene:(UIWindowScene*)scene - (void)handleURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts scene:(UIWindowScene*)scene
{ {
for(UIOpenURLContext* context in URLContexts) for(UIOpenURLContext* context in URLContexts)
{ {
NSLog(@"openURLContexts %@", context.URL); NSLog(@"openURLContexts %@", context.URL);
NSURL* url = context.URL; NSURL* url = context.URL;
if (url != nil && [url isFileURL]) { if (url != nil && [url isFileURL]) {
[url startAccessingSecurityScopedResource]; [url startAccessingSecurityScopedResource];
void (^doneBlock)(BOOL) = ^(BOOL shouldExit) void (^doneBlock)(BOOL) = ^(BOOL shouldExit)
{ {
[url stopAccessingSecurityScopedResource]; [url stopAccessingSecurityScopedResource];
[[NSFileManager defaultManager] removeItemAtURL:url error:nil]; [[NSFileManager defaultManager] removeItemAtURL:url error:nil];
if(shouldExit) if(shouldExit)
{ {
NSLog(@"Respring + Exit"); NSLog(@"Respring + Exit");
respring(); respring();
exit(0); exit(0);
} }
}; };
if ([url.pathExtension isEqualToString:@"ipa"]) if ([url.pathExtension isEqualToString:@"ipa"])
{ {
[self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{ [self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{
doneBlock(NO); doneBlock(NO);
}]; }];
} }
else if([url.pathExtension isEqualToString:@"tar"]) else if([url.pathExtension isEqualToString:@"tar"])
{ {
// Update TrollStore itself // Update TrollStore itself
NSLog(@"Updating TrollStore..."); NSLog(@"Updating TrollStore...");
int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path]); int ret = spawnRoot(helperPath(), @[@"install-trollstore", url.path], nil, nil);
doneBlock(ret == 0); doneBlock(ret == 0);
NSLog(@"Updated TrollStore!"); NSLog(@"Updated TrollStore!");
} }
} }
} }
} }
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions { - (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`. // 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. // 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). // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions); NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions);
UIWindowScene* windowScene = (UIWindowScene*)scene; UIWindowScene* windowScene = (UIWindowScene*)scene;
_window = [[UIWindow alloc] initWithWindowScene:windowScene]; _window = [[UIWindow alloc] initWithWindowScene:windowScene];
_rootViewController = [[TSRootViewController alloc] init]; _rootViewController = [[TSRootViewController alloc] init];
_window.rootViewController = _rootViewController; _window.rootViewController = _rootViewController;
[_window makeKeyAndVisible]; [_window makeKeyAndVisible];
if(connectionOptions.URLContexts.count) if(connectionOptions.URLContexts.count)
{ {
[self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene]; [self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene];
} }
} }
- (void)sceneDidDisconnect:(UIScene *)scene { - (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system. // 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. // 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. // 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). // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
} }
- (void)sceneDidBecomeActive:(UIScene *)scene { - (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state. // 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. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
} }
- (void)sceneWillResignActive:(UIScene *)scene { - (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state. // 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). // This may occur due to temporary interruptions (ex. an incoming phone call).
} }
- (void)sceneWillEnterForeground:(UIScene *)scene { - (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground. // Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background. // Use this method to undo the changes made on entering the background.
} }
- (void)sceneDidEnterBackground:(UIScene *)scene { - (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background. // 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 // 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. // to restore the scene back to its current state.
} }
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts - (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{ {
NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts); NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts);
[self handleURLContexts:URLContexts scene:(UIWindowScene*)scene]; [self handleURLContexts:URLContexts scene:(UIWindowScene*)scene];
} }
@end @end

View File

@ -225,7 +225,7 @@
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ 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(), ^ dispatch_async(dispatch_get_main_queue(), ^
{ {
@ -259,7 +259,7 @@
} }
else else
{ {
spawnRoot(helperPath(), @[@"install-ldid", location.path]); spawnRoot(helperPath(), @[@"install-ldid", location.path], nil, nil);
dispatch_async(dispatch_get_main_queue(), ^ dispatch_async(dispatch_get_main_queue(), ^
{ {
[self stopActivityWithCompletion:nil]; [self stopActivityWithCompletion:nil];
@ -294,7 +294,7 @@
{ {
UIAlertAction* installAction = [UIAlertAction actionWithTitle:[appProxy localizedName] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) 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]; [self reloadSpecifiers];
}]; }];
@ -314,7 +314,7 @@
- (void)uninstallPersistenceHelperPressed - (void)uninstallPersistenceHelperPressed
{ {
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"]); spawnRoot(helperPath(), @[@"uninstall-persistence-helper"], nil, nil);
[self reloadSpecifiers]; [self reloadSpecifiers];
} }
@ -327,7 +327,7 @@
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{ {
spawnRoot(helperPath(), @[@"uninstall-trollstore"]); spawnRoot(helperPath(), @[@"uninstall-trollstore"], nil, nil);
exit(0); exit(0);
}]; }];
[uninstallWarningAlert addAction:continueAction]; [uninstallWarningAlert addAction:continueAction];

View File

@ -1,6 +1,7 @@
@import Foundation; @import Foundation;
extern NSString* helperPath(void); 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 void respring(void);
extern NSString* getTrollStoreVersion(void); extern NSString* getTrollStoreVersion(void);

View File

@ -14,7 +14,29 @@ NSString* helperPath(void)
return [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"trollstorehelper"]; 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]; NSMutableArray* argsM = args.mutableCopy ?: [NSMutableArray new];
[argsM insertObject:path.lastPathComponent atIndex:0]; [argsM insertObject:path.lastPathComponent atIndex:0];
@ -28,18 +50,35 @@ int spawnRoot(NSString* path, NSArray* args)
} }
argsC[argCount] = NULL; argsC[argCount] = NULL;
int rv;
posix_spawnattr_t attr; posix_spawnattr_t attr;
rv = posix_spawnattr_init(&attr); posix_spawnattr_init(&attr);
if(rv != 0) return rv;
posix_spawnattr_set_persona_np(&attr, 99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE); posix_spawnattr_set_persona_np(&attr, 99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE);
posix_spawnattr_set_persona_uid_np(&attr, 0); posix_spawnattr_set_persona_uid_np(&attr, 0);
posix_spawnattr_set_persona_gid_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; pid_t task_pid;
int status = -200; 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); posix_spawnattr_destroy(&attr);
for (NSUInteger i = 0; i < argCount; i++) for (NSUInteger i = 0; i < argCount; i++)
{ {
@ -64,6 +103,20 @@ int spawnRoot(NSString* path, NSArray* args)
} }
} while (!WIFEXITED(status) && !WIFSIGNALED(status)); } 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); return WEXITSTATUS(status);
} }

View File

@ -1,6 +1,6 @@
Package: com.opa334.trollstore Package: com.opa334.trollstore
Name: TrollStore Name: TrollStore
Version: 1.0.7 Version: 1.0.8
Architecture: iphoneos-arm Architecture: iphoneos-arm
Description: An awesome application! Description: An awesome application!
Maintainer: opa334 Maintainer: opa334