This commit is contained in:
opa334 2023-01-21 13:52:39 +01:00
parent d244304313
commit 3aafa51503
15 changed files with 616 additions and 235 deletions

View File

@ -123,6 +123,33 @@ NSString* appPathForAppId(NSString* appId)
return nil; return nil;
} }
NSString* findAppNameInBundlePath(NSString* bundlePath)
{
NSArray* bundleItems = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bundlePath error:nil];
for(NSString* bundleItem in bundleItems)
{
if([bundleItem.pathExtension isEqualToString:@"app"])
{
return bundleItem;
}
}
return nil;
}
NSString* findAppPathInBundlePath(NSString* bundlePath)
{
NSString* appName = findAppNameInBundlePath(bundlePath);
if(!appName) return nil;
return [bundlePath stringByAppendingPathComponent:appName];
}
NSURL* findAppURLInBundleURL(NSURL* bundleURL)
{
NSString* appName = findAppNameInBundlePath(bundleURL.path);
if(!appName) return nil;
return [bundleURL URLByAppendingPathComponent:appName];
}
BOOL isMachoFile(NSString* filePath) BOOL isMachoFile(NSString* filePath)
{ {
FILE* file = fopen(filePath.fileSystemRepresentation, "r"); FILE* file = fopen(filePath.fileSystemRepresentation, "r");
@ -205,12 +232,13 @@ void setTSURLSchemeState(BOOL newState, NSString* customAppPath)
} }
} }
void installLdid(NSString* ldidToCopyPath, NSString* ldidVersion)
void installLdid(NSString* ldidToCopyPath)
{ {
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidToCopyPath]) return; if(![[NSFileManager defaultManager] fileExistsAtPath:ldidToCopyPath]) return;
NSString* ldidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"]; NSString* ldidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
NSString* ldidVersionPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid.version"];
if([[NSFileManager defaultManager] fileExistsAtPath:ldidPath]) if([[NSFileManager defaultManager] fileExistsAtPath:ldidPath])
{ {
[[NSFileManager defaultManager] removeItemAtPath:ldidPath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:ldidPath error:nil];
@ -218,8 +246,11 @@ void installLdid(NSString* ldidToCopyPath)
[[NSFileManager defaultManager] copyItemAtPath:ldidToCopyPath toPath:ldidPath error:nil]; [[NSFileManager defaultManager] copyItemAtPath:ldidToCopyPath toPath:ldidPath error:nil];
NSData* ldidVersionData = [ldidVersion dataUsingEncoding:NSUTF8StringEncoding];
[ldidVersionData writeToFile:ldidVersionPath atomically:YES];
chmod(ldidPath.fileSystemRepresentation, 0755); chmod(ldidPath.fileSystemRepresentation, 0755);
chown(ldidPath.fileSystemRepresentation, 0, 0); chmod(ldidVersionPath.fileSystemRepresentation, 0644);
} }
BOOL isLdidInstalled(void) BOOL isLdidInstalled(void)
@ -433,7 +464,6 @@ int signApp(NSString* appPath)
NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"]; NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"];
if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]]) if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]])
{ {
// if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now
NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned; NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned;
if([tsBundleIsPreSignedNum boolValue] == YES) if([tsBundleIsPreSignedNum boolValue] == YES)
@ -478,34 +508,8 @@ int signApp(NSString* appPath)
} }
else else
{ {
// Work around an ldid bug where it doesn't keep entitlements on stray binaries
NSMutableDictionary* storedEntitlements = [NSMutableDictionary new];
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil];
NSURL* fileURL;
while(fileURL = [enumerator nextObject])
{
NSString* filePath = fileURL.path;
if(isMachoFile(filePath))
{
storedEntitlements[filePath] = dumpEntitlementsFromBinaryAtPath(filePath);
}
}
// app has entitlements, keep them // app has entitlements, keep them
ldidRet = runLdid(@[@"-s", certArg, appPath], nil, &errorOutput); ldidRet = runLdid(@[@"-s", certArg, appPath], nil, &errorOutput);
[storedEntitlements enumerateKeysAndObjectsUsingBlock:^(NSString* binaryPath, NSDictionary* entitlements, BOOL* stop)
{
NSDictionary* newEntitlements = dumpEntitlementsFromBinaryAtPath(binaryPath);
if(!newEntitlements || ![newEntitlements isEqualToDictionary:entitlements])
{
NSString* tmpEntitlementPlistPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"ent.xml"];
[entitlements writeToURL:[NSURL fileURLWithPath:tmpEntitlementPlistPath] error:nil];
NSString* tmpEntitlementArg = [@"-S" stringByAppendingString:tmpEntitlementPlistPath];
runLdid(@[tmpEntitlementArg, certArg, binaryPath], nil, nil);
[[NSFileManager defaultManager] removeItemAtPath:tmpEntitlementPlistPath error:nil];
}
}];
} }
NSLog(@"ldid exited with status %d", ldidRet); NSLog(@"ldid exited with status %d", ldidRet);
@ -581,7 +585,7 @@ void applyPatchesToInfoDictionary(NSString* appPath)
// 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
// 174: // 174:
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate) int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod)
{ {
NSLog(@"[installApp force = %d]", force); NSLog(@"[installApp force = %d]", force);
@ -590,18 +594,18 @@ int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate)
NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appPayloadPath error:nil]; NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appPayloadPath error:nil];
if(!items) return 167; if(!items) return 167;
NSString* appBundlePath; NSString* appBundleToInstallPath;
for(NSString* item in items) for(NSString* item in items)
{ {
if([item.pathExtension isEqualToString:@"app"]) if([item.pathExtension isEqualToString:@"app"])
{ {
appBundlePath = [appPayloadPath stringByAppendingPathComponent:item]; appBundleToInstallPath = [appPayloadPath stringByAppendingPathComponent:item];
break; break;
} }
} }
if(!appBundlePath) return 167; if(!appBundleToInstallPath) return 167;
NSString* appId = appIdForAppPath(appBundlePath); NSString* appId = appIdForAppPath(appBundleToInstallPath);
if(!appId) return 176; if(!appId) return 176;
if(([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"] && !isTSUpdate) || [immutableAppBundleIdentifiers() containsObject:appId.lowercaseString]) if(([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"] && !isTSUpdate) || [immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
@ -609,115 +613,151 @@ int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate)
return 179; return 179;
} }
if(!infoDictionaryForAppPath(appBundlePath)) return 172; if(!infoDictionaryForAppPath(appBundleToInstallPath)) return 172;
if(!isTSUpdate) if(!isTSUpdate)
{ {
applyPatchesToInfoDictionary(appBundlePath); applyPatchesToInfoDictionary(appBundleToInstallPath);
} }
if(sign) if(sign)
{ {
int signRet = signApp(appBundlePath); int signRet = signApp(appBundleToInstallPath);
if(signRet != 0) return signRet; if(signRet != 0) return signRet;
} }
loadMCMFramework(); MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
if(appContainer)
{
// App update
// Replace existing bundle with new version
BOOL existed; // Check if the existing app bundle is empty
NSError* mcmError; NSURL* bundleContainerURL = appContainer.url;
MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError]; NSURL* appBundleURL = findAppURLInBundleURL(bundleContainerURL);
if(!appContainer || mcmError)
{
NSLog(@"[installApp] failed to create app container for %@: %@", appId, mcmError);
return 170;
}
if(existed) // Make sure the installed app is a TrollStore app or the container is empty (or the force flag is set)
{ NSURL* trollStoreMarkURL = [bundleContainerURL URLByAppendingPathComponent:@"_TrollStore"];
NSLog(@"[installApp] got existing app container: %@", appContainer); if(!appBundleURL && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force)
}
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:nil];
for(NSString* bundleItem in bundleItems)
{
if([bundleItem.pathExtension isEqualToString:@"app"])
{ {
isEmpty = NO; NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
break; return 171;
} }
}
NSLog(@"[installApp] container is empty? %d", isEmpty); // Terminate app if it's still running
if(!isTSUpdate)
// 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)
{
NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
return 171;
}
// Mark app as TrollStore app
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;
}
fixPermissionsOfAppBundle(appBundlePath);
// Wipe old version if needed
if(existed)
{
if(![appId isEqualToString:@"com.opa334.TrollStore"])
{ {
BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated"); BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated");
} }
NSLog(@"[installApp] found existing TrollStore app, cleaning directory"); NSLog(@"[installApp] replacing existing app with new version");
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
NSURL* fileURL; // Delete existing .app directory if it exists
while(fileURL = [enumerator nextObject]) if(appBundleURL)
{ {
// do not under any circumstance delete this file as it makes iOS loose the app registration [[NSFileManager defaultManager] removeItemAtURL:appBundleURL error:nil];
if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] || [fileURL.lastPathComponent isEqualToString:@"_TrollStore"])
{
NSLog(@"[installApp] skipping removal of %@", fileURL);
continue;
}
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil];
} }
}
// Install app NSString* newAppBundlePath = [bundleContainerURL.path stringByAppendingPathComponent:appBundleToInstallPath.lastPathComponent];
NSString* newAppBundlePath = [appContainer.url.path stringByAppendingPathComponent:appBundlePath.lastPathComponent]; NSLog(@"[installApp] new app path: %@", newAppBundlePath);
NSLog(@"[installApp] new app path: %@", newAppBundlePath);
NSError* copyError; // Install new version into existing app bundle
BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appBundlePath toPath:newAppBundlePath error:&copyError]; NSError* copyError;
if(suc) BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appBundleToInstallPath toPath:newAppBundlePath error:&copyError];
{ if(!suc)
NSLog(@"[installApp] App %@ installed, adding to icon cache now...", appId); {
registerPath(newAppBundlePath, NO, YES); NSLog(@"[installApp] Error copying new version during update: %@", copyError);
return 0; return 178;
}
} }
else else
{ {
NSLog(@"[installApp] Failed to copy app bundle for app %@, error: %@", appId, copyError); // Initial app install
return 178; BOOL systemMethodSuccessful = NO;
if(useInstalldMethod)
{
// System method
// Do initial placeholder installation using LSApplicationWorkspace
NSLog(@"[installApp] doing placeholder installation using LSApplicationWorkspace");
NSError* installError;
@try
{
systemMethodSuccessful = [[LSApplicationWorkspace defaultWorkspace] installApplication:[NSURL fileURLWithPath:appPackagePath] withOptions:@{
LSInstallTypeKey : @1,
@"PackageType" : @"Placeholder"
} error:&installError];
}
@catch(NSException* e)
{
NSLog(@"[installApp] encountered expection %@ while trying to do placeholder install", e);
systemMethodSuccessful = NO;
}
if(!systemMethodSuccessful)
{
NSLog(@"[installApp] encountered error %@ while trying to do placeholder install", installError);
}
}
if(!systemMethodSuccessful)
{
// Custom method
// Manually create app bundle via MCM apis and move app there
NSLog(@"[installApp] doing custom installation using MCMAppContainer");
NSError* mcmError;
appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:nil error:&mcmError];
if(!appContainer || mcmError)
{
NSLog(@"[installApp] failed to create app container for %@: %@", appId, mcmError);
return 170;
}
else
{
NSLog(@"[installApp] created app container: %@", appContainer);
}
NSString* newAppBundlePath = [appContainer.url.path stringByAppendingPathComponent:appBundleToInstallPath.lastPathComponent];
NSLog(@"[installApp] new app path: %@", newAppBundlePath);
NSError* copyError;
BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appBundleToInstallPath toPath:newAppBundlePath error:&copyError];
if(!suc)
{
NSLog(@"[installApp] Failed to copy app bundle for app %@, error: %@", appId, copyError);
return 178;
}
}
} }
appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
// Mark app as TrollStore app
NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"];
if(![[NSFileManager defaultManager] fileExistsAtPath:trollStoreMarkURL.path])
{
NSError* creationError;
NSData* emptyData = [NSData data];
BOOL marked = [emptyData writeToURL:trollStoreMarkURL options:0 error:&creationError];
if(!marked)
{
NSLog(@"[installApp] failed to mark %@ as TrollStore app by creating %@, error: %@", appId, trollStoreMarkURL.path, creationError);
return 177;
}
}
// At this point the (new version of the) app is installed but still needs to be registered
// Also permissions need to be fixed
NSURL* updatedAppURL = findAppURLInBundleURL(appContainer.url);
fixPermissionsOfAppBundle(updatedAppURL.path);
registerPath(updatedAppURL.path, 0, YES);
return 0;
} }
int uninstallApp(NSString* appPath, NSString* appId) int uninstallApp(NSString* appPath, NSString* appId, BOOL useCustomMethod)
{ {
BOOL deleteSuc = NO; BOOL deleteSuc = NO;
if(!appId && appPath) if(!appId && appPath)
@ -760,7 +800,21 @@ int uninstallApp(NSString* appPath, NSString* appId)
} }
} }
deleteSuc = [[LSApplicationWorkspace defaultWorkspace] uninstallApplication:appId withOptions:nil]; BOOL systemMethodSuccessful = NO;
if(!useCustomMethod)
{
systemMethodSuccessful = [[LSApplicationWorkspace defaultWorkspace] uninstallApplication:appId withOptions:nil];
}
if(!systemMethodSuccessful)
{
deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:nil];
registerPath(appPath, YES, YES);
}
else
{
deleteSuc = systemMethodSuccessful;
}
} }
if(deleteSuc) if(deleteSuc)
@ -774,7 +828,7 @@ int uninstallApp(NSString* appPath, NSString* appId)
} }
} }
int uninstallAppByPath(NSString* appPath) int uninstallAppByPath(NSString* appPath, BOOL useCustomMethod)
{ {
if(!appPath) return 1; if(!appPath) return 1;
@ -786,21 +840,20 @@ int uninstallAppByPath(NSString* appPath)
} }
NSString* appId = appIdForAppPath(standardizedAppPath); NSString* appId = appIdForAppPath(standardizedAppPath);
return uninstallApp(appPath, appId); return uninstallApp(appPath, appId, useCustomMethod);
} }
int uninstallAppById(NSString* appId) int uninstallAppById(NSString* appId, BOOL useCustomMethod)
{ {
if(!appId) return 1; if(!appId) return 1;
NSString* appPath = appPathForAppId(appId); NSString* appPath = appPathForAppId(appId);
if(!appPath) return 1; if(!appPath) return 1;
return uninstallApp(appPath, appId); return uninstallApp(appPath, appId, useCustomMethod);
} }
// 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, BOOL useInstalldMethod)
int installIpa(NSString* ipaPath, BOOL force)
{ {
cleanRestrictions(); cleanRestrictions();
@ -819,18 +872,18 @@ int installIpa(NSString* ipaPath, BOOL force)
return 168; return 168;
} }
int ret = installApp(tmpPackagePath, YES, force, NO); int ret = installApp(tmpPackagePath, YES, force, NO, useInstalldMethod);
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
return ret; return ret;
} }
void uninstallAllApps(void) void uninstallAllApps(BOOL useCustomMethod)
{ {
for(NSString* appPath in trollStoreInstalledAppBundlePaths()) for(NSString* appPath in trollStoreInstalledAppBundlePaths())
{ {
uninstallAppById(appIdForAppPath(appPath)); uninstallAppById(appIdForAppPath(appPath), useCustomMethod);
} }
} }
@ -872,14 +925,36 @@ int installTrollStore(NSString* pathToTar)
NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"]; NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1; if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;
// Save existing ldid installation if it exists // Transfer existing ldid installation if it exists
NSString* existingLdidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"]; // But only if the to-be-installed version of TrollStore is 1.5.0 or above
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidPath]) // This is to make it possible to downgrade to older versions still
NSString* toInstallInfoPlistPath = [tmpTrollStorePath stringByAppendingPathComponent:@"Info.plist"];
if(![[NSFileManager defaultManager] fileExistsAtPath:toInstallInfoPlistPath]) return 1;
NSDictionary* toInstallInfoDict = [NSDictionary dictionaryWithContentsOfFile:toInstallInfoPlistPath];
NSString* toInstallVersion = toInstallInfoDict[@"CFBundleVersion"];
NSComparisonResult result = [@"1.5.0" compare:toInstallVersion options:NSNumericSearch];
if(result != NSOrderedDescending)
{ {
NSString* tmpLdidPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid"]; NSString* existingLdidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidPath]) NSString* existingLdidVersionPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid.version"];
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidPath])
{ {
[[NSFileManager defaultManager] copyItemAtPath:existingLdidPath toPath:tmpLdidPath error:nil]; NSString* tmpLdidPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidPath])
{
[[NSFileManager defaultManager] copyItemAtPath:existingLdidPath toPath:tmpLdidPath error:nil];
}
}
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidVersionPath])
{
NSString* tmpLdidVersionPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid.version"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidVersionPath])
{
[[NSFileManager defaultManager] copyItemAtPath:existingLdidVersionPath toPath:tmpLdidVersionPath error:nil];
}
} }
} }
@ -898,7 +973,7 @@ int installTrollStore(NSString* pathToTar)
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper); _installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
} }
int ret = installApp(tmpPackagePath, NO, YES, YES); int ret = installApp(tmpPackagePath, NO, YES, YES, YES);
NSLog(@"[installTrollStore] installApp => %d", ret); NSLog(@"[installTrollStore] installApp => %d", ret);
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil]; [[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
return ret; return ret;
@ -1106,90 +1181,114 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
@autoreleasepool { @autoreleasepool {
if(argc <= 1) return -1; if(argc <= 1) return -1;
NSLog(@"trollstore helper go, uid: %d, gid: %d", getuid(), getgid()); if(getuid() != 0)
{
NSLog(@"ERROR: trollstorehelper has to be run as root.");
return -1;
}
NSMutableArray* args = [NSMutableArray new];
for (int i = 1; i < argc; i++)
{
[args addObject:[NSString stringWithUTF8String:argv[i]]];
}
NSLog(@"trollstorehelper invoked with arguments: %@", args);
int ret = 0; int ret = 0;
NSString* cmd = args.firstObject;
NSString* cmd = [NSString stringWithUTF8String:argv[1]];
if([cmd isEqualToString:@"install"]) if([cmd isEqualToString:@"install"])
{ {
BOOL force = NO; if(args.count < 2) return -3;
if(argc <= 2) return -3; // use system method when specified, otherwise use custom method
if(argc > 3) BOOL useInstalldMethod = [args containsObject:@"installd"];
{ BOOL force = [args containsObject:@"force"];
if(!strcmp(argv[3], "force")) NSString* ipaPath = args.lastObject;
{ ret = installIpa(ipaPath, force, useInstalldMethod);
force = YES; }
} else if([cmd isEqualToString:@"uninstall"])
}
NSString* ipaPath = [NSString stringWithUTF8String:argv[2]];
ret = installIpa(ipaPath, force);
} else if([cmd isEqualToString:@"uninstall"])
{ {
if(argc <= 2) return -3; if(args.count < 2) return -3;
NSString* appId = [NSString stringWithUTF8String:argv[2]]; // use custom method when specified, otherwise use system method
ret = uninstallAppById(appId); BOOL useCustomMethod = [args containsObject:@"custom"];
} else if([cmd isEqualToString:@"uninstall-path"]) NSString* appId = args.lastObject;
ret = uninstallAppById(appId, useCustomMethod);
}
else if([cmd isEqualToString:@"uninstall-path"])
{ {
if(argc <= 2) return -3; if(args.count < 2) return -3;
NSString* appPath = [NSString stringWithUTF8String:argv[2]]; // use custom method when specified, otherwise use system method
ret = uninstallAppByPath(appPath); BOOL useCustomMethod = [args containsObject:@"custom"];
}else if([cmd isEqualToString:@"install-trollstore"]) NSString* appPath = args.lastObject;
ret = uninstallAppByPath(appPath, useCustomMethod);
}
else if([cmd isEqualToString:@"install-trollstore"])
{ {
if(argc <= 2) return -3; if(args.count < 2) return -3;
NSString* tsTar = [NSString stringWithUTF8String:argv[2]]; NSString* tsTar = args.lastObject;
ret = installTrollStore(tsTar); ret = installTrollStore(tsTar);
NSLog(@"installed troll store? %d", ret==0); NSLog(@"installed troll store? %d", ret==0);
} else if([cmd isEqualToString:@"uninstall-trollstore"]) }
else if([cmd isEqualToString:@"uninstall-trollstore"])
{ {
uninstallAllApps(); if(![args containsObject:@"preserve-apps"])
{
uninstallAllApps([args containsObject:@"custom"]);
}
uninstallTrollStore(YES); uninstallTrollStore(YES);
} else if([cmd isEqualToString:@"uninstall-trollstore-preserve-apps"]) }
else if([cmd isEqualToString:@"install-ldid"])
{ {
uninstallTrollStore(YES); if(args.count < 3) return -3;
}else if([cmd isEqualToString:@"install-ldid"]) NSString* ldidPath = args[1];
{ NSString* ldidVersion = args[2];
if(argc <= 2) return -3; installLdid(ldidPath, ldidVersion);
NSString* ldidPath = [NSString stringWithUTF8String:argv[2]]; }
installLdid(ldidPath); else if([cmd isEqualToString:@"refresh"])
} else if([cmd isEqualToString:@"refresh"])
{ {
refreshAppRegistrations(YES); refreshAppRegistrations(YES);
} else if([cmd isEqualToString:@"refresh-all"]) }
else if([cmd isEqualToString:@"refresh-all"])
{ {
cleanRestrictions(); cleanRestrictions();
//refreshAppRegistrations(NO); // <- fixes app permissions resetting, causes apps to move around on home screen, so I had to disable it //refreshAppRegistrations(NO); // <- fixes app permissions resetting, causes apps to move around on home screen, so I had to disable it
[[NSFileManager defaultManager] removeItemAtPath:@"/var/containers/Shared/SystemGroup/systemgroup.com.apple.lsd.iconscache/Library/Caches/com.apple.IconsCache" error:nil];
[[LSApplicationWorkspace defaultWorkspace] _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:YES]; [[LSApplicationWorkspace defaultWorkspace] _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:YES];
refreshAppRegistrations(YES); refreshAppRegistrations(YES);
killall(@"backboardd", YES); killall(@"backboardd", YES);
} else if([cmd isEqualToString:@"install-persistence-helper"]) }
else if([cmd isEqualToString:@"install-persistence-helper"])
{ {
if(argc <= 2) return -3; if(args.count < 2) return -3;
NSString* systemAppId = [NSString stringWithUTF8String:argv[2]]; NSString* systemAppId = args.lastObject;
installPersistenceHelper(systemAppId); installPersistenceHelper(systemAppId);
} else if([cmd isEqualToString:@"uninstall-persistence-helper"]) }
else if([cmd isEqualToString:@"uninstall-persistence-helper"])
{ {
uninstallPersistenceHelper(); uninstallPersistenceHelper();
} else if([cmd isEqualToString:@"register-user-persistence-helper"]) }
else if([cmd isEqualToString:@"register-user-persistence-helper"])
{ {
if(argc <= 2) return -3; if(args.count < 2) return -3;
NSString* userAppId = [NSString stringWithUTF8String:argv[2]]; NSString* userAppId = args.lastObject;
registerUserPersistenceHelper(userAppId); registerUserPersistenceHelper(userAppId);
} else if([cmd isEqualToString:@"modify-registration"]) }
else if([cmd isEqualToString:@"modify-registration"])
{ {
if(argc <= 3) return -3; if(args.count < 3) return -3;
NSString* appPath = [NSString stringWithUTF8String:argv[2]]; NSString* appPath = args[1];
NSString* newRegistration = [NSString stringWithUTF8String:argv[3]]; NSString* newRegistration = args[2];
NSString* trollStoreMark = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"]; NSString* trollStoreMark = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"];
if([[NSFileManager defaultManager] fileExistsAtPath:trollStoreMark]) if([[NSFileManager defaultManager] fileExistsAtPath:trollStoreMark])
{ {
registerPath(appPath, NO, [newRegistration isEqualToString:@"System"]); registerPath(appPath, NO, [newRegistration isEqualToString:@"System"]);
} }
} else if([cmd isEqualToString:@"url-scheme"]) }
else if([cmd isEqualToString:@"url-scheme"])
{ {
if(argc <= 2) return -3; if(args.count < 2) return -3;
NSString* modifyArg = [NSString stringWithUTF8String:argv[2]]; NSString* modifyArg = args.lastObject;
BOOL newState = [modifyArg isEqualToString:@"enable"]; BOOL newState = [modifyArg isEqualToString:@"enable"];
if(newState == YES || [modifyArg isEqualToString:@"disable"]) if(newState == YES || [modifyArg isEqualToString:@"disable"])
{ {
@ -1197,8 +1296,7 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
} }
} }
NSLog(@"returning %d", ret); NSLog(@"trollstorehelper returning %d", ret);
return ret; return ret;
} }
} }

View File

@ -12,5 +12,6 @@
- (void)refreshAppRegistrationsPressed; - (void)refreshAppRegistrationsPressed;
- (void)uninstallPersistenceHelperPressed; - (void)uninstallPersistenceHelperPressed;
- (void)handleUninstallation; - (void)handleUninstallation;
- (NSMutableArray*)argsForUninstallingTrollStore;
- (void)uninstallTrollStorePressed; - (void)uninstallTrollStorePressed;
@end @end

View File

@ -188,20 +188,28 @@
} }
} }
- (NSMutableArray*)argsForUninstallingTrollStore
{
return @[@"uninstall-trollstore"].mutableCopy;
}
- (void)uninstallTrollStorePressed - (void)uninstallTrollStorePressed
{ {
UIAlertController* uninstallAlert = [UIAlertController alertControllerWithTitle:@"Uninstall" message:@"You are about to uninstall TrollStore, do you want to preserve the apps installed by it?" preferredStyle:UIAlertControllerStyleAlert]; UIAlertController* uninstallAlert = [UIAlertController alertControllerWithTitle:@"Uninstall" message:@"You are about to uninstall TrollStore, do you want to preserve the apps installed by it?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* uninstallAllAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Uninstall Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) UIAlertAction* uninstallAllAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Uninstall Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{ {
spawnRoot(rootHelperPath(), @[@"uninstall-trollstore"], nil, nil); NSMutableArray* args = [self argsForUninstallingTrollStore];
spawnRoot(rootHelperPath(), @[args], nil, nil);
[self handleUninstallation]; [self handleUninstallation];
}]; }];
[uninstallAlert addAction:uninstallAllAction]; [uninstallAlert addAction:uninstallAllAction];
UIAlertAction* preserveAppsAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Preserve Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) UIAlertAction* preserveAppsAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Preserve Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{ {
spawnRoot(rootHelperPath(), @[@"uninstall-trollstore-preserve-apps"], nil, nil); NSMutableArray* args = [self argsForUninstallingTrollStore];
[args addObject:@"preserve-apps"];
spawnRoot(rootHelperPath(), args, nil, nil);
[self handleUninstallation]; [self handleUninstallation];
}]; }];
[uninstallAlert addAction:preserveAppsAction]; [uninstallAlert addAction:preserveAppsAction];

View File

@ -13,6 +13,7 @@ extern int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString*
extern void killall(NSString* processName, BOOL softly); extern void killall(NSString* processName, BOOL softly);
extern void respring(void); extern void respring(void);
extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion)); extern void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion));
extern void fetchLatestLdidVersion(void (^completionHandler)(NSString* latestVersion));
extern NSArray* trollStoreInstalledAppBundlePaths(); extern NSArray* trollStoreInstalledAppBundlePaths();
extern NSArray* trollStoreInstalledAppContainerPaths(); extern NSArray* trollStoreInstalledAppContainerPaths();

View File

@ -287,9 +287,10 @@ void respring(void)
exit(0); exit(0);
} }
void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion)) void github_fetchLatestVersion(NSString* repo, void (^completionHandler)(NSString* latestVersion))
{ {
NSURL* githubLatestAPIURL = [NSURL URLWithString:@"https://api.github.com/repos/opa334/TrollStore/releases/latest"]; NSString* urlString = [NSString stringWithFormat:@"https://api.github.com/repos/%@/releases/latest", repo];
NSURL* githubLatestAPIURL = [NSURL URLWithString:urlString];
NSURLSessionDataTask* task = [NSURLSession.sharedSession dataTaskWithURL:githubLatestAPIURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) NSURLSessionDataTask* task = [NSURLSession.sharedSession dataTaskWithURL:githubLatestAPIURL completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)
{ {
@ -311,6 +312,16 @@ void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVers
[task resume]; [task resume];
} }
void fetchLatestTrollStoreVersion(void (^completionHandler)(NSString* latestVersion))
{
github_fetchLatestVersion(@"opa334/TrollStore", completionHandler);
}
void fetchLatestLdidVersion(void (^completionHandler)(NSString* latestVersion))
{
github_fetchLatestVersion(@"opa334/ldid", completionHandler);
}
NSArray* trollStoreInstalledAppContainerPaths() NSArray* trollStoreInstalledAppContainerPaths()
{ {
NSMutableArray* appContainerPaths = [NSMutableArray new]; NSMutableArray* appContainerPaths = [NSMutableArray new];

View File

@ -1,5 +1,6 @@
#import "TSApplicationsManager.h" #import "TSApplicationsManager.h"
#import <TSUtil.h> #import <TSUtil.h>
extern NSUserDefaults* trollStoreUserDefaults();
@implementation TSApplicationsManager @implementation TSApplicationsManager
@ -75,15 +76,25 @@
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut - (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut
{ {
int ret; NSMutableArray* args = [NSMutableArray new];
[args addObject:@"install"];
if(force) if(force)
{ {
ret = spawnRoot(rootHelperPath(), @[@"install", pathToIpa, @"force"], nil, logOut); [args addObject:@"force"];
}
NSNumber* installationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"installationMethod"];
int installationMethodToUse = installationMethodToUseNum ? installationMethodToUseNum.intValue : 1;
if(installationMethodToUse == 1)
{
[args addObject:@"custom"];
} }
else else
{ {
ret = spawnRoot(rootHelperPath(), @[@"install", pathToIpa], nil, logOut); [args addObject:@"installd"];
} }
[args addObject:pathToIpa];
int ret = spawnRoot(rootHelperPath(), args, nil, logOut);
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret; return ret;
} }
@ -96,7 +107,24 @@
- (int)uninstallApp:(NSString*)appId - (int)uninstallApp:(NSString*)appId
{ {
if(!appId) return -200; if(!appId) return -200;
int ret = spawnRoot(rootHelperPath(), @[@"uninstall", appId], nil, nil);
NSMutableArray* args = [NSMutableArray new];
[args addObject:@"uninstall"];
NSNumber* uninstallationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"uninstallationMethod"];
int uninstallationMethodToUse = uninstallationMethodToUseNum ? uninstallationMethodToUseNum.intValue : 0;
if(uninstallationMethodToUse == 1)
{
[args addObject:@"custom"];
}
else
{
[args addObject:@"installd"];
}
[args addObject:appId];
int ret = spawnRoot(rootHelperPath(), args, nil, nil);
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret; return ret;
} }
@ -104,7 +132,24 @@
- (int)uninstallAppByPath:(NSString*)path - (int)uninstallAppByPath:(NSString*)path
{ {
if(!path) return -200; if(!path) return -200;
int ret = spawnRoot(rootHelperPath(), @[@"uninstall-path", path], nil, nil);
NSMutableArray* args = [NSMutableArray new];
[args addObject:@"uninstall-path"];
NSNumber* uninstallationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"uninstallationMethod"];
int uninstallationMethodToUse = uninstallationMethodToUseNum ? uninstallationMethodToUseNum.intValue : 0;
if(uninstallationMethodToUse == 1)
{
[args addObject:@"custom"];
}
else
{
[args addObject:@"installd"];
}
[args addObject:path];
int ret = spawnRoot(rootHelperPath(), args, nil, nil);
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil]; [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret; return ret;
} }

View File

@ -9,4 +9,6 @@
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion; + (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion;
+ (void)installLdid;
@end @end

View File

@ -187,4 +187,47 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
}); });
} }
+ (void)installLdid
{
fetchLatestLdidVersion(^(NSString* latestVersion)
{
dispatch_async(dispatch_get_main_queue(), ^
{
NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/latest/download/ldid"];
NSURLRequest* ldidRequest = [NSURLRequest requestWithURL:ldidURL];
[TSPresentationDelegate startActivity:@"Installing ldid"];
NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:ldidRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
{
if(error)
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading ldid: %@", error] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
dispatch_async(dispatch_get_main_queue(), ^
{
[TSPresentationDelegate stopActivityWithCompletion:^
{
[TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil];
}];
});
}
else
{
spawnRoot(rootHelperPath(), @[@"install-ldid", location.path, latestVersion], nil, nil);
dispatch_async(dispatch_get_main_queue(), ^
{
[TSPresentationDelegate stopActivityWithCompletion:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TrollStoreReloadSettingsNotification" object:nil userInfo:nil];
});
}
}];
[downloadTask resume];
});
});
}
@end @end

View File

@ -72,6 +72,20 @@
} }
} }
// We want to auto install ldid if either it doesn't exist
// or if it's the one from an old TrollStore version that's no longer supported
- (void)handleLdidCheck
{
NSString* tsAppPath = [NSBundle mainBundle].bundlePath;
NSString* ldidPath = [tsAppPath stringByAppendingPathComponent:@"ldid"];
NSString* ldidVersionPath = [tsAppPath stringByAppendingPathComponent:@"ldid.version"];
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidPath] || ![[NSFileManager defaultManager] fileExistsAtPath:ldidVersionPath])
{
[TSInstallationController installLdid];
}
}
- (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`.
@ -88,6 +102,10 @@
{ {
[self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene]; [self handleURLContexts:connectionOptions.URLContexts scene:(UIWindowScene*)scene];
} }
else
{
[self handleLdidCheck];
}
} }

View File

@ -0,0 +1,5 @@
#import <Preferences/PSListController.h>
@interface TSSettingsAdvancedListController : PSListController
@end

View File

@ -0,0 +1,103 @@
#import "TSSettingsAdvancedListController.h"
#import <Preferences/PSSpecifier.h>
extern NSUserDefaults* trollStoreUserDefaults();
@interface PSSpecifier ()
@property (nonatomic,retain) NSArray* values;
@end
@implementation TSSettingsAdvancedListController
- (NSMutableArray*)specifiers
{
if(!_specifiers)
{
_specifiers = [NSMutableArray new];
PSSpecifier* installationMethodGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
//installationMethodGroupSpecifier.name = @"Installation";
[installationMethodGroupSpecifier setProperty:@"installd:\nInstalls applications by doing a placeholder installation through installd, fixing the permissions and then adding it to icon cache.\nAdvantage: Might be slightly more persistent then the custom method in terms of icon cache reloads.\nDisadvantage: Causes some small issues with certain applications for seemingly no reason (E.g. Watusi cannot save preferences when being installed using this method).\n\nCustom (Recommended):\nInstalls applications by manually creating a bundle using MobileContainerManager, copying the app into it and adding it to icon cache.\nAdvantage: No known issues (As opposed to the Watusi issue outlined in the installd method).\nDisadvantage: Might be slightly less persistent then the installd method in terms of icon cache reloads.\n\nNOTE: In cases where installd is selected but the placeholder installation fails, TrollStore automatically falls back to using the Custom method." forKey:@"footerText"];
[_specifiers addObject:installationMethodGroupSpecifier];
PSSpecifier* installationMethodSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Installation Method"
target:self
set:nil
get:nil
detail:nil
cell:PSStaticTextCell
edit:nil];
[installationMethodSpecifier setProperty:@YES forKey:@"enabled"];
installationMethodSpecifier.identifier = @"installationMethodLabel";
[_specifiers addObject:installationMethodSpecifier];
PSSpecifier* installationMethodSegmentSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Installation Method Segment"
target:self
set:@selector(setPreferenceValue:specifier:)
get:@selector(readPreferenceValue:)
detail:nil
cell:PSSegmentCell
edit:nil];
[installationMethodSegmentSpecifier setProperty:@YES forKey:@"enabled"];
installationMethodSegmentSpecifier.identifier = @"installationMethodSegment";
[installationMethodSegmentSpecifier setProperty:@"com.opa334.TrollStore" forKey:@"defaults"];
[installationMethodSegmentSpecifier setProperty:@"installationMethod" forKey:@"key"];
installationMethodSegmentSpecifier.values = @[@0, @1];
installationMethodSegmentSpecifier.titleDictionary = @{@0 : @"installd", @1 : @"Custom"};
[installationMethodSegmentSpecifier setProperty:@1 forKey:@"default"];
[_specifiers addObject:installationMethodSegmentSpecifier];
PSSpecifier* uninstallationMethodGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
//uninstallationMethodGroupSpecifier.name = @"Uninstallation";
[uninstallationMethodGroupSpecifier setProperty:@"installd (Recommended):\nUninstalls applications using the same API that SpringBoard uses when uninstalling them from the home screen.\n\nCustom:\nUninstalls applications by removing them from icon cache and then deleting their application and data bundles directly.\n\nNOTE: In cases where installd is selected but the stock uninstallation fails, TrollStore automatically falls back to using the Custom method." forKey:@"footerText"];
[_specifiers addObject:uninstallationMethodGroupSpecifier];
PSSpecifier* uninstallationMethodSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstallation Method"
target:self
set:nil
get:nil
detail:nil
cell:PSStaticTextCell
edit:nil];
[uninstallationMethodSpecifier setProperty:@YES forKey:@"enabled"];
uninstallationMethodSpecifier.identifier = @"uninstallationMethodLabel";
[_specifiers addObject:uninstallationMethodSpecifier];
PSSpecifier* uninstallationMethodSegmentSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Installation Method Segment"
target:self
set:@selector(setPreferenceValue:specifier:)
get:@selector(readPreferenceValue:)
detail:nil
cell:PSSegmentCell
edit:nil];
[uninstallationMethodSegmentSpecifier setProperty:@YES forKey:@"enabled"];
uninstallationMethodSegmentSpecifier.identifier = @"uninstallationMethodSegment";
[uninstallationMethodSegmentSpecifier setProperty:@"com.opa334.TrollStore" forKey:@"defaults"];
[uninstallationMethodSegmentSpecifier setProperty:@"uninstallationMethod" forKey:@"key"];
uninstallationMethodSegmentSpecifier.values = @[@0, @1];
uninstallationMethodSegmentSpecifier.titleDictionary = @{@0 : @"installd", @1 : @"Custom"};
[uninstallationMethodSegmentSpecifier setProperty:@0 forKey:@"default"];
[_specifiers addObject:uninstallationMethodSegmentSpecifier];
}
[(UINavigationItem *)self.navigationItem setTitle:@"Advanced"];
return _specifiers;
}
- (void)setPreferenceValue:(NSObject*)value specifier:(PSSpecifier*)specifier
{
NSUserDefaults* tsDefaults = trollStoreUserDefaults();
[tsDefaults setObject:value forKey:[specifier propertyForKey:@"key"]];
}
- (NSObject*)readPreferenceValue:(PSSpecifier*)specifier
{
NSUserDefaults* tsDefaults = trollStoreUserDefaults();
NSObject* toReturn = [tsDefaults objectForKey:[specifier propertyForKey:@"key"]];
if(!toReturn)
{
toReturn = [specifier propertyForKey:@"default"];
}
return toReturn;
}
@end

View File

@ -4,5 +4,6 @@
{ {
PSSpecifier* _installPersistenceHelperSpecifier; PSSpecifier* _installPersistenceHelperSpecifier;
NSString* _newerVersion; NSString* _newerVersion;
NSString* _newerLdidVersion;
} }
@end @end

View File

@ -3,6 +3,8 @@
#import <Preferences/PSSpecifier.h> #import <Preferences/PSSpecifier.h>
#import <Preferences/PSListItemsController.h> #import <Preferences/PSListItemsController.h>
#import <TSPresentationDelegate.h> #import <TSPresentationDelegate.h>
#import "TSInstallationController.h"
#import "TSSettingsAdvancedListController.h"
@interface NSUserDefaults (Private) @interface NSUserDefaults (Private)
- (instancetype)_initWithSuiteName:(NSString *)suiteName container:(NSURL *)container; - (instancetype)_initWithSuiteName:(NSString *)suiteName container:(NSURL *)container;
@ -15,6 +17,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
{ {
[super viewDidLoad]; [super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:@"TrollStoreReloadSettingsNotification" object:nil];
fetchLatestTrollStoreVersion(^(NSString* latestVersion) fetchLatestTrollStoreVersion(^(NSString* latestVersion)
{ {
@ -29,6 +32,26 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
}); });
} }
}); });
fetchLatestLdidVersion(^(NSString* latestVersion)
{
NSString* ldidVersionPath = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"ldid.version"];
NSString* ldidVersion = nil;
NSData* ldidVersionData = [NSData dataWithContentsOfFile:ldidVersionPath];
if(ldidVersionData)
{
ldidVersion = [[NSString alloc] initWithData:ldidVersionData encoding:NSUTF8StringEncoding];
}
if(![latestVersion isEqualToString:ldidVersion])
{
_newerLdidVersion = latestVersion;
dispatch_async(dispatch_get_main_queue(), ^
{
[self reloadSpecifiers];
});
}
});
} }
- (NSMutableArray*)specifiers - (NSMutableArray*)specifiers
@ -88,8 +111,16 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
[_specifiers addObject:rebuildIconCacheSpecifier]; [_specifiers addObject:rebuildIconCacheSpecifier];
NSString* ldidPath = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"ldid"]; NSString* ldidPath = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"ldid"];
NSString* ldidVersionPath = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"ldid.version"];
BOOL ldidInstalled = [[NSFileManager defaultManager] fileExistsAtPath:ldidPath]; BOOL ldidInstalled = [[NSFileManager defaultManager] fileExistsAtPath:ldidPath];
NSString* ldidVersion = nil;
NSData* ldidVersionData = [NSData dataWithContentsOfFile:ldidVersionPath];
if(ldidVersionData)
{
ldidVersion = [[NSString alloc] initWithData:ldidVersionData encoding:NSUTF8StringEncoding];
}
PSSpecifier* signingGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; PSSpecifier* signingGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
signingGroupSpecifier.name = @"Signing"; signingGroupSpecifier.name = @"Signing";
@ -106,7 +137,13 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
if(ldidInstalled) if(ldidInstalled)
{ {
PSSpecifier* ldidInstalledSpecifier = [PSSpecifier preferenceSpecifierNamed:@"ldid: Installed" NSString* installedTitle = @"ldid: Installed";
if(ldidVersion)
{
installedTitle = [NSString stringWithFormat:@"%@ (%@)", installedTitle, ldidVersion];
}
PSSpecifier* ldidInstalledSpecifier = [PSSpecifier preferenceSpecifierNamed:installedTitle
target:self target:self
set:nil set:nil
get:nil get:nil
@ -116,6 +153,22 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
[ldidInstalledSpecifier setProperty:@NO forKey:@"enabled"]; [ldidInstalledSpecifier setProperty:@NO forKey:@"enabled"];
ldidInstalledSpecifier.identifier = @"ldidInstalled"; ldidInstalledSpecifier.identifier = @"ldidInstalled";
[_specifiers addObject:ldidInstalledSpecifier]; [_specifiers addObject:ldidInstalledSpecifier];
if(_newerLdidVersion && ![_newerLdidVersion isEqualToString:ldidVersion])
{
NSString* updateTitle = [NSString stringWithFormat:@"Update to %@", _newerLdidVersion];
PSSpecifier* ldidUpdateSpecifier = [PSSpecifier preferenceSpecifierNamed:updateTitle
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
ldidUpdateSpecifier.identifier = @"updateLdid";
[ldidUpdateSpecifier setProperty:@YES forKey:@"enabled"];
ldidUpdateSpecifier.buttonAction = @selector(installOrUpdateLdidPressed);
[_specifiers addObject:ldidUpdateSpecifier];
}
} }
else else
{ {
@ -126,9 +179,9 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
detail:nil detail:nil
cell:PSButtonCell cell:PSButtonCell
edit:nil]; edit:nil];
installLdidSpecifier.identifier = @"ldidInstalled"; installLdidSpecifier.identifier = @"installLdid";
[installLdidSpecifier setProperty:@YES forKey:@"enabled"]; [installLdidSpecifier setProperty:@YES forKey:@"enabled"];
installLdidSpecifier.buttonAction = @selector(installLdidPressed); installLdidSpecifier.buttonAction = @selector(installOrUpdateLdidPressed);
[_specifiers addObject:installLdidSpecifier]; [_specifiers addObject:installLdidSpecifier];
} }
@ -234,11 +287,21 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
[_specifiers addObject:installAlertConfigurationSpecifier]; [_specifiers addObject:installAlertConfigurationSpecifier];
PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier]; PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", [self getTrollStoreVersion]] forKey:@"footerText"]; [otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nTrollStore is NOT for piracy!\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", [self getTrollStoreVersion]] forKey:@"footerText"];
[_specifiers addObject:otherGroupSpecifier]; [_specifiers addObject:otherGroupSpecifier];
PSSpecifier* advancedLinkSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Advanced"
target:self
set:nil
get:nil
detail:nil
cell:PSLinkListCell
edit:nil];
advancedLinkSpecifier.detailControllerClass = [TSSettingsAdvancedListController class];
[advancedLinkSpecifier setProperty:@YES forKey:@"enabled"];
[_specifiers addObject:advancedLinkSpecifier];
// Uninstall TrollStore // Uninstall TrollStore
PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore" PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore"
target:self target:self
@ -277,7 +340,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
- (NSArray*)installationConfirmationNames - (NSArray*)installationConfirmationNames
{ {
return @[@"Always (Recommended)", @"Only on Remote Installs", @"Never (Not Recommeded)"]; return @[@"Always (Recommended)", @"Only on Remote URL Installs", @"Never (Not Recommeded)"];
} }
- (void)respringButtonPressed - (void)respringButtonPressed
@ -285,41 +348,9 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
respring(); respring();
} }
- (void)installLdidPressed - (void)installOrUpdateLdidPressed
{ {
NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/download/v2.1.5-procursus5/ldid"]; [TSInstallationController installLdid];
NSURLRequest* ldidRequest = [NSURLRequest requestWithURL:ldidURL];
[TSPresentationDelegate startActivity:@"Installing ldid"];
NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:ldidRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
{
if(error)
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading ldid: %@", error] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
dispatch_async(dispatch_get_main_queue(), ^
{
[TSPresentationDelegate stopActivityWithCompletion:^
{
[TSPresentationDelegate presentViewController:errorAlert animated:YES completion:nil];
}];
});
}
else
{
spawnRoot(rootHelperPath(), @[@"install-ldid", location.path], nil, nil);
dispatch_async(dispatch_get_main_queue(), ^
{
[TSPresentationDelegate stopActivityWithCompletion:nil];
[self reloadSpecifiers];
});
}
}];
[downloadTask resume];
} }
- (void)installPersistenceHelperPressed - (void)installPersistenceHelperPressed
@ -410,4 +441,18 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
return toReturn; return toReturn;
} }
- (NSMutableArray*)argsForUninstallingTrollStore
{
NSMutableArray* args = @[@"uninstall-trollstore"].mutableCopy;
NSNumber* uninstallationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"uninstallationMethod"];
int uninstallationMethodToUse = uninstallationMethodToUseNum ? uninstallationMethodToUseNum.intValue : 0;
if(uninstallationMethodToUse == 1)
{
[args addObject:@"custom"];
}
return args;
}
@end @end

BIN
cert.p12

Binary file not shown.

Binary file not shown.