diff --git a/RootHelper/control b/RootHelper/control
index 1a94d3d..dc13dd4 100644
--- a/RootHelper/control
+++ b/RootHelper/control
@@ -1,6 +1,6 @@
Package: com.opa334.trollstoreroothelper
Name: trollstoreroothelper
-Version: 1.3.5
+Version: 1.4
Architecture: iphoneos-arm
Description: An awesome tool of some sort!!
Maintainer: opa334
diff --git a/RootHelper/entitlements.plist b/RootHelper/entitlements.plist
index 1071ba4..70c45bc 100644
--- a/RootHelper/entitlements.plist
+++ b/RootHelper/entitlements.plist
@@ -1,3 +1,4 @@
+
@@ -5,12 +6,12 @@
com.apple.private.security.container-required
- com.apple.security.exception.files.absolute-path.read-write
-
- /
-
+ com.apple.private.security.no-sandbox
+
com.apple.private.security.container-manager
+ com.apple.private.MobileContainerManager.allowed
+
com.apple.private.coreservices.canmaplsdatabase
com.apple.lsapplicationworkspace.rebuildappdatabases
@@ -19,7 +20,7 @@
com.apple.private.security.storage.MobileDocuments
- com.apple.private.MobileContainerManager.allowed
+ com.apple.private.security.storage-exempt.heritable
com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled
@@ -27,9 +28,21 @@
com.apple.private.uninstall.deletion
+ com.apple.springboard.launchapplications
+
com.apple.backboardd.launchapplications
+ com.apple.frontboard.launchapplications
+
com.apple.multitasking.termination
+ com.apple.private.mobileinstall.allowedSPI
+
+ InstallForLaunchServices
+ Install
+ UninstallForLaunchServices
+ Uninstall
+ UpdatePlaceholderMetadata
+
diff --git a/RootHelper/main.m b/RootHelper/main.m
index 6d5ebef..403c866 100644
--- a/RootHelper/main.m
+++ b/RootHelper/main.m
@@ -55,7 +55,13 @@ NSSet* appleURLSchemes(void)
LSApplicationProxy* proxy;
while(proxy = [enumerator nextObject])
{
- [systemURLSchemes unionSet:proxy.claimedURLSchemes];
+ for(NSString* claimedURLScheme in proxy.claimedURLSchemes)
+ {
+ if([claimedURLScheme isKindOfClass:NSString.class])
+ {
+ [systemURLSchemes addObject:claimedURLScheme.lowercaseString];
+ }
+ }
}
return systemURLSchemes.copy;
@@ -83,22 +89,26 @@ NSSet* immutableAppBundleIdentifiers(void)
NSDictionary* infoDictionaryForAppPath(NSString* appPath)
{
+ if(!appPath) return nil;
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"];
return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
}
NSString* appIdForAppPath(NSString* appPath)
{
+ if(!appPath) return nil;
return infoDictionaryForAppPath(appPath)[@"CFBundleIdentifier"];
}
NSString* appMainExecutablePathForAppPath(NSString* appPath)
{
+ if(!appPath) return nil;
return [appPath stringByAppendingPathComponent:infoDictionaryForAppPath(appPath)[@"CFBundleExecutable"]];
}
NSString* appPathForAppId(NSString* appId)
{
+ if(!appId) return nil;
for(NSString* appPath in trollStoreInstalledAppBundlePaths())
{
if([appIdForAppPath(appPath) isEqualToString:appId])
@@ -111,7 +121,7 @@ NSString* appPathForAppId(NSString* appId)
BOOL isMachoFile(NSString* filePath)
{
- FILE* file = fopen(filePath.UTF8String, "r");
+ FILE* file = fopen(filePath.fileSystemRepresentation, "r");
if(!file) return NO;
fseek(file, 0, SEEK_SET);
@@ -130,8 +140,8 @@ void fixPermissionsOfAppBundle(NSString* appBundlePath)
while(fileURL = [enumerator nextObject])
{
NSString* filePath = fileURL.path;
- chown(filePath.UTF8String, 33, 33);
- chmod(filePath.UTF8String, 0644);
+ chown(filePath.fileSystemRepresentation, 33, 33);
+ chmod(filePath.fileSystemRepresentation, 0644);
}
// Apply correct permissions (Second run, set executables and directories to 0755)
@@ -145,15 +155,53 @@ void fixPermissionsOfAppBundle(NSString* appBundlePath)
if(isDir || isMachoFile(filePath))
{
- chmod(filePath.UTF8String, 0755);
+ chmod(filePath.fileSystemRepresentation, 0755);
}
}
-
- // Set .app directory permissions too
- chmod(appBundlePath.UTF8String, 0755);
- chown(appBundlePath.UTF8String, 33, 33);
}
+NSArray* TSURLScheme(void)
+{
+ return @[
+ @{
+ @"CFBundleURLName" : @"com.apple.Magnifier",
+ @"CFBundleURLSchemes" : @[
+ @"apple-magnifier"
+ ]
+ }
+ ];
+}
+
+BOOL getTSURLSchemeState(NSString* customAppPath)
+{
+ NSString* pathToUse = customAppPath ?: trollStoreAppPath();
+
+ NSDictionary* trollStoreInfoDict = infoDictionaryForAppPath(pathToUse);
+ return (BOOL)trollStoreInfoDict[@"CFBundleURLTypes"];
+}
+
+void setTSURLSchemeState(BOOL newState, NSString* customAppPath)
+{
+ NSString* tsAppPath = trollStoreAppPath();
+ NSString* pathToUse = customAppPath ?: tsAppPath;
+ if(newState != getTSURLSchemeState(pathToUse))
+ {
+ NSDictionary* trollStoreInfoDict = infoDictionaryForAppPath(pathToUse);
+ NSMutableDictionary* trollStoreInfoDictM = trollStoreInfoDict.mutableCopy;
+ if(newState)
+ {
+ trollStoreInfoDictM[@"CFBundleURLTypes"] = TSURLScheme();
+ }
+ else
+ {
+ [trollStoreInfoDictM removeObjectForKey:@"CFBundleURLTypes"];
+ }
+ NSString* outPath = [pathToUse stringByAppendingPathComponent:@"Info.plist"];
+ [trollStoreInfoDictM.copy writeToURL:[NSURL fileURLWithPath:outPath] error:nil];
+ }
+}
+
+
void installLdid(NSString* ldidToCopyPath)
{
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidToCopyPath]) return;
@@ -166,8 +214,8 @@ void installLdid(NSString* ldidToCopyPath)
[[NSFileManager defaultManager] copyItemAtPath:ldidToCopyPath toPath:ldidPath error:nil];
- chmod(ldidPath.UTF8String, 0755);
- chown(ldidPath.UTF8String, 0, 0);
+ chmod(ldidPath.fileSystemRepresentation, 0755);
+ chown(ldidPath.fileSystemRepresentation, 0, 0);
}
BOOL isLdidInstalled(void)
@@ -206,7 +254,7 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput)
pid_t task_pid;
int status = -200;
- int spawnError = posix_spawn(&task_pid, [ldidPath UTF8String], &action, NULL, (char* const*)argsC, NULL);
+ int spawnError = posix_spawn(&task_pid, [ldidPath fileSystemRepresentation], &action, NULL, (char* const*)argsC, NULL);
for (NSUInteger i = 0; i < argCount; i++)
{
free(argsC[i]);
@@ -500,7 +548,19 @@ void applyPatchesToInfoDictionary(NSString* appPath)
if(URLSchemes)
{
NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray:URLSchemes];
- [URLSchemesSet minusSet:appleSchemes];
+ for(NSString* existingURLScheme in [URLSchemesSet copy])
+ {
+ if(![existingURLScheme isKindOfClass:[NSString class]])
+ {
+ [URLSchemesSet removeObject:existingURLScheme];
+ continue;
+ }
+
+ if([appleSchemes containsObject:existingURLScheme.lowercaseString])
+ {
+ [URLSchemesSet removeObject:existingURLScheme];
+ }
+ }
modifiedURLType[@"CFBundleURLSchemes"] = [URLSchemesSet allObjects];
}
[CFBundleURLTypesM addObject:modifiedURLType.copy];
@@ -517,172 +577,153 @@ void applyPatchesToInfoDictionary(NSString* appPath)
// 172: no info.plist found in app
// 173: app is not signed and cannot be signed because ldid not installed or didn't work
// 174:
-int installApp(NSString* appPath, BOOL sign, BOOL force)
+int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate)
{
NSLog(@"[installApp force = %d]", force);
- if(!infoDictionaryForAppPath(appPath)) return 172;
+ NSString* appPayloadPath = [appPackagePath stringByAppendingPathComponent:@"Payload"];
+
+ NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appPayloadPath error:nil];
+ if(!items) return 167;
+
+ NSString* appBundlePath;
+ for(NSString* item in items)
+ {
+ if([item.pathExtension isEqualToString:@"app"])
+ {
+ appBundlePath = [appPayloadPath stringByAppendingPathComponent:item];
+ break;
+ }
+ }
+ if(!appBundlePath) return 167;
- NSString* appId = appIdForAppPath(appPath);
+ NSString* appId = appIdForAppPath(appBundlePath);
if(!appId) return 176;
- if([immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
+
+ if(([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"] && !isTSUpdate) || [immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
{
return 179;
}
- if(![appId isEqualToString:@"com.opa334.TrollStore"])
+ if(!infoDictionaryForAppPath(appBundlePath)) return 172;
+
+ if(!isTSUpdate)
{
- applyPatchesToInfoDictionary(appPath);
+ applyPatchesToInfoDictionary(appBundlePath);
}
if(sign)
{
- int signRet = signApp(appPath);
+ int signRet = signApp(appBundlePath);
if(signRet != 0) return signRet;
}
- BOOL existed;
- NSError* mcmError;
- MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError];
- if(!appContainer || mcmError)
+ LSApplicationProxy* existingAppProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
+ if(existingAppProxy.installed)
{
- NSLog(@"[installApp] failed to create app container for %@: %@", appId, mcmError);
- return 170;
- }
+ // App update
+ // Replace existing bundle with new version
- if(existed)
- {
- NSLog(@"[installApp] got existing app container: %@", appContainer);
- }
- else
- {
- NSLog(@"[installApp] created app container: %@", appContainer);
- }
+ // Check if the existing app bundle is empty
+ BOOL appBundleExists = existingAppProxy.bundleURL && [existingAppProxy.bundleURL checkResourceIsReachableAndReturnError:nil];
- // 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"])
+ // LSBundleProxy also has a bundleContainerURL property, but unforunately it is unreliable and just nil most of the time
+ NSURL* bundleContainerURL = existingAppProxy.bundleURL.URLByDeletingLastPathComponent;
+
+ // 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"];
+ if(appBundleExists && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force)
{
- isEmpty = NO;
- break;
+ NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
+ return 171;
}
- }
- NSLog(@"[installApp] container is empty? %d", isEmpty);
-
- // Make sure there isn't already an app store app installed with the same identifier
- NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"];
- if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force)
- {
- 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(appPath);
-
- // Wipe old version if needed
- if(existed)
- {
- if(![appId isEqualToString:@"com.opa334.TrollStore"])
+ // Terminate app if it's still running
+ if(!isTSUpdate)
{
BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated");
}
- NSLog(@"[installApp] found existing TrollStore app, cleaning directory");
- NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
- NSURL* fileURL;
- while(fileURL = [enumerator nextObject])
+ NSLog(@"[installApp] replacing existing app with new version");
+
+ // Delete existing .app directory if it exists
+ if(appBundleExists)
{
- // do not under any circumstance delete this file as it makes iOS loose the app registration
- 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];
+ [[NSFileManager defaultManager] removeItemAtURL:existingAppProxy.bundleURL error:nil];
}
- }
- // Install app
- NSString* newAppPath = [appContainer.url.path stringByAppendingPathComponent:appPath.lastPathComponent];
- NSLog(@"[installApp] new app path: %@", newAppPath);
-
- NSError* copyError;
- BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appPath toPath:newAppPath error:©Error];
- if(suc)
- {
- NSLog(@"[installApp] App %@ installed, adding to icon cache now...", appId);
- registerPath((char*)newAppPath.UTF8String, 0, YES);
- return 0;
+ // Install new version into existing app bundle
+ NSError* copyError;
+ BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appBundlePath toPath:[bundleContainerURL.path stringByAppendingPathComponent:appBundlePath.lastPathComponent] error:©Error];
+ if(!suc)
+ {
+ NSLog(@"[installApp] Error copying new version during update: %@", copyError);
+ return 178;
+ }
}
else
{
- NSLog(@"[installApp] Failed to copy app bundle for app %@, error: %@", appId, copyError);
- return 178;
+ // Initial app install
+ // Do initial placeholder installation using LSApplicationWorkspace
+
+ NSError* installError;
+ BOOL suc = NO;
+ @try
+ {
+ suc = [[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);
+ suc = NO;
+ }
+
+ if(!suc)
+ {
+ NSLog(@"[installApp] encountered error %@ while trying to do placeholder install", installError);
+ return 180;
+ }
+
+ // Get newly installed proxy
+ existingAppProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
+
+ // Mark app as TrollStore app
+ NSURL* bundleContainerURL = existingAppProxy.bundleURL.URLByDeletingLastPathComponent;
+ NSURL* trollStoreMarkURL = [bundleContainerURL URLByAppendingPathComponent:@"_TrollStore"];
+ 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;
+ }
}
+
+ // At this point the (new version of the) app is installed but still needs to be registered
+ // Also permissions need to be fixed
+ fixPermissionsOfAppBundle(existingAppProxy.bundleURL.path);
+ registerPath((char*)existingAppProxy.bundleURL.path.fileSystemRepresentation, 0, YES);
}
int uninstallApp(NSString* appPath, NSString* appId)
{
- if(appId)
+ BOOL deleteSuc = NO;
+ if(!appId && appPath)
{
- BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App uninstalled");
-
- LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
- MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
- NSString *containerPath = [appContainer url].path;
- if(containerPath)
- {
- NSLog(@"[uninstallApp] deleting %@", containerPath);
- // delete app container path
- [[NSFileManager defaultManager] removeItemAtPath:containerPath error:nil];
- }
-
- // delete group container paths
- [[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupId, NSURL* groupURL, BOOL* stop)
- {
- // If another app still has this group, don't delete it
- NSArray* appsWithGroup = applicationsWithGroupId(groupId);
- if(appsWithGroup.count > 1)
- {
- NSLog(@"[uninstallApp] not deleting %@, appsWithGroup.count:%lu", groupURL, appsWithGroup.count);
- return;
- }
-
- NSLog(@"[uninstallApp] deleting %@", groupURL);
- [[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil];
- }];
-
- // delete app plugin paths
- for(LSPlugInKitProxy* pluginProxy in appProxy.plugInKitPlugins)
- {
- NSURL* pluginURL = pluginProxy.dataContainerURL;
- if(pluginURL)
- {
- NSLog(@"[uninstallApp] deleting %@", pluginURL);
- [[NSFileManager defaultManager] removeItemAtURL:pluginURL error:nil];
- }
- }
+ // Special case, something is wrong about this app
+ // Most likely the Info.plist is missing
+ // (Hopefully this never happens)
+ deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:nil];
+ registerPath((char*)appPath.fileSystemRepresentation, 1, YES);
}
- // unregister app
- registerPath((char*)appPath.UTF8String, 1, YES);
+ if(appId)
+ {
+ deleteSuc = [[LSApplicationWorkspace defaultWorkspace] uninstallApplication:appId withOptions:nil];
+ }
- NSLog(@"[uninstallApp] deleting %@", [appPath stringByDeletingLastPathComponent]);
- // delete app
- BOOL deleteSuc = [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:nil];
if(deleteSuc)
{
return 0;
@@ -693,35 +734,18 @@ int uninstallApp(NSString* appPath, NSString* appId)
}
}
-/*int detachApp(NSString* appId)
-{
- NSString* appPath = appPathForAppId(appId);
- NSString* executablePath = appMainExecutablePathForAppPath(appPath);
- NSString* trollStoreMarkPath = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"];
-
- // Not attached to TrollStore
- if(![[NSFileManager defaultManager] fileExistsAtPath:trollStoreMarkPath]) return 0;
-
- // Refuse to detach app if it's still signed with fake root cert
- SecStaticCodeRef codeRef = getStaticCodeRef(executablePath);
- if(codeRef != NULL)
- {
- if(codeCertChainContainsFakeAppStoreExtensions(codeRef))
- {
- CFRelease(codeRef);
- return 184;
- }
- }
-
- // Deleting TrollStore mark to detach app
- BOOL suc = [[NSFileManager defaultManager] removeItemAtPath:trollStoreMarkPath error:nil];
- return !suc;
-}*/
-
int uninstallAppByPath(NSString* appPath)
{
if(!appPath) return 1;
- NSString* appId = appIdForAppPath(appPath);
+
+ NSString* standardizedAppPath = appPath.stringByStandardizingPath;
+
+ if(![standardizedAppPath hasPrefix:@"/var/containers/Bundle/Application/"] && standardizedAppPath.pathComponents.count == 5)
+ {
+ return 1;
+ }
+
+ NSString* appId = appIdForAppPath(standardizedAppPath);
return uninstallApp(appPath, appId);
}
@@ -741,38 +765,21 @@ int installIpa(NSString* ipaPath, BOOL force)
if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166;
BOOL suc = NO;
- NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
+ NSString* tmpPackagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
- suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:nil];
+ suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPackagePath withIntermediateDirectories:NO attributes:nil error:nil];
if(!suc) return 1;
- extract(ipaPath, tmpPath);
-
- NSString* tmpPayloadPath = [tmpPath stringByAppendingPathComponent:@"Payload"];
-
- NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpPayloadPath error:nil];
- if(!items) return 167;
-
- NSString* tmpAppPath;
- for(NSString* item in items)
+ int extractRet = extract(ipaPath, tmpPackagePath);
+ if(extractRet != 0)
{
- if([item.pathExtension isEqualToString:@"app"])
- {
- tmpAppPath = [tmpPayloadPath stringByAppendingPathComponent:item];
- break;
- }
+ [[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
+ return 168;
}
- if(!tmpAppPath) return 167;
- NSString* appId = appIdForAppPath(tmpAppPath);
- if([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"])
- {
- return 179;
- }
+ int ret = installApp(tmpPackagePath, YES, force, NO);
- int ret = installApp(tmpAppPath, YES, force);
-
- [[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil];
+ [[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
return ret;
}
@@ -785,78 +792,85 @@ void uninstallAllApps(void)
}
}
-BOOL uninstallTrollStore(BOOL unregister)
+int uninstallTrollStore(BOOL unregister)
{
NSString* trollStore = trollStorePath();
if(![[NSFileManager defaultManager] fileExistsAtPath:trollStore]) return NO;
if(unregister)
{
- registerPath((char*)trollStoreAppPath().UTF8String, 1, YES);
+ registerPath((char*)trollStoreAppPath().fileSystemRepresentation, 1, YES);
}
return [[NSFileManager defaultManager] removeItemAtPath:trollStore error:nil];
}
-BOOL installTrollStore(NSString* pathToTar)
+int installTrollStore(NSString* pathToTar)
{
- //_CFPreferencesCopyValueWithContainerType _CFPreferencesCopyValueWithContainer = (_CFPreferencesCopyValueWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesCopyValueWithContainer");
_CFPreferencesSetValueWithContainerType _CFPreferencesSetValueWithContainer = (_CFPreferencesSetValueWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesSetValueWithContainer");
_CFPreferencesSynchronizeWithContainerType _CFPreferencesSynchronizeWithContainer = (_CFPreferencesSynchronizeWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesSynchronizeWithContainer");
-
- /*CFPropertyListRef SBShowNonDefaultSystemAppsValue = _CFPreferencesCopyValueWithContainer(CFSTR("SBShowNonDefaultSystemApps"), CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
- if(SBShowNonDefaultSystemAppsValue != kCFBooleanTrue)
- {*/
- _CFPreferencesSetValueWithContainer(CFSTR("SBShowNonDefaultSystemApps"), kCFBooleanTrue, CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
- _CFPreferencesSynchronizeWithContainer(CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
- //NSLog(@"unrestricted springboard apps");
- /*}*/
-
+ _CFPreferencesSetValueWithContainer(CFSTR("SBShowNonDefaultSystemApps"), kCFBooleanTrue, CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
+ _CFPreferencesSynchronizeWithContainer(CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
if(![[NSFileManager defaultManager] fileExistsAtPath:pathToTar]) return 1;
if(![pathToTar.pathExtension isEqualToString:@"tar"]) return 1;
- NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
- BOOL suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:nil];
+ NSString* tmpPackagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
+ NSString* tmpPayloadPath = [tmpPackagePath stringByAppendingPathComponent:@"Payload"];
+ BOOL suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPayloadPath withIntermediateDirectories:YES attributes:nil error:nil];
if(!suc) return 1;
- extract(pathToTar, tmpPath);
+ int extractRet = extract(pathToTar, tmpPayloadPath);
+ if(extractRet != 0)
+ {
+ [[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
+ return 169;
+ }
- NSString* tmpTrollStore = [tmpPath stringByAppendingPathComponent:@"TrollStore.app"];
- if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStore]) return 1;
+ NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
+ if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;
// Save existing ldid installation if it exists
NSString* existingLdidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidPath])
{
- NSString* tmpLdidPath = [tmpTrollStore stringByAppendingPathComponent:@"ldid"];
+ NSString* tmpLdidPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid"];
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidPath])
{
[[NSFileManager defaultManager] copyItemAtPath:existingLdidPath toPath:tmpLdidPath error:nil];
}
}
+ // Merge existing URL scheme settings value
+ if(!getTSURLSchemeState(nil))
+ {
+ setTSURLSchemeState(NO, tmpTrollStorePath);
+ }
+
// Update system app persistence helper if used
LSApplicationProxy* persistenceHelperApp = findPersistenceHelperApp(PERSISTENCE_HELPER_TYPE_SYSTEM);
if(persistenceHelperApp)
{
- NSString* trollStorePersistenceHelper = [tmpTrollStore stringByAppendingPathComponent:@"PersistenceHelper"];
- NSString* trollStoreRootHelper = [tmpTrollStore stringByAppendingPathComponent:@"trollstorehelper"];
+ NSString* trollStorePersistenceHelper = [tmpTrollStorePath stringByAppendingPathComponent:@"PersistenceHelper"];
+ NSString* trollStoreRootHelper = [tmpTrollStorePath stringByAppendingPathComponent:@"trollstorehelper"];
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
}
- return installApp(tmpTrollStore, NO, YES);;
+ int ret = installApp(tmpPackagePath, NO, YES, YES);
+ NSLog(@"[installTrollStore] installApp => %d", ret);
+ [[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
+ return ret;
}
void refreshAppRegistrations()
{
- //registerPath((char*)trollStoreAppPath().UTF8String, 1, YES);
- registerPath((char*)trollStoreAppPath().UTF8String, 0, YES);
+ //registerPath((char*)trollStoreAppPath().fileSystemRepresentation, 1, YES);
+ registerPath((char*)trollStoreAppPath().fileSystemRepresentation, 0, YES);
for(NSString* appPath in trollStoreInstalledAppBundlePaths())
{
- //registerPath((char*)appPath.UTF8String, 1, YES);
- registerPath((char*)appPath.UTF8String, 0, YES);
+ //registerPath((char*)appPath.fileSystemRepresentation, 1, YES);
+ registerPath((char*)appPath.fileSystemRepresentation, 0, YES);
}
}
@@ -893,8 +907,8 @@ BOOL _installPersistenceHelper(LSApplicationProxy* appProxy, NSString* sourcePer
return NO;
}
- chmod(executablePath.UTF8String, 0755);
- chown(executablePath.UTF8String, 33, 33);
+ chmod(executablePath.fileSystemRepresentation, 0755);
+ chown(executablePath.fileSystemRepresentation, 33, 33);
NSError* error;
if(![[NSFileManager defaultManager] copyItemAtPath:sourceRootHelper toPath:rootHelperPath error:&error])
@@ -902,8 +916,8 @@ BOOL _installPersistenceHelper(LSApplicationProxy* appProxy, NSString* sourcePer
NSLog(@"error copying root helper: %@", error);
}
- chmod(rootHelperPath.UTF8String, 0755);
- chown(rootHelperPath.UTF8String, 0, 0);
+ chmod(rootHelperPath.fileSystemRepresentation, 0755);
+ chown(rootHelperPath.fileSystemRepresentation, 0, 0);
// mark system app as persistence helper
if(![[NSFileManager defaultManager] fileExistsAtPath:markPath])
@@ -1050,8 +1064,6 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
NSLog(@"trollstore helper go, uid: %d, gid: %d", getuid(), getgid());
- loadMCMFramework();
-
int ret = 0;
NSString* cmd = [NSString stringWithUTF8String:argv[1]];
@@ -1073,12 +1085,7 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
if(argc <= 2) return -3;
NSString* appId = [NSString stringWithUTF8String:argv[2]];
ret = uninstallAppById(appId);
- } /*else if([cmd isEqualToString:@"detach"])
- {
- if(argc <= 2) return -3;
- NSString* appId = [NSString stringWithUTF8String:argv[2]];
- ret = detachApp(appId);
- } */else if([cmd isEqualToString:@"uninstall-path"])
+ } else if([cmd isEqualToString:@"uninstall-path"])
{
if(argc <= 2) return -3;
NSString* appPath = [NSString stringWithUTF8String:argv[2]];
@@ -1093,7 +1100,10 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
{
uninstallAllApps();
uninstallTrollStore(YES);
- } else if([cmd isEqualToString:@"install-ldid"])
+ } else if([cmd isEqualToString:@"uninstall-trollstore-preserve-apps"])
+ {
+ uninstallTrollStore(YES);
+ }else if([cmd isEqualToString:@"install-ldid"])
{
if(argc <= 2) return -3;
NSString* ldidPath = [NSString stringWithUTF8String:argv[2]];
@@ -1129,7 +1139,16 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
NSString* trollStoreMark = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"];
if([[NSFileManager defaultManager] fileExistsAtPath:trollStoreMark])
{
- registerPath((char*)appPath.UTF8String, 0, [newRegistration isEqualToString:@"System"]);
+ registerPath((char*)appPath.fileSystemRepresentation, 0, [newRegistration isEqualToString:@"System"]);
+ }
+ } else if([cmd isEqualToString:@"url-scheme"])
+ {
+ if(argc <= 2) return -3;
+ NSString* modifyArg = [NSString stringWithUTF8String:argv[2]];
+ BOOL newState = [modifyArg isEqualToString:@"enable"];
+ if(newState == YES || [modifyArg isEqualToString:@"disable"])
+ {
+ setTSURLSchemeState(newState, nil);
}
}
diff --git a/RootHelper/unarchive.m b/RootHelper/unarchive.m
index 83bbd5b..be72fb2 100644
--- a/RootHelper/unarchive.m
+++ b/RootHelper/unarchive.m
@@ -45,7 +45,7 @@ int extract(NSString* fileToExtract, NSString* extractionPath)
ext = archive_write_disk_new();
archive_write_disk_set_options(ext, flags);
archive_write_disk_set_standard_lookup(ext);
- if ((r = archive_read_open_filename(a, fileToExtract.UTF8String, 10240)))
+ if ((r = archive_read_open_filename(a, fileToExtract.fileSystemRepresentation, 10240)))
return 1;
for (;;)
{
@@ -59,8 +59,8 @@ int extract(NSString* fileToExtract, NSString* extractionPath)
NSString* currentFile = [NSString stringWithUTF8String:archive_entry_pathname(entry)];
NSString* fullOutputPath = [extractionPath stringByAppendingPathComponent:currentFile];
- //printf("extracting %s to %s\n", currentFile.UTF8String, fullOutputPath.UTF8String);
- archive_entry_set_pathname(entry, fullOutputPath.UTF8String);
+ //printf("extracting %@ to %@\n", currentFile, fullOutputPath);
+ archive_entry_set_pathname(entry, fullOutputPath.fileSystemRepresentation);
r = archive_write_header(ext, entry);
if (r < ARCHIVE_OK)
diff --git a/Shared/CoreServices.h b/Shared/CoreServices.h
index de33eef..4a21547 100644
--- a/Shared/CoreServices.h
+++ b/Shared/CoreServices.h
@@ -1,6 +1,9 @@
+extern NSString *LSInstallTypeKey;
+
@interface LSBundleProxy
@property (nonatomic,readonly) NSString * bundleIdentifier;
@property (nonatomic) NSURL* dataContainerURL;
+@property (nonatomic,readonly) NSURL* bundleContainerURL;
-(NSString*)localizedName;
@end
@@ -26,7 +29,7 @@
- (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 internal:(BOOL)arg2 user:(BOOL)arg3;
- (BOOL)openApplicationWithBundleID:(NSString *)arg1 ;
- (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy*))block;
-- (BOOL)installApplication:(NSString*)pathToExtractedApp withOptions:(NSDictionary*)options;
+- (BOOL)installApplication:(NSURL*)appPackageURL withOptions:(NSDictionary*)options error:(NSError**)error;
- (BOOL)uninstallApplication:(NSString*)appId withOptions:(NSDictionary*)options;
@end
diff --git a/Shared/TSListControllerShared.h b/Shared/TSListControllerShared.h
index b78269b..cb9612d 100644
--- a/Shared/TSListControllerShared.h
+++ b/Shared/TSListControllerShared.h
@@ -3,10 +3,6 @@
#import
@interface TSListControllerShared : PSListController
-{
- UIAlertController* _activityController;
-}
-
- (BOOL)isTrollStore;
- (NSString*)getTrollStoreVersion;
- (void)downloadTrollStoreAndDo:(void (^)(NSString* localTrollStoreTarPath))doHandler;
diff --git a/Shared/TSListControllerShared.m b/Shared/TSListControllerShared.m
index a25c456..f57a1be 100644
--- a/Shared/TSListControllerShared.m
+++ b/Shared/TSListControllerShared.m
@@ -190,19 +190,26 @@
- (void)uninstallTrollStorePressed
{
- UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" 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* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
- [uninstallWarningAlert addAction:cancelAction];
-
- UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
+ UIAlertAction* uninstallAllAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Uninstall Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
{
spawnRoot(rootHelperPath(), @[@"uninstall-trollstore"], nil, nil);
[self handleUninstallation];
}];
- [uninstallWarningAlert addAction:continueAction];
+ [uninstallAlert addAction:uninstallAllAction];
- [TSPresentationDelegate presentViewController:uninstallWarningAlert animated:YES completion:nil];
+ UIAlertAction* preserveAppsAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Preserve Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
+ {
+ spawnRoot(rootHelperPath(), @[@"uninstall-trollstore-preserve-apps"], nil, nil);
+ [self handleUninstallation];
+ }];
+ [uninstallAlert addAction:preserveAppsAction];
+
+ UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
+ [uninstallAlert addAction:cancelAction];
+
+ [TSPresentationDelegate presentViewController:uninstallAlert animated:YES completion:nil];
}
@end
\ No newline at end of file
diff --git a/TrollHelper/Resources/Info.plist b/TrollHelper/Resources/Info.plist
index 6891349..13e385b 100644
--- a/TrollHelper/Resources/Info.plist
+++ b/TrollHelper/Resources/Info.plist
@@ -52,7 +52,7 @@
iPhoneOS
CFBundleVersion
- 1.3.5
+ 1.4
LSRequiresIPhoneOS
UIDeviceFamily
diff --git a/TrollHelper/control b/TrollHelper/control
index 3a87a38..54b263f 100644
--- a/TrollHelper/control
+++ b/TrollHelper/control
@@ -1,6 +1,6 @@
Package: com.opa334.trollstorehelper
Name: TrollStore Helper
-Version: 1.3.5
+Version: 1.4
Architecture: iphoneos-arm
Description: Helper utility to install and manage TrollStore!
Maintainer: opa334
diff --git a/TrollHelper/entitlements.plist b/TrollHelper/entitlements.plist
index 687e38b..8d8ff62 100644
--- a/TrollHelper/entitlements.plist
+++ b/TrollHelper/entitlements.plist
@@ -3,31 +3,7 @@
application-identifier
- com.opa334.TrollStore
- platform-application
-
- com.apple.security.exception.files.absolute-path.read-write
-
- /
-
- com.apple.private.security.no-sandbox
-
- com.apple.private.persona-mgmt
-
- com.apple.private.security.container-manager
-
- com.apple.private.coreservices.canmaplsdatabase
-
- com.apple.lsapplicationworkspace.rebuildappdatabases
-
- com.apple.private.MobileContainerManager.allowed
-
- com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled
-
- com.apple.private.MobileInstallationHelperService.allowed
-
- com.apple.private.uninstall.deletion
-
+ com.opa334.trollstorepersistencehelper
com.apple.CommCenter.fine-grained
cellular-plan
@@ -35,11 +11,49 @@
data-allowed-write
preferences-write
+ com.apple.private.persona-mgmt
+
+
+
+ platform-application
+
+ com.apple.private.security.no-sandbox
+
+ com.apple.private.security.container-manager
+
+ com.apple.private.MobileContainerManager.allowed
+
+ com.apple.private.coreservices.canmaplsdatabase
+
+ com.apple.lsapplicationworkspace.rebuildappdatabases
+
com.apple.private.security.storage.AppBundles
+ com.apple.private.security.storage.MobileDocuments
+
+ com.apple.private.security.storage-exempt.heritable
+
+ com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled
+
+ com.apple.private.MobileInstallationHelperService.allowed
+
+ com.apple.private.uninstall.deletion
+
+ com.apple.springboard.launchapplications
+
com.apple.backboardd.launchapplications
+ com.apple.frontboard.launchapplications
+
com.apple.multitasking.termination
+ com.apple.private.mobileinstall.allowedSPI
+
+ InstallForLaunchServices
+ Install
+ UninstallForLaunchServices
+ Uninstall
+ UpdatePlaceholderMetadata
+
\ No newline at end of file
diff --git a/TrollStore/Resources/Info.plist b/TrollStore/Resources/Info.plist
index 3556ea2..403e4f5 100644
--- a/TrollStore/Resources/Info.plist
+++ b/TrollStore/Resources/Info.plist
@@ -50,7 +50,7 @@
iPhoneOS
CFBundleVersion
- 1.3.5
+ 1.4
LSRequiresIPhoneOS
UIDeviceFamily
diff --git a/TrollStore/TSAppInfo.m b/TrollStore/TSAppInfo.m
index d9c7e02..b8867b5 100644
--- a/TrollStore/TSAppInfo.m
+++ b/TrollStore/TSAppInfo.m
@@ -366,7 +366,7 @@ extern UIImage* imageWithSize(UIImage* image, CGSize size);
_archive = archive_read_new();
archive_read_support_format_all(_archive);
archive_read_support_filter_all(_archive);
- int r = archive_read_open_filename(_archive, _path.UTF8String, 10240);
+ int r = archive_read_open_filename(_archive, _path.fileSystemRepresentation, 10240);
return r ? r : 0;
}
diff --git a/TrollStore/TSAppTableViewController.m b/TrollStore/TSAppTableViewController.m
index 89e25fb..368be5f 100644
--- a/TrollStore/TSAppTableViewController.m
+++ b/TrollStore/TSAppTableViewController.m
@@ -178,7 +178,7 @@ UIImage* imageWithSize(UIImage* image, CGSize size)
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray *)urls
{
NSString* pathToIPA = urls.firstObject.path;
- [TSInstallationController presentInstallationAlertForFile:pathToIPA completion:nil];
+ [TSInstallationController presentInstallationAlertIfEnabledForFile:pathToIPA isRemoteInstall:NO completion:nil];
}
- (void)openAppPressedForRowAtIndexPath:(NSIndexPath*)indexPath
diff --git a/TrollStore/TSApplicationsManager.m b/TrollStore/TSApplicationsManager.m
index 880d5eb..b585132 100644
--- a/TrollStore/TSApplicationsManager.m
+++ b/TrollStore/TSApplicationsManager.m
@@ -30,6 +30,12 @@
case 167:
errorDescription = @"The IPA file does not appear to contain an app.";
break;
+ case 168:
+ errorDescription = @"Failed to extract IPA file.";
+ break;
+ case 169:
+ errorDescription = @"Failed to extract update tar file.";
+ break;
// App install errors
case 170:
errorDescription = @"Failed to create container for app bundle.";
@@ -61,10 +67,9 @@
case 179:
errorDescription = @"The app you tried to install has the same identifier as a system app already installed on the device. The installation has been prevented to protect you from possible bootloops or other issues.";
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;*/
+ case 180:
+ errorDescription = @"The LSApplicationWorkspace app installation failed.";
+ break;
}
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
diff --git a/TrollStore/TSInstallationController.h b/TrollStore/TSInstallationController.h
index 122b6aa..96ebdc2 100644
--- a/TrollStore/TSInstallationController.h
+++ b/TrollStore/TSInstallationController.h
@@ -2,7 +2,7 @@
@interface TSInstallationController : NSObject
-+ (void)presentInstallationAlertForFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion;
++ (void)presentInstallationAlertIfEnabledForFile:(NSString*)pathToIPA isRemoteInstall:(BOOL)remoteInstall completion:(void (^)(BOOL, NSError*))completionBlock;
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completion;
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion;
diff --git a/TrollStore/TSInstallationController.m b/TrollStore/TSInstallationController.m
index 9d1a236..fd02b6d 100644
--- a/TrollStore/TSInstallationController.m
+++ b/TrollStore/TSInstallationController.m
@@ -5,6 +5,8 @@
#import
#import
+extern NSUserDefaults* trollStoreUserDefaults(void);
+
@implementation TSInstallationController
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completionBlock
@@ -73,8 +75,30 @@
});
}
-+ (void)presentInstallationAlertForFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completionBlock
++ (void)presentInstallationAlertIfEnabledForFile:(NSString*)pathToIPA isRemoteInstall:(BOOL)remoteInstall completion:(void (^)(BOOL, NSError*))completionBlock
{
+ NSNumber* installAlertConfigurationNum = [trollStoreUserDefaults() objectForKey:@"installAlertConfiguration"];
+ NSUInteger installAlertConfiguration = 0;
+ if(installAlertConfigurationNum)
+ {
+ installAlertConfiguration = installAlertConfigurationNum.unsignedIntegerValue;
+ if(installAlertConfiguration > 2)
+ {
+ // broken pref? revert to 0
+ installAlertConfiguration = 0;
+ }
+ }
+
+ // Check if user disabled alert for this kind of install
+ if(installAlertConfiguration > 0)
+ {
+ if(installAlertConfiguration == 2 || (installAlertConfiguration == 1 && !remoteInstall))
+ {
+ [self handleAppInstallFromFile:pathToIPA completion:completionBlock];
+ return;
+ }
+ }
+
TSAppInfo* appInfo = [[TSAppInfo alloc] initWithIPAPath:pathToIPA];
[appInfo loadInfoWithCompletion:^(NSError* error)
{
@@ -144,7 +168,7 @@
NSString* tmpIpaPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.ipa"];
[[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil];
[[NSFileManager defaultManager] moveItemAtPath:location.path toPath:tmpIpaPath error:nil];
- [self presentInstallationAlertForFile:tmpIpaPath completion:^(BOOL success, NSError* error)
+ [self presentInstallationAlertIfEnabledForFile:tmpIpaPath isRemoteInstall:YES completion:^(BOOL success, NSError* error)
{
[[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil];
if(completionBlock) completionBlock(success, error);
diff --git a/TrollStore/TSSceneDelegate.m b/TrollStore/TSSceneDelegate.m
index 8f3b4c1..8550dfe 100644
--- a/TrollStore/TSSceneDelegate.m
+++ b/TrollStore/TSSceneDelegate.m
@@ -32,7 +32,7 @@
if ([url.pathExtension.lowercaseString isEqualToString:@"ipa"] || [url.pathExtension.lowercaseString isEqualToString:@"tipa"])
{
- [TSInstallationController presentInstallationAlertForFile:url.path completion:^(BOOL success, NSError* error){
+ [TSInstallationController presentInstallationAlertIfEnabledForFile:url.path isRemoteInstall:NO completion:^(BOOL success, NSError* error){
doneBlock(NO);
}];
}
diff --git a/TrollStore/TSSettingsListController.m b/TrollStore/TSSettingsListController.m
index 9f3e6d2..2b6f7e6 100644
--- a/TrollStore/TSSettingsListController.m
+++ b/TrollStore/TSSettingsListController.m
@@ -1,8 +1,14 @@
#import "TSSettingsListController.h"
#import
#import
+#import
#import
+@interface NSUserDefaults (Private)
+- (instancetype)_initWithSuiteName:(NSString *)suiteName container:(NSURL *)container;
+@end
+extern NSUserDefaults* trollStoreUserDefaults(void);
+
@implementation TSSettingsListController
- (void)viewDidLoad
@@ -195,6 +201,40 @@
}
}
+ PSSpecifier* installationSettingsGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
+ installationSettingsGroupSpecifier.name = @"Security";
+ [installationSettingsGroupSpecifier setProperty:@"The URL Scheme, when enabled, will allow apps and websites to trigger TrollStore installations through the apple-magnifier://install?url= URL scheme." forKey:@"footerText"];
+
+ [_specifiers addObject:installationSettingsGroupSpecifier];
+
+ PSSpecifier* URLSchemeToggle = [PSSpecifier preferenceSpecifierNamed:@"URL Scheme Enabled"
+ target:self
+ set:@selector(setURLSchemeEnabled:forSpecifier:)
+ get:@selector(getURLSchemeEnabledForSpecifier:)
+ detail:nil
+ cell:PSSwitchCell
+ edit:nil];
+
+ [_specifiers addObject:URLSchemeToggle];
+
+ PSSpecifier* installAlertConfigurationSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Show Install Confirmation Alert"
+ target:self
+ set:@selector(setPreferenceValue:specifier:)
+ get:@selector(readPreferenceValue:)
+ detail:nil
+ cell:PSLinkListCell
+ edit:nil];
+
+ installAlertConfigurationSpecifier.detailControllerClass = [PSListItemsController class];
+ [installAlertConfigurationSpecifier setProperty:@"installationConfirmationValues" forKey:@"valuesDataSource"];
+ [installAlertConfigurationSpecifier setProperty:@"installationConfirmationNames" forKey:@"titlesDataSource"];
+ [installAlertConfigurationSpecifier setProperty:@"com.opa334.TrollStore" forKey:@"defaults"];
+ [installAlertConfigurationSpecifier setProperty:@"installAlertConfiguration" forKey:@"key"];
+ [installAlertConfigurationSpecifier setProperty:@0 forKey:@"default"];
+
+ [_specifiers addObject:installAlertConfigurationSpecifier];
+
+
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"];
[_specifiers addObject:otherGroupSpecifier];
@@ -230,6 +270,16 @@
return _specifiers;
}
+- (NSArray*)installationConfirmationValues
+{
+ return @[@0, @1, @2];
+}
+
+- (NSArray*)installationConfirmationNames
+{
+ return @[@"Always (Recommended)", @"Only on Remote Installs", @"Never (Not Recommeded)"];
+}
+
- (void)respringButtonPressed
{
respring();
@@ -313,9 +363,51 @@
[TSPresentationDelegate presentViewController:selectAppAlert animated:YES completion:nil];
}
+- (id)getURLSchemeEnabledForSpecifier:(PSSpecifier*)specifier
+{
+ BOOL URLSchemeActive = (BOOL)[NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleURLTypes"];
+ return @(URLSchemeActive);
+}
+
+- (void)setURLSchemeEnabled:(id)value forSpecifier:(PSSpecifier*)specifier
+{
+ NSNumber* newValue = value;
+ NSString* newStateString = [newValue boolValue] ? @"enable" : @"disable";
+ spawnRoot(rootHelperPath(), @[@"url-scheme", newStateString], nil, nil);
+
+ UIAlertController* rebuildNoticeAlert = [UIAlertController alertControllerWithTitle:@"URL Scheme Changed" message:@"In order to properly apply the change of the URL scheme setting, rebuilding the icon cache is needed." preferredStyle:UIAlertControllerStyleAlert];
+ UIAlertAction* rebuildNowAction = [UIAlertAction actionWithTitle:@"Rebuild Now" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
+ {
+ [self rebuildIconCachePressed];
+ }];
+ [rebuildNoticeAlert addAction:rebuildNowAction];
+
+ UIAlertAction* rebuildLaterAction = [UIAlertAction actionWithTitle:@"Rebuild Later" style:UIAlertActionStyleCancel handler:nil];
+ [rebuildNoticeAlert addAction:rebuildLaterAction];
+
+ [TSPresentationDelegate presentViewController:rebuildNoticeAlert animated:YES completion:nil];
+}
+
- (void)doTheDashPressed
{
spawnRoot(rootHelperPath(), @[@"dash"], nil, nil);
}
+- (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
\ No newline at end of file
diff --git a/TrollStore/control b/TrollStore/control
index 502dbb9..264d020 100644
--- a/TrollStore/control
+++ b/TrollStore/control
@@ -1,6 +1,6 @@
Package: com.opa334.trollstore
Name: TrollStore
-Version: 1.3.5
+Version: 1.4
Architecture: iphoneos-arm
Description: An awesome application!
Maintainer: opa334
diff --git a/TrollStore/main.m b/TrollStore/main.m
index dee9a84..99cf0a0 100644
--- a/TrollStore/main.m
+++ b/TrollStore/main.m
@@ -2,6 +2,11 @@
#import "TSAppDelegate.h"
#import "TSUtil.h"
+NSUserDefaults* trollStoreUserDefaults(void)
+{
+ return [[NSUserDefaults alloc] initWithSuiteName:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Preferences/com.opa334.TrollStore.plist"]];
+}
+
int main(int argc, char *argv[]) {
@autoreleasepool {
chineseWifiFixup();