mirror of https://github.com/opa334/TrollStore.git
1.4
This commit is contained in:
parent
2d762b39ef
commit
7f34ae76a6
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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:©Error];
|
||||
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:©Error];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -3,10 +3,6 @@
|
|||
#import <Preferences/PSSpecifier.h>
|
||||
|
||||
@interface TSListControllerShared : PSListController
|
||||
{
|
||||
UIAlertController* _activityController;
|
||||
}
|
||||
|
||||
- (BOOL)isTrollStore;
|
||||
- (NSString*)getTrollStoreVersion;
|
||||
- (void)downloadTrollStoreAndDo:(void (^)(NSString* localTrollStoreTarPath))doHandler;
|
||||
|
|
|
@ -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
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue