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
|
Package: com.opa334.trollstoreroothelper
|
||||||
Name: trollstoreroothelper
|
Name: trollstoreroothelper
|
||||||
Version: 1.3.5
|
Version: 1.4
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: An awesome tool of some sort!!
|
Description: An awesome tool of some sort!!
|
||||||
Maintainer: opa334
|
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">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
@ -5,12 +6,12 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.private.security.container-required</key>
|
<key>com.apple.private.security.container-required</key>
|
||||||
<false/>
|
<false/>
|
||||||
<key>com.apple.security.exception.files.absolute-path.read-write</key>
|
<key>com.apple.private.security.no-sandbox</key>
|
||||||
<array>
|
<true/>
|
||||||
<string>/</string>
|
|
||||||
</array>
|
|
||||||
<key>com.apple.private.security.container-manager</key>
|
<key>com.apple.private.security.container-manager</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.private.MobileContainerManager.allowed</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.private.coreservices.canmaplsdatabase</key>
|
<key>com.apple.private.coreservices.canmaplsdatabase</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
|
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
|
||||||
|
@ -19,7 +20,7 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.private.security.storage.MobileDocuments</key>
|
<key>com.apple.private.security.storage.MobileDocuments</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.private.MobileContainerManager.allowed</key>
|
<key>com.apple.private.security.storage-exempt.heritable</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled</key>
|
<key>com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
@ -27,9 +28,21 @@
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.private.uninstall.deletion</key>
|
<key>com.apple.private.uninstall.deletion</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.springboard.launchapplications</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.backboardd.launchapplications</key>
|
<key>com.apple.backboardd.launchapplications</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.frontboard.launchapplications</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.multitasking.termination</key>
|
<key>com.apple.multitasking.termination</key>
|
||||||
<true/>
|
<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>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|
|
@ -55,7 +55,13 @@ NSSet<NSString*>* appleURLSchemes(void)
|
||||||
LSApplicationProxy* proxy;
|
LSApplicationProxy* proxy;
|
||||||
while(proxy = [enumerator nextObject])
|
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;
|
return systemURLSchemes.copy;
|
||||||
|
@ -83,22 +89,26 @@ NSSet<NSString*>* immutableAppBundleIdentifiers(void)
|
||||||
|
|
||||||
NSDictionary* infoDictionaryForAppPath(NSString* appPath)
|
NSDictionary* infoDictionaryForAppPath(NSString* appPath)
|
||||||
{
|
{
|
||||||
|
if(!appPath) return nil;
|
||||||
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"];
|
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"];
|
||||||
return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
|
return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* appIdForAppPath(NSString* appPath)
|
NSString* appIdForAppPath(NSString* appPath)
|
||||||
{
|
{
|
||||||
|
if(!appPath) return nil;
|
||||||
return infoDictionaryForAppPath(appPath)[@"CFBundleIdentifier"];
|
return infoDictionaryForAppPath(appPath)[@"CFBundleIdentifier"];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* appMainExecutablePathForAppPath(NSString* appPath)
|
NSString* appMainExecutablePathForAppPath(NSString* appPath)
|
||||||
{
|
{
|
||||||
|
if(!appPath) return nil;
|
||||||
return [appPath stringByAppendingPathComponent:infoDictionaryForAppPath(appPath)[@"CFBundleExecutable"]];
|
return [appPath stringByAppendingPathComponent:infoDictionaryForAppPath(appPath)[@"CFBundleExecutable"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* appPathForAppId(NSString* appId)
|
NSString* appPathForAppId(NSString* appId)
|
||||||
{
|
{
|
||||||
|
if(!appId) return nil;
|
||||||
for(NSString* appPath in trollStoreInstalledAppBundlePaths())
|
for(NSString* appPath in trollStoreInstalledAppBundlePaths())
|
||||||
{
|
{
|
||||||
if([appIdForAppPath(appPath) isEqualToString:appId])
|
if([appIdForAppPath(appPath) isEqualToString:appId])
|
||||||
|
@ -111,7 +121,7 @@ NSString* appPathForAppId(NSString* appId)
|
||||||
|
|
||||||
BOOL isMachoFile(NSString* filePath)
|
BOOL isMachoFile(NSString* filePath)
|
||||||
{
|
{
|
||||||
FILE* file = fopen(filePath.UTF8String, "r");
|
FILE* file = fopen(filePath.fileSystemRepresentation, "r");
|
||||||
if(!file) return NO;
|
if(!file) return NO;
|
||||||
|
|
||||||
fseek(file, 0, SEEK_SET);
|
fseek(file, 0, SEEK_SET);
|
||||||
|
@ -130,8 +140,8 @@ void fixPermissionsOfAppBundle(NSString* appBundlePath)
|
||||||
while(fileURL = [enumerator nextObject])
|
while(fileURL = [enumerator nextObject])
|
||||||
{
|
{
|
||||||
NSString* filePath = fileURL.path;
|
NSString* filePath = fileURL.path;
|
||||||
chown(filePath.UTF8String, 33, 33);
|
chown(filePath.fileSystemRepresentation, 33, 33);
|
||||||
chmod(filePath.UTF8String, 0644);
|
chmod(filePath.fileSystemRepresentation, 0644);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply correct permissions (Second run, set executables and directories to 0755)
|
// Apply correct permissions (Second run, set executables and directories to 0755)
|
||||||
|
@ -145,15 +155,53 @@ void fixPermissionsOfAppBundle(NSString* appBundlePath)
|
||||||
|
|
||||||
if(isDir || isMachoFile(filePath))
|
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)
|
void installLdid(NSString* ldidToCopyPath)
|
||||||
{
|
{
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidToCopyPath]) return;
|
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidToCopyPath]) return;
|
||||||
|
@ -166,8 +214,8 @@ void installLdid(NSString* ldidToCopyPath)
|
||||||
|
|
||||||
[[NSFileManager defaultManager] copyItemAtPath:ldidToCopyPath toPath:ldidPath error:nil];
|
[[NSFileManager defaultManager] copyItemAtPath:ldidToCopyPath toPath:ldidPath error:nil];
|
||||||
|
|
||||||
chmod(ldidPath.UTF8String, 0755);
|
chmod(ldidPath.fileSystemRepresentation, 0755);
|
||||||
chown(ldidPath.UTF8String, 0, 0);
|
chown(ldidPath.fileSystemRepresentation, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL isLdidInstalled(void)
|
BOOL isLdidInstalled(void)
|
||||||
|
@ -206,7 +254,7 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput)
|
||||||
|
|
||||||
pid_t task_pid;
|
pid_t task_pid;
|
||||||
int status = -200;
|
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++)
|
for (NSUInteger i = 0; i < argCount; i++)
|
||||||
{
|
{
|
||||||
free(argsC[i]);
|
free(argsC[i]);
|
||||||
|
@ -500,7 +548,19 @@ void applyPatchesToInfoDictionary(NSString* appPath)
|
||||||
if(URLSchemes)
|
if(URLSchemes)
|
||||||
{
|
{
|
||||||
NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray: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];
|
modifiedURLType[@"CFBundleURLSchemes"] = [URLSchemesSet allObjects];
|
||||||
}
|
}
|
||||||
[CFBundleURLTypesM addObject:modifiedURLType.copy];
|
[CFBundleURLTypesM addObject:modifiedURLType.copy];
|
||||||
|
@ -517,172 +577,153 @@ void applyPatchesToInfoDictionary(NSString* appPath)
|
||||||
// 172: no info.plist found in app
|
// 172: no info.plist found in app
|
||||||
// 173: app is not signed and cannot be signed because ldid not installed or didn't work
|
// 173: app is not signed and cannot be signed because ldid not installed or didn't work
|
||||||
// 174:
|
// 174:
|
||||||
int installApp(NSString* appPath, BOOL sign, BOOL force)
|
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate)
|
||||||
{
|
{
|
||||||
NSLog(@"[installApp force = %d]", force);
|
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(!appId) return 176;
|
||||||
if([immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
|
|
||||||
|
if(([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"] && !isTSUpdate) || [immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
|
||||||
{
|
{
|
||||||
return 179;
|
return 179;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(![appId isEqualToString:@"com.opa334.TrollStore"])
|
if(!infoDictionaryForAppPath(appBundlePath)) return 172;
|
||||||
|
|
||||||
|
if(!isTSUpdate)
|
||||||
{
|
{
|
||||||
applyPatchesToInfoDictionary(appPath);
|
applyPatchesToInfoDictionary(appBundlePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(sign)
|
if(sign)
|
||||||
{
|
{
|
||||||
int signRet = signApp(appPath);
|
int signRet = signApp(appBundlePath);
|
||||||
if(signRet != 0) return signRet;
|
if(signRet != 0) return signRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL existed;
|
LSApplicationProxy* existingAppProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
|
||||||
NSError* mcmError;
|
if(existingAppProxy.installed)
|
||||||
MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError];
|
|
||||||
if(!appContainer || mcmError)
|
|
||||||
{
|
{
|
||||||
NSLog(@"[installApp] failed to create app container for %@: %@", appId, mcmError);
|
// App update
|
||||||
return 170;
|
// Replace existing bundle with new version
|
||||||
}
|
|
||||||
|
|
||||||
if(existed)
|
// Check if the existing app bundle is empty
|
||||||
{
|
BOOL appBundleExists = existingAppProxy.bundleURL && [existingAppProxy.bundleURL checkResourceIsReachableAndReturnError:nil];
|
||||||
NSLog(@"[installApp] got existing app container: %@", appContainer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NSLog(@"[installApp] created app container: %@", appContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the bundle is empty
|
// LSBundleProxy also has a bundleContainerURL property, but unforunately it is unreliable and just nil most of the time
|
||||||
BOOL isEmpty = YES;
|
NSURL* bundleContainerURL = existingAppProxy.bundleURL.URLByDeletingLastPathComponent;
|
||||||
NSArray* bundleItems = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appContainer.url.path error:nil];
|
|
||||||
for(NSString* bundleItem in bundleItems)
|
|
||||||
{
|
|
||||||
if([bundleItem.pathExtension isEqualToString:@"app"])
|
|
||||||
{
|
|
||||||
isEmpty = NO;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NSLog(@"[installApp] container is empty? %d", isEmpty);
|
// 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"];
|
||||||
// Make sure there isn't already an app store app installed with the same identifier
|
if(appBundleExists && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force)
|
||||||
NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"];
|
|
||||||
if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force)
|
|
||||||
{
|
{
|
||||||
NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
|
NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
|
||||||
return 171;
|
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
|
// 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];
|
BOOL marked = [[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil];
|
||||||
if(!marked)
|
if(!marked)
|
||||||
{
|
{
|
||||||
NSLog(@"[installApp] failed to mark %@ as TrollStore app", appId);
|
NSLog(@"[installApp] failed to mark %@ as TrollStore app", appId);
|
||||||
return 177;
|
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");
|
// At this point the (new version of the) app is installed but still needs to be registered
|
||||||
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
|
// Also permissions need to be fixed
|
||||||
NSURL* fileURL;
|
fixPermissionsOfAppBundle(existingAppProxy.bundleURL.path);
|
||||||
while(fileURL = [enumerator nextObject])
|
registerPath((char*)existingAppProxy.bundleURL.path.fileSystemRepresentation, 0, YES);
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int uninstallApp(NSString* appPath, NSString* appId)
|
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)
|
if(appId)
|
||||||
{
|
{
|
||||||
BKSTerminateApplicationForReasonAndReportWithDescription(appId, 5, false, @"TrollStore - App uninstalled");
|
deleteSuc = [[LSApplicationWorkspace defaultWorkspace] uninstallApplication:appId withOptions:nil];
|
||||||
|
|
||||||
LSApplicationProxy* appProxy = [LSApplicationProxy applicationProxyForIdentifier:appId];
|
|
||||||
MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
|
|
||||||
NSString *containerPath = [appContainer url].path;
|
|
||||||
if(containerPath)
|
|
||||||
{
|
|
||||||
NSLog(@"[uninstallApp] deleting %@", containerPath);
|
|
||||||
// delete app container path
|
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:containerPath error:nil];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete group container paths
|
|
||||||
[[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupId, NSURL* groupURL, BOOL* stop)
|
|
||||||
{
|
|
||||||
// If another app still has this group, don't delete it
|
|
||||||
NSArray<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)
|
if(deleteSuc)
|
||||||
{
|
{
|
||||||
return 0;
|
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)
|
int uninstallAppByPath(NSString* appPath)
|
||||||
{
|
{
|
||||||
if(!appPath) return 1;
|
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);
|
return uninstallApp(appPath, appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -741,38 +765,21 @@ int installIpa(NSString* ipaPath, BOOL force)
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166;
|
if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166;
|
||||||
|
|
||||||
BOOL suc = NO;
|
BOOL suc = NO;
|
||||||
NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
NSString* 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;
|
if(!suc) return 1;
|
||||||
|
|
||||||
extract(ipaPath, tmpPath);
|
int extractRet = extract(ipaPath, tmpPackagePath);
|
||||||
|
if(extractRet != 0)
|
||||||
NSString* tmpPayloadPath = [tmpPath stringByAppendingPathComponent:@"Payload"];
|
|
||||||
|
|
||||||
NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpPayloadPath error:nil];
|
|
||||||
if(!items) return 167;
|
|
||||||
|
|
||||||
NSString* tmpAppPath;
|
|
||||||
for(NSString* item in items)
|
|
||||||
{
|
{
|
||||||
if([item.pathExtension isEqualToString:@"app"])
|
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
||||||
{
|
return 168;
|
||||||
tmpAppPath = [tmpPayloadPath stringByAppendingPathComponent:item];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!tmpAppPath) return 167;
|
|
||||||
|
|
||||||
NSString* appId = appIdForAppPath(tmpAppPath);
|
|
||||||
if([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"])
|
|
||||||
{
|
|
||||||
return 179;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -785,78 +792,85 @@ void uninstallAllApps(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL uninstallTrollStore(BOOL unregister)
|
int uninstallTrollStore(BOOL unregister)
|
||||||
{
|
{
|
||||||
NSString* trollStore = trollStorePath();
|
NSString* trollStore = trollStorePath();
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:trollStore]) return NO;
|
if(![[NSFileManager defaultManager] fileExistsAtPath:trollStore]) return NO;
|
||||||
|
|
||||||
if(unregister)
|
if(unregister)
|
||||||
{
|
{
|
||||||
registerPath((char*)trollStoreAppPath().UTF8String, 1, YES);
|
registerPath((char*)trollStoreAppPath().fileSystemRepresentation, 1, YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [[NSFileManager defaultManager] removeItemAtPath:trollStore error:nil];
|
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");
|
_CFPreferencesSetValueWithContainerType _CFPreferencesSetValueWithContainer = (_CFPreferencesSetValueWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesSetValueWithContainer");
|
||||||
_CFPreferencesSynchronizeWithContainerType _CFPreferencesSynchronizeWithContainer = (_CFPreferencesSynchronizeWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesSynchronizeWithContainer");
|
_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);
|
_CFPreferencesSetValueWithContainer(CFSTR("SBShowNonDefaultSystemApps"), kCFBooleanTrue, CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
|
||||||
_CFPreferencesSynchronizeWithContainer(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(![[NSFileManager defaultManager] fileExistsAtPath:pathToTar]) return 1;
|
||||||
if(![pathToTar.pathExtension isEqualToString:@"tar"]) return 1;
|
if(![pathToTar.pathExtension isEqualToString:@"tar"]) return 1;
|
||||||
|
|
||||||
NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
NSString* tmpPackagePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
||||||
BOOL suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:nil];
|
NSString* tmpPayloadPath = [tmpPackagePath stringByAppendingPathComponent:@"Payload"];
|
||||||
|
BOOL suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPayloadPath withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
if(!suc) return 1;
|
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"];
|
NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStore]) return 1;
|
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;
|
||||||
|
|
||||||
// Save existing ldid installation if it exists
|
// Save existing ldid installation if it exists
|
||||||
NSString* existingLdidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
|
NSString* existingLdidPath = [trollStoreAppPath() stringByAppendingPathComponent:@"ldid"];
|
||||||
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidPath])
|
if([[NSFileManager defaultManager] fileExistsAtPath:existingLdidPath])
|
||||||
{
|
{
|
||||||
NSString* tmpLdidPath = [tmpTrollStore stringByAppendingPathComponent:@"ldid"];
|
NSString* tmpLdidPath = [tmpTrollStorePath stringByAppendingPathComponent:@"ldid"];
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidPath])
|
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpLdidPath])
|
||||||
{
|
{
|
||||||
[[NSFileManager defaultManager] copyItemAtPath:existingLdidPath toPath:tmpLdidPath error:nil];
|
[[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
|
// Update system app persistence helper if used
|
||||||
LSApplicationProxy* persistenceHelperApp = findPersistenceHelperApp(PERSISTENCE_HELPER_TYPE_SYSTEM);
|
LSApplicationProxy* persistenceHelperApp = findPersistenceHelperApp(PERSISTENCE_HELPER_TYPE_SYSTEM);
|
||||||
if(persistenceHelperApp)
|
if(persistenceHelperApp)
|
||||||
{
|
{
|
||||||
NSString* trollStorePersistenceHelper = [tmpTrollStore stringByAppendingPathComponent:@"PersistenceHelper"];
|
NSString* trollStorePersistenceHelper = [tmpTrollStorePath stringByAppendingPathComponent:@"PersistenceHelper"];
|
||||||
NSString* trollStoreRootHelper = [tmpTrollStore stringByAppendingPathComponent:@"trollstorehelper"];
|
NSString* trollStoreRootHelper = [tmpTrollStorePath stringByAppendingPathComponent:@"trollstorehelper"];
|
||||||
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
|
_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()
|
void refreshAppRegistrations()
|
||||||
{
|
{
|
||||||
//registerPath((char*)trollStoreAppPath().UTF8String, 1, YES);
|
//registerPath((char*)trollStoreAppPath().fileSystemRepresentation, 1, YES);
|
||||||
registerPath((char*)trollStoreAppPath().UTF8String, 0, YES);
|
registerPath((char*)trollStoreAppPath().fileSystemRepresentation, 0, YES);
|
||||||
|
|
||||||
for(NSString* appPath in trollStoreInstalledAppBundlePaths())
|
for(NSString* appPath in trollStoreInstalledAppBundlePaths())
|
||||||
{
|
{
|
||||||
//registerPath((char*)appPath.UTF8String, 1, YES);
|
//registerPath((char*)appPath.fileSystemRepresentation, 1, YES);
|
||||||
registerPath((char*)appPath.UTF8String, 0, YES);
|
registerPath((char*)appPath.fileSystemRepresentation, 0, YES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,8 +907,8 @@ BOOL _installPersistenceHelper(LSApplicationProxy* appProxy, NSString* sourcePer
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
chmod(executablePath.UTF8String, 0755);
|
chmod(executablePath.fileSystemRepresentation, 0755);
|
||||||
chown(executablePath.UTF8String, 33, 33);
|
chown(executablePath.fileSystemRepresentation, 33, 33);
|
||||||
|
|
||||||
NSError* error;
|
NSError* error;
|
||||||
if(![[NSFileManager defaultManager] copyItemAtPath:sourceRootHelper toPath:rootHelperPath error:&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);
|
NSLog(@"error copying root helper: %@", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
chmod(rootHelperPath.UTF8String, 0755);
|
chmod(rootHelperPath.fileSystemRepresentation, 0755);
|
||||||
chown(rootHelperPath.UTF8String, 0, 0);
|
chown(rootHelperPath.fileSystemRepresentation, 0, 0);
|
||||||
|
|
||||||
// mark system app as persistence helper
|
// mark system app as persistence helper
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:markPath])
|
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());
|
NSLog(@"trollstore helper go, uid: %d, gid: %d", getuid(), getgid());
|
||||||
|
|
||||||
loadMCMFramework();
|
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
NSString* cmd = [NSString stringWithUTF8String:argv[1]];
|
NSString* cmd = [NSString stringWithUTF8String:argv[1]];
|
||||||
|
@ -1073,12 +1085,7 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
|
||||||
if(argc <= 2) return -3;
|
if(argc <= 2) return -3;
|
||||||
NSString* appId = [NSString stringWithUTF8String:argv[2]];
|
NSString* appId = [NSString stringWithUTF8String:argv[2]];
|
||||||
ret = uninstallAppById(appId);
|
ret = uninstallAppById(appId);
|
||||||
} /*else if([cmd isEqualToString:@"detach"])
|
} else if([cmd isEqualToString:@"uninstall-path"])
|
||||||
{
|
|
||||||
if(argc <= 2) return -3;
|
|
||||||
NSString* appId = [NSString stringWithUTF8String:argv[2]];
|
|
||||||
ret = detachApp(appId);
|
|
||||||
} */else if([cmd isEqualToString:@"uninstall-path"])
|
|
||||||
{
|
{
|
||||||
if(argc <= 2) return -3;
|
if(argc <= 2) return -3;
|
||||||
NSString* appPath = [NSString stringWithUTF8String:argv[2]];
|
NSString* appPath = [NSString stringWithUTF8String:argv[2]];
|
||||||
|
@ -1093,7 +1100,10 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
|
||||||
{
|
{
|
||||||
uninstallAllApps();
|
uninstallAllApps();
|
||||||
uninstallTrollStore(YES);
|
uninstallTrollStore(YES);
|
||||||
} else if([cmd isEqualToString:@"install-ldid"])
|
} else if([cmd isEqualToString:@"uninstall-trollstore-preserve-apps"])
|
||||||
|
{
|
||||||
|
uninstallTrollStore(YES);
|
||||||
|
}else if([cmd isEqualToString:@"install-ldid"])
|
||||||
{
|
{
|
||||||
if(argc <= 2) return -3;
|
if(argc <= 2) return -3;
|
||||||
NSString* ldidPath = [NSString stringWithUTF8String:argv[2]];
|
NSString* ldidPath = [NSString stringWithUTF8String:argv[2]];
|
||||||
|
@ -1129,7 +1139,16 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
|
||||||
NSString* trollStoreMark = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"];
|
NSString* trollStoreMark = [[appPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"_TrollStore"];
|
||||||
if([[NSFileManager defaultManager] fileExistsAtPath:trollStoreMark])
|
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();
|
ext = archive_write_disk_new();
|
||||||
archive_write_disk_set_options(ext, flags);
|
archive_write_disk_set_options(ext, flags);
|
||||||
archive_write_disk_set_standard_lookup(ext);
|
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;
|
return 1;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -59,8 +59,8 @@ int extract(NSString* fileToExtract, NSString* extractionPath)
|
||||||
|
|
||||||
NSString* currentFile = [NSString stringWithUTF8String:archive_entry_pathname(entry)];
|
NSString* currentFile = [NSString stringWithUTF8String:archive_entry_pathname(entry)];
|
||||||
NSString* fullOutputPath = [extractionPath stringByAppendingPathComponent:currentFile];
|
NSString* fullOutputPath = [extractionPath stringByAppendingPathComponent:currentFile];
|
||||||
//printf("extracting %s to %s\n", currentFile.UTF8String, fullOutputPath.UTF8String);
|
//printf("extracting %@ to %@\n", currentFile, fullOutputPath);
|
||||||
archive_entry_set_pathname(entry, fullOutputPath.UTF8String);
|
archive_entry_set_pathname(entry, fullOutputPath.fileSystemRepresentation);
|
||||||
|
|
||||||
r = archive_write_header(ext, entry);
|
r = archive_write_header(ext, entry);
|
||||||
if (r < ARCHIVE_OK)
|
if (r < ARCHIVE_OK)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
extern NSString *LSInstallTypeKey;
|
||||||
|
|
||||||
@interface LSBundleProxy
|
@interface LSBundleProxy
|
||||||
@property (nonatomic,readonly) NSString * bundleIdentifier;
|
@property (nonatomic,readonly) NSString * bundleIdentifier;
|
||||||
@property (nonatomic) NSURL* dataContainerURL;
|
@property (nonatomic) NSURL* dataContainerURL;
|
||||||
|
@property (nonatomic,readonly) NSURL* bundleContainerURL;
|
||||||
-(NSString*)localizedName;
|
-(NSString*)localizedName;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -26,7 +29,7 @@
|
||||||
- (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 internal:(BOOL)arg2 user:(BOOL)arg3;
|
- (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 internal:(BOOL)arg2 user:(BOOL)arg3;
|
||||||
- (BOOL)openApplicationWithBundleID:(NSString *)arg1 ;
|
- (BOOL)openApplicationWithBundleID:(NSString *)arg1 ;
|
||||||
- (void)enumerateApplicationsOfType:(NSUInteger)type block:(void (^)(LSApplicationProxy*))block;
|
- (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;
|
- (BOOL)uninstallApplication:(NSString*)appId withOptions:(NSDictionary*)options;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,6 @@
|
||||||
#import <Preferences/PSSpecifier.h>
|
#import <Preferences/PSSpecifier.h>
|
||||||
|
|
||||||
@interface TSListControllerShared : PSListController
|
@interface TSListControllerShared : PSListController
|
||||||
{
|
|
||||||
UIAlertController* _activityController;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)isTrollStore;
|
- (BOOL)isTrollStore;
|
||||||
- (NSString*)getTrollStoreVersion;
|
- (NSString*)getTrollStoreVersion;
|
||||||
- (void)downloadTrollStoreAndDo:(void (^)(NSString* localTrollStoreTarPath))doHandler;
|
- (void)downloadTrollStoreAndDo:(void (^)(NSString* localTrollStoreTarPath))doHandler;
|
||||||
|
|
|
@ -190,19 +190,26 @@
|
||||||
|
|
||||||
- (void)uninstallTrollStorePressed
|
- (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];
|
UIAlertAction* uninstallAllAction = [UIAlertAction actionWithTitle:@"Uninstall TrollStore, Uninstall Apps" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
|
||||||
[uninstallWarningAlert addAction:cancelAction];
|
|
||||||
|
|
||||||
UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
|
|
||||||
{
|
{
|
||||||
spawnRoot(rootHelperPath(), @[@"uninstall-trollstore"], nil, nil);
|
spawnRoot(rootHelperPath(), @[@"uninstall-trollstore"], nil, nil);
|
||||||
[self handleUninstallation];
|
[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
|
@end
|
|
@ -52,7 +52,7 @@
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.3.5</string>
|
<string>1.4</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIDeviceFamily</key>
|
<key>UIDeviceFamily</key>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Package: com.opa334.trollstorehelper
|
Package: com.opa334.trollstorehelper
|
||||||
Name: TrollStore Helper
|
Name: TrollStore Helper
|
||||||
Version: 1.3.5
|
Version: 1.4
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: Helper utility to install and manage TrollStore!
|
Description: Helper utility to install and manage TrollStore!
|
||||||
Maintainer: opa334
|
Maintainer: opa334
|
||||||
|
|
|
@ -3,31 +3,7 @@
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>application-identifier</key>
|
<key>application-identifier</key>
|
||||||
<string>com.opa334.TrollStore</string>
|
<string>com.opa334.trollstorepersistencehelper</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/>
|
|
||||||
<key>com.apple.CommCenter.fine-grained</key>
|
<key>com.apple.CommCenter.fine-grained</key>
|
||||||
<array>
|
<array>
|
||||||
<string>cellular-plan</string>
|
<string>cellular-plan</string>
|
||||||
|
@ -35,11 +11,49 @@
|
||||||
<string>data-allowed-write</string>
|
<string>data-allowed-write</string>
|
||||||
<string>preferences-write</string>
|
<string>preferences-write</string>
|
||||||
</array>
|
</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>
|
<key>com.apple.private.security.storage.AppBundles</key>
|
||||||
<true/>
|
<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>
|
<key>com.apple.backboardd.launchapplications</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>com.apple.frontboard.launchapplications</key>
|
||||||
|
<true/>
|
||||||
<key>com.apple.multitasking.termination</key>
|
<key>com.apple.multitasking.termination</key>
|
||||||
<true/>
|
<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>
|
</dict>
|
||||||
</plist>
|
</plist>
|
|
@ -50,7 +50,7 @@
|
||||||
<string>iPhoneOS</string>
|
<string>iPhoneOS</string>
|
||||||
</array>
|
</array>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.3.5</string>
|
<string>1.4</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIDeviceFamily</key>
|
<key>UIDeviceFamily</key>
|
||||||
|
|
|
@ -366,7 +366,7 @@ extern UIImage* imageWithSize(UIImage* image, CGSize size);
|
||||||
_archive = archive_read_new();
|
_archive = archive_read_new();
|
||||||
archive_read_support_format_all(_archive);
|
archive_read_support_format_all(_archive);
|
||||||
archive_read_support_filter_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;
|
return r ? r : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ UIImage* imageWithSize(UIImage* image, CGSize size)
|
||||||
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
|
- (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentsAtURLs:(NSArray<NSURL *> *)urls
|
||||||
{
|
{
|
||||||
NSString* pathToIPA = urls.firstObject.path;
|
NSString* pathToIPA = urls.firstObject.path;
|
||||||
[TSInstallationController presentInstallationAlertForFile:pathToIPA completion:nil];
|
[TSInstallationController presentInstallationAlertIfEnabledForFile:pathToIPA isRemoteInstall:NO completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)openAppPressedForRowAtIndexPath:(NSIndexPath*)indexPath
|
- (void)openAppPressedForRowAtIndexPath:(NSIndexPath*)indexPath
|
||||||
|
|
|
@ -30,6 +30,12 @@
|
||||||
case 167:
|
case 167:
|
||||||
errorDescription = @"The IPA file does not appear to contain an app.";
|
errorDescription = @"The IPA file does not appear to contain an app.";
|
||||||
break;
|
break;
|
||||||
|
case 168:
|
||||||
|
errorDescription = @"Failed to extract IPA file.";
|
||||||
|
break;
|
||||||
|
case 169:
|
||||||
|
errorDescription = @"Failed to extract update tar file.";
|
||||||
|
break;
|
||||||
// App install errors
|
// App install errors
|
||||||
case 170:
|
case 170:
|
||||||
errorDescription = @"Failed to create container for app bundle.";
|
errorDescription = @"Failed to create container for app bundle.";
|
||||||
|
@ -61,10 +67,9 @@
|
||||||
case 179:
|
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.";
|
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;
|
break;
|
||||||
// App detach errors
|
case 180:
|
||||||
/*case 184:
|
errorDescription = @"The LSApplicationWorkspace app installation failed.";
|
||||||
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;
|
||||||
break;*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
|
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
@interface TSInstallationController : NSObject
|
@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 forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completion;
|
||||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion;
|
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion;
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#import <TSUtil.h>
|
#import <TSUtil.h>
|
||||||
#import <TSPresentationDelegate.h>
|
#import <TSPresentationDelegate.h>
|
||||||
|
|
||||||
|
extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||||
|
|
||||||
@implementation TSInstallationController
|
@implementation TSInstallationController
|
||||||
|
|
||||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA forceInstall:(BOOL)force completion:(void (^)(BOOL, NSError*))completionBlock
|
+ (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];
|
TSAppInfo* appInfo = [[TSAppInfo alloc] initWithIPAPath:pathToIPA];
|
||||||
[appInfo loadInfoWithCompletion:^(NSError* error)
|
[appInfo loadInfoWithCompletion:^(NSError* error)
|
||||||
{
|
{
|
||||||
|
@ -144,7 +168,7 @@
|
||||||
NSString* tmpIpaPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.ipa"];
|
NSString* tmpIpaPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"tmp.ipa"];
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil];
|
||||||
[[NSFileManager defaultManager] moveItemAtPath:location.path toPath: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];
|
[[NSFileManager defaultManager] removeItemAtPath:tmpIpaPath error:nil];
|
||||||
if(completionBlock) completionBlock(success, error);
|
if(completionBlock) completionBlock(success, error);
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
if ([url.pathExtension.lowercaseString isEqualToString:@"ipa"] || [url.pathExtension.lowercaseString isEqualToString:@"tipa"])
|
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);
|
doneBlock(NO);
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
#import "TSSettingsListController.h"
|
#import "TSSettingsListController.h"
|
||||||
#import <TSUtil.h>
|
#import <TSUtil.h>
|
||||||
#import <Preferences/PSSpecifier.h>
|
#import <Preferences/PSSpecifier.h>
|
||||||
|
#import <Preferences/PSListItemsController.h>
|
||||||
#import <TSPresentationDelegate.h>
|
#import <TSPresentationDelegate.h>
|
||||||
|
|
||||||
|
@interface NSUserDefaults (Private)
|
||||||
|
- (instancetype)_initWithSuiteName:(NSString *)suiteName container:(NSURL *)container;
|
||||||
|
@end
|
||||||
|
extern NSUserDefaults* trollStoreUserDefaults(void);
|
||||||
|
|
||||||
@implementation TSSettingsListController
|
@implementation TSSettingsListController
|
||||||
|
|
||||||
- (void)viewDidLoad
|
- (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];
|
PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
|
||||||
[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", [self getTrollStoreVersion]] forKey:@"footerText"];
|
[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@lunotech11, @SerenaKit, @tylinux: Various contributions\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", [self getTrollStoreVersion]] forKey:@"footerText"];
|
||||||
[_specifiers addObject:otherGroupSpecifier];
|
[_specifiers addObject:otherGroupSpecifier];
|
||||||
|
@ -230,6 +270,16 @@
|
||||||
return _specifiers;
|
return _specifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray*)installationConfirmationValues
|
||||||
|
{
|
||||||
|
return @[@0, @1, @2];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray*)installationConfirmationNames
|
||||||
|
{
|
||||||
|
return @[@"Always (Recommended)", @"Only on Remote Installs", @"Never (Not Recommeded)"];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)respringButtonPressed
|
- (void)respringButtonPressed
|
||||||
{
|
{
|
||||||
respring();
|
respring();
|
||||||
|
@ -313,9 +363,51 @@
|
||||||
[TSPresentationDelegate presentViewController:selectAppAlert animated:YES completion:nil];
|
[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
|
- (void)doTheDashPressed
|
||||||
{
|
{
|
||||||
spawnRoot(rootHelperPath(), @[@"dash"], nil, nil);
|
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
|
@end
|
|
@ -1,6 +1,6 @@
|
||||||
Package: com.opa334.trollstore
|
Package: com.opa334.trollstore
|
||||||
Name: TrollStore
|
Name: TrollStore
|
||||||
Version: 1.3.5
|
Version: 1.4
|
||||||
Architecture: iphoneos-arm
|
Architecture: iphoneos-arm
|
||||||
Description: An awesome application!
|
Description: An awesome application!
|
||||||
Maintainer: opa334
|
Maintainer: opa334
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
#import "TSAppDelegate.h"
|
#import "TSAppDelegate.h"
|
||||||
#import "TSUtil.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[]) {
|
int main(int argc, char *argv[]) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
chineseWifiFixup();
|
chineseWifiFixup();
|
||||||
|
|
Loading…
Reference in New Issue