This commit is contained in:
opa334 2022-11-19 23:22:20 +01:00
parent 2d762b39ef
commit 7f34ae76a6
20 changed files with 466 additions and 288 deletions

View File

@ -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

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
@ -5,12 +6,12 @@
<true/>
<key>com.apple.private.security.container-required</key>
<false/>
<key>com.apple.security.exception.files.absolute-path.read-write</key>
<array>
<string>/</string>
</array>
<key>com.apple.private.security.no-sandbox</key>
<true/>
<key>com.apple.private.security.container-manager</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<true/>
<key>com.apple.private.coreservices.canmaplsdatabase</key>
<true/>
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
@ -19,7 +20,7 @@
<true/>
<key>com.apple.private.security.storage.MobileDocuments</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<key>com.apple.private.security.storage-exempt.heritable</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled</key>
<true/>
@ -27,9 +28,21 @@
<true/>
<key>com.apple.private.uninstall.deletion</key>
<true/>
<key>com.apple.springboard.launchapplications</key>
<true/>
<key>com.apple.backboardd.launchapplications</key>
<true/>
<key>com.apple.frontboard.launchapplications</key>
<true/>
<key>com.apple.multitasking.termination</key>
<true/>
<key>com.apple.private.mobileinstall.allowedSPI</key>
<array>
<string>InstallForLaunchServices</string>
<string>Install</string>
<string>UninstallForLaunchServices</string>
<string>Uninstall</string>
<string>UpdatePlaceholderMetadata</string>
</array>
</dict>
</plist>

View File

@ -55,7 +55,13 @@ NSSet<NSString*>* 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<NSString*>* 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,14 +155,52 @@ 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)
{
@ -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"];
NSString* appId = appIdForAppPath(appPath);
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(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"])
{
isEmpty = NO;
break;
}
}
// LSBundleProxy also has a bundleContainerURL property, but unforunately it is unreliable and just nil most of the time
NSURL* bundleContainerURL = existingAppProxy.bundleURL.URLByDeletingLastPathComponent;
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)
// 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)
{
NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
return 171;
}
// Terminate app if it's still running
if(!isTSUpdate)
{
BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App updated");
}
NSLog(@"[installApp] replacing existing app with new version");
// Delete existing .app directory if it exists
if(appBundleExists)
{
[[NSFileManager defaultManager] removeItemAtURL:existingAppProxy.bundleURL error:nil];
}
// Install new version into existing app bundle
NSError* copyError;
BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appBundlePath toPath:[bundleContainerURL.path stringByAppendingPathComponent:appBundlePath.lastPathComponent] error:&copyError];
if(!suc)
{
NSLog(@"[installApp] Error copying new version during update: %@", copyError);
return 178;
}
}
else
{
// 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;
}
fixPermissionsOfAppBundle(appPath);
// Wipe old version if needed
if(existed)
{
if(![appId isEqualToString:@"com.opa334.TrollStore"])
{
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])
{
// 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];
}
}
// 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:&copyError];
if(suc)
{
NSLog(@"[installApp] App %@ installed, adding to icon cache now...", appId);
registerPath((char*)newAppPath.UTF8String, 0, YES);
return 0;
}
else
{
NSLog(@"[installApp] Failed to copy app bundle for app %@, error: %@", appId, copyError);
return 178;
}
// 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)
{
BOOL deleteSuc = NO;
if(!appId && appPath)
{
// 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);
}
if(appId)
{
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];
deleteSuc = [[LSApplicationWorkspace defaultWorkspace] uninstallApplication:appId withOptions: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<LSApplicationProxy*>* appsWithGroup = applicationsWithGroupId(groupId);
if(appsWithGroup.count > 1)
{
NSLog(@"[uninstallApp] not deleting %@, appsWithGroup.count:%lu", groupURL, appsWithGroup.count);
return;
}
NSLog(@"[uninstallApp] deleting %@", groupURL);
[[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil];
}];
// 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];
}
}
}
// unregister app
registerPath((char*)appPath.UTF8String, 1, YES);
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;
}
}
if(!tmpAppPath) return 167;
NSString* appId = appIdForAppPath(tmpAppPath);
if([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"])
{
return 179;
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
return 168;
}
int ret = installApp(tmpAppPath, YES, force);
int ret = installApp(tmpPackagePath, YES, force, NO);
[[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");
/*}*/
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,6 +1100,9 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
{
uninstallAllApps();
uninstallTrollStore(YES);
} else if([cmd isEqualToString:@"uninstall-trollstore-preserve-apps"])
{
uninstallTrollStore(YES);
}else if([cmd isEqualToString:@"install-ldid"])
{
if(argc <= 2) return -3;
@ -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);
}
}

View File

@ -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)

View File

@ -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

View File

@ -3,10 +3,6 @@
#import <Preferences/PSSpecifier.h>
@interface TSListControllerShared : PSListController
{
UIAlertController* _activityController;
}
- (BOOL)isTrollStore;
- (NSString*)getTrollStoreVersion;
- (void)downloadTrollStoreAndDo:(void (^)(NSString* localTrollStoreTarPath))doHandler;

View File

@ -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

View File

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

View File

@ -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

View File

@ -3,31 +3,7 @@
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>com.opa334.TrollStore</string>
<key>platform-application</key>
<true/>
<key>com.apple.security.exception.files.absolute-path.read-write</key>
<array>
<string>/</string>
</array>
<key>com.apple.private.security.no-sandbox</key>
<true/>
<key>com.apple.private.persona-mgmt</key>
<true/>
<key>com.apple.private.security.container-manager</key>
<true/>
<key>com.apple.private.coreservices.canmaplsdatabase</key>
<true/>
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.allowed</key>
<true/>
<key>com.apple.private.uninstall.deletion</key>
<true/>
<string>com.opa334.trollstorepersistencehelper</string>
<key>com.apple.CommCenter.fine-grained</key>
<array>
<string>cellular-plan</string>
@ -35,11 +11,49 @@
<string>data-allowed-write</string>
<string>preferences-write</string>
</array>
<key>com.apple.private.persona-mgmt</key>
<true/>
<!-- All entitlements from RootHelper except for com.apple.private.security.container-required=false -->
<key>platform-application</key>
<true/>
<key>com.apple.private.security.no-sandbox</key>
<true/>
<key>com.apple.private.security.container-manager</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<true/>
<key>com.apple.private.coreservices.canmaplsdatabase</key>
<true/>
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
<true/>
<key>com.apple.private.security.storage.AppBundles</key>
<true/>
<key>com.apple.private.security.storage.MobileDocuments</key>
<true/>
<key>com.apple.private.security.storage-exempt.heritable</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.allowed</key>
<true/>
<key>com.apple.private.uninstall.deletion</key>
<true/>
<key>com.apple.springboard.launchapplications</key>
<true/>
<key>com.apple.backboardd.launchapplications</key>
<true/>
<key>com.apple.frontboard.launchapplications</key>
<true/>
<key>com.apple.multitasking.termination</key>
<true/>
<key>com.apple.private.mobileinstall.allowedSPI</key>
<array>
<string>InstallForLaunchServices</string>
<string>Install</string>
<string>UninstallForLaunchServices</string>
<string>Uninstall</string>
<string>UpdatePlaceholderMetadata</string>
</array>
</dict>
</plist>

View File

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

View File

@ -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;
}

View File

@ -178,7 +178,7 @@ UIImage* imageWithSize(UIImage* image, CGSize size)
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
{
NSString* pathToIPA = urls.firstObject.path;
[TSInstallationController presentInstallationAlertForFile:pathToIPA completion:nil];
[TSInstallationController presentInstallationAlertIfEnabledForFile:pathToIPA isRemoteInstall:NO completion:nil];
}
- (void)openAppPressedForRowAtIndexPath:(NSIndexPath*)indexPath

View File

@ -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}];

View File

@ -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;

View File

@ -5,6 +5,8 @@
#import <TSUtil.h>
#import <TSPresentationDelegate.h>
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);

View File

@ -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);
}];
}

View File

@ -1,8 +1,14 @@
#import "TSSettingsListController.h"
#import <TSUtil.h>
#import <Preferences/PSSpecifier.h>
#import <Preferences/PSListItemsController.h>
#import <TSPresentationDelegate.h>
@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=<IPA_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

View File

@ -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

View File

@ -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();