mirror of
https://github.com/opa334/TrollStore.git
synced 2026-02-22 12:12:24 +08:00
Merge 48ba54ca67 into d11c04666a
This commit is contained in:
commit
d16ac30312
@ -807,7 +807,13 @@ int signApp(NSString* appPath)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void applyPatchesToInfoDictionary(NSString* appPath)
|
NSString* randomStealthBundleIdentifierSuffix(void)
|
||||||
|
{
|
||||||
|
uint64_t randomValue = ((uint64_t)arc4random() << 32) | arc4random();
|
||||||
|
return [NSString stringWithFormat:@"TS_%016llX", randomValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyPatchesToInfoDictionary(NSString* appPath, BOOL stealthInstall, BOOL stripURLSchemesInStealth)
|
||||||
{
|
{
|
||||||
NSURL* appURL = [NSURL fileURLWithPath:appPath];
|
NSURL* appURL = [NSURL fileURLWithPath:appPath];
|
||||||
NSURL* infoPlistURL = [appURL URLByAppendingPathComponent:@"Info.plist"];
|
NSURL* infoPlistURL = [appURL URLByAppendingPathComponent:@"Info.plist"];
|
||||||
@ -817,41 +823,84 @@ void applyPatchesToInfoDictionary(NSString* appPath)
|
|||||||
// Enable Notifications
|
// Enable Notifications
|
||||||
infoDictM[@"SBAppUsesLocalNotifications"] = @1;
|
infoDictM[@"SBAppUsesLocalNotifications"] = @1;
|
||||||
|
|
||||||
// Remove system claimed URL schemes if existant
|
if(stealthInstall)
|
||||||
NSSet* appleSchemes = systemURLSchemes();
|
|
||||||
NSArray* CFBundleURLTypes = infoDictM[@"CFBundleURLTypes"];
|
|
||||||
if([CFBundleURLTypes isKindOfClass:[NSArray class]])
|
|
||||||
{
|
{
|
||||||
NSMutableArray* CFBundleURLTypesM = [NSMutableArray new];
|
NSString* originalAppId = infoDictM[@"TSOriginalBundleIdentifier"];
|
||||||
|
if(![originalAppId isKindOfClass:NSString.class] || originalAppId.length == 0)
|
||||||
for(NSDictionary* URLType in CFBundleURLTypes)
|
|
||||||
{
|
{
|
||||||
if(![URLType isKindOfClass:[NSDictionary class]]) continue;
|
originalAppId = infoDictM[@"CFBundleIdentifier"];
|
||||||
|
|
||||||
NSMutableDictionary* modifiedURLType = URLType.mutableCopy;
|
|
||||||
NSArray* URLSchemes = URLType[@"CFBundleURLSchemes"];
|
|
||||||
if(URLSchemes)
|
|
||||||
{
|
|
||||||
NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray:URLSchemes];
|
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
infoDictM[@"CFBundleURLTypes"] = CFBundleURLTypesM.copy;
|
if([originalAppId isKindOfClass:NSString.class] && originalAppId.length > 0)
|
||||||
|
{
|
||||||
|
NSString* stealthAppIdToUse = installedStealthAppIdForOriginalAppId(originalAppId);
|
||||||
|
if(!stealthAppIdToUse)
|
||||||
|
{
|
||||||
|
NSString* currentAppId = infoDictM[@"CFBundleIdentifier"];
|
||||||
|
NSString* currentOriginalAppId = infoDictM[@"TSOriginalBundleIdentifier"];
|
||||||
|
BOOL hasExistingStealthIdInInfoPlist = [currentAppId isKindOfClass:NSString.class] &&
|
||||||
|
currentAppId.length > 0 &&
|
||||||
|
![currentAppId isEqualToString:originalAppId] &&
|
||||||
|
[currentOriginalAppId isKindOfClass:NSString.class] &&
|
||||||
|
[currentOriginalAppId isEqualToString:originalAppId];
|
||||||
|
if(hasExistingStealthIdInInfoPlist)
|
||||||
|
{
|
||||||
|
stealthAppIdToUse = currentAppId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stealthAppIdToUse = [originalAppId stringByAppendingFormat:@".%@", randomStealthBundleIdentifierSuffix()];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
infoDictM[@"TSOriginalBundleIdentifier"] = originalAppId;
|
||||||
|
infoDictM[@"CFBundleIdentifier"] = stealthAppIdToUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(stripURLSchemesInStealth)
|
||||||
|
{
|
||||||
|
// Strip URL schemes in stealth mode.
|
||||||
|
[infoDictM removeObjectForKey:@"CFBundleURLTypes"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remove system claimed URL schemes if existant
|
||||||
|
NSSet* appleSchemes = systemURLSchemes();
|
||||||
|
NSArray* CFBundleURLTypes = infoDictM[@"CFBundleURLTypes"];
|
||||||
|
if([CFBundleURLTypes isKindOfClass:[NSArray class]])
|
||||||
|
{
|
||||||
|
NSMutableArray* CFBundleURLTypesM = [NSMutableArray new];
|
||||||
|
|
||||||
|
for(NSDictionary* URLType in CFBundleURLTypes)
|
||||||
|
{
|
||||||
|
if(![URLType isKindOfClass:[NSDictionary class]]) continue;
|
||||||
|
|
||||||
|
NSMutableDictionary* modifiedURLType = URLType.mutableCopy;
|
||||||
|
NSArray* URLSchemes = URLType[@"CFBundleURLSchemes"];
|
||||||
|
if(URLSchemes)
|
||||||
|
{
|
||||||
|
NSMutableSet* URLSchemesSet = [NSMutableSet setWithArray:URLSchemes];
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
|
infoDictM[@"CFBundleURLTypes"] = CFBundleURLTypesM.copy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[infoDictM writeToURL:infoPlistURL error:nil];
|
[infoDictM writeToURL:infoPlistURL error:nil];
|
||||||
@ -864,29 +913,54 @@ void applyPatchesToInfoDictionary(NSString* appPath)
|
|||||||
// 174:
|
// 174:
|
||||||
// 180: tried to sign app where the main binary is encrypted
|
// 180: tried to sign app where the main binary is encrypted
|
||||||
// 184: tried to sign app where an additional binary is encrypted
|
// 184: tried to sign app where an additional binary is encrypted
|
||||||
|
// 186: stealth/non-stealth install mode conflicts with an existing install
|
||||||
|
|
||||||
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod, BOOL skipUICache)
|
int installApp(NSString* appPackagePath, BOOL sign, BOOL force, BOOL isTSUpdate, BOOL useInstalldMethod, BOOL skipUICache, BOOL stealthInstall, BOOL stripURLSchemesInStealth)
|
||||||
{
|
{
|
||||||
NSLog(@"[installApp force = %d]", force);
|
NSLog(@"[installApp force = %d, stealthInstall = %d]", force, stealthInstall);
|
||||||
|
|
||||||
NSString* appPayloadPath = [appPackagePath stringByAppendingPathComponent:@"Payload"];
|
NSString* appPayloadPath = [appPackagePath stringByAppendingPathComponent:@"Payload"];
|
||||||
|
|
||||||
NSString* appBundleToInstallPath = findAppPathInBundlePath(appPayloadPath);
|
NSString* appBundleToInstallPath = findAppPathInBundlePath(appPayloadPath);
|
||||||
if(!appBundleToInstallPath) return 167;
|
if(!appBundleToInstallPath) return 167;
|
||||||
|
|
||||||
NSString* appId = appIdForAppPath(appBundleToInstallPath);
|
NSDictionary* appInfoDict = infoDictionaryForAppPath(appBundleToInstallPath);
|
||||||
if(!appId) return 176;
|
if(!appInfoDict) return 172;
|
||||||
|
|
||||||
if(([appId.lowercaseString isEqualToString:@"com.opa334.trollstore"] && !isTSUpdate) || [immutableAppBundleIdentifiers() containsObject:appId.lowercaseString])
|
NSString* originalAppId = appInfoDict[@"CFBundleIdentifier"];
|
||||||
|
if(![originalAppId isKindOfClass:NSString.class] || originalAppId.length == 0) return 176;
|
||||||
|
|
||||||
|
NSSet* immutableBundleIds = immutableAppBundleIdentifiers();
|
||||||
|
BOOL isTrollStoreIdentifier = [originalAppId.lowercaseString isEqualToString:@"com.opa334.trollstore"] || [originalAppId.lowercaseString hasPrefix:@"com.opa334.trollstore."];
|
||||||
|
if((isTrollStoreIdentifier && !isTSUpdate) || [immutableBundleIds containsObject:originalAppId.lowercaseString])
|
||||||
{
|
{
|
||||||
return 179;
|
return 179;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!infoDictionaryForAppPath(appBundleToInstallPath)) return 172;
|
|
||||||
|
|
||||||
if(!isTSUpdate)
|
if(!isTSUpdate)
|
||||||
{
|
{
|
||||||
applyPatchesToInfoDictionary(appBundleToInstallPath);
|
NSString* existingStealthAppId = installedStealthAppIdForOriginalAppId(originalAppId);
|
||||||
|
BOOL hasStealthInstall = [existingStealthAppId isKindOfClass:NSString.class] && existingStealthAppId.length > 0;
|
||||||
|
BOOL hasNonStealthInstall = [LSApplicationProxy applicationProxyForIdentifier:originalAppId].installed;
|
||||||
|
|
||||||
|
// Disallow mixing install modes for the same original app identifier.
|
||||||
|
if((stealthInstall && hasNonStealthInstall) || (!stealthInstall && hasStealthInstall))
|
||||||
|
{
|
||||||
|
return 186;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isTSUpdate || stealthInstall)
|
||||||
|
{
|
||||||
|
applyPatchesToInfoDictionary(appBundleToInstallPath, stealthInstall, stripURLSchemesInStealth);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString* appId = appIdForAppPath(appBundleToInstallPath);
|
||||||
|
if(!appId) return 176;
|
||||||
|
|
||||||
|
if([immutableBundleIds containsObject:appId.lowercaseString])
|
||||||
|
{
|
||||||
|
return 179;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL requiresDevMode = NO;
|
BOOL requiresDevMode = NO;
|
||||||
@ -1190,7 +1264,7 @@ int uninstallAppById(NSString* appId, BOOL useCustomMethod)
|
|||||||
// 167: IPA does not appear to contain an app
|
// 167: IPA does not appear to contain an app
|
||||||
// 180: IPA's main binary is encrypted
|
// 180: IPA's main binary is encrypted
|
||||||
// 184: IPA contains additional encrypted binaries
|
// 184: IPA contains additional encrypted binaries
|
||||||
int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod, BOOL skipUICache)
|
int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod, BOOL skipUICache, BOOL stealthInstall)
|
||||||
{
|
{
|
||||||
cleanRestrictions();
|
cleanRestrictions();
|
||||||
|
|
||||||
@ -1209,7 +1283,7 @@ int installIpa(NSString* ipaPath, BOOL force, BOOL useInstalldMethod, BOOL skipU
|
|||||||
return 168;
|
return 168;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = installApp(tmpPackagePath, YES, force, NO, useInstalldMethod, skipUICache);
|
int ret = installApp(tmpPackagePath, YES, force, NO, useInstalldMethod, skipUICache, stealthInstall, YES);
|
||||||
|
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
||||||
|
|
||||||
@ -1261,6 +1335,9 @@ int installTrollStore(NSString* pathToTar)
|
|||||||
|
|
||||||
NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
|
NSString* tmpTrollStorePath = [tmpPayloadPath stringByAppendingPathComponent:@"TrollStore.app"];
|
||||||
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;
|
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStorePath]) return 1;
|
||||||
|
NSString* previousTrollStorePath = trollStorePath();
|
||||||
|
NSString* previousTrollStoreAppPath = trollStoreAppPath();
|
||||||
|
NSString* previousTrollStoreAppId = appIdForAppPath(previousTrollStoreAppPath);
|
||||||
|
|
||||||
//if (@available(iOS 16, *)) {} else {
|
//if (@available(iOS 16, *)) {} else {
|
||||||
// Transfer existing ldid installation if it exists
|
// Transfer existing ldid installation if it exists
|
||||||
@ -1312,8 +1389,21 @@ int installTrollStore(NSString* pathToTar)
|
|||||||
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
|
_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = installApp(tmpPackagePath, NO, YES, YES, YES, NO);
|
int ret = installApp(tmpPackagePath, NO, YES, YES, YES, NO, YES, NO);
|
||||||
NSLog(@"[installTrollStore] installApp => %d", ret);
|
NSLog(@"[installTrollStore] installApp => %d", ret);
|
||||||
|
NSString* targetTrollStoreAppId = (ret == 0) ? appIdForAppPath(tmpTrollStorePath) : nil;
|
||||||
|
if(ret == 0 && previousTrollStorePath && previousTrollStoreAppPath && previousTrollStoreAppId && targetTrollStoreAppId)
|
||||||
|
{
|
||||||
|
BOOL didChangeBundleId = ![previousTrollStoreAppId isEqualToString:targetTrollStoreAppId];
|
||||||
|
MCMAppContainer* targetContainer = [MCMAppContainer containerWithIdentifier:targetTrollStoreAppId createIfNecessary:NO existed:nil error:nil];
|
||||||
|
BOOL sameContainerPath = [previousTrollStorePath isEqualToString:targetContainer.url.path];
|
||||||
|
if(didChangeBundleId && !sameContainerPath)
|
||||||
|
{
|
||||||
|
// Migrate away from legacy non-stealth install by removing the old app container.
|
||||||
|
registerPath(previousTrollStoreAppPath, YES, YES);
|
||||||
|
[[NSFileManager defaultManager] removeItemAtPath:previousTrollStorePath error:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
[[NSFileManager defaultManager] removeItemAtPath:tmpPackagePath error:nil];
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1547,8 +1637,9 @@ int MAIN_NAME(int argc, char *argv[], char *envp[])
|
|||||||
BOOL useInstalldMethod = [args containsObject:@"installd"];
|
BOOL useInstalldMethod = [args containsObject:@"installd"];
|
||||||
BOOL force = [args containsObject:@"force"];
|
BOOL force = [args containsObject:@"force"];
|
||||||
BOOL skipUICache = [args containsObject:@"skip-uicache"];
|
BOOL skipUICache = [args containsObject:@"skip-uicache"];
|
||||||
|
BOOL stealthInstall = [args containsObject:@"stealth"];
|
||||||
NSString* ipaPath = args.lastObject;
|
NSString* ipaPath = args.lastObject;
|
||||||
ret = installIpa(ipaPath, force, useInstalldMethod, skipUICache);
|
ret = installIpa(ipaPath, force, useInstalldMethod, skipUICache, stealthInstall);
|
||||||
}
|
}
|
||||||
else if([cmd isEqualToString:@"uninstall"])
|
else if([cmd isEqualToString:@"uninstall"])
|
||||||
{
|
{
|
||||||
|
|||||||
@ -131,7 +131,8 @@ bool registerPath(NSString *path, BOOL unregister, BOOL forceSystem) {
|
|||||||
dictToRegister[@"Container"] = containerPath;
|
dictToRegister[@"Container"] = containerPath;
|
||||||
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath, appContainerized);
|
dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath, appContainerized);
|
||||||
}
|
}
|
||||||
dictToRegister[@"IsDeletable"] = @(![appBundleID isEqualToString:@"com.opa334.TrollStore"] && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
|
BOOL isTrollStoreMainApp = [path isEqualToString:trollStoreAppPath()];
|
||||||
|
dictToRegister[@"IsDeletable"] = @(!isTrollStoreMainApp && kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber_iOS_15_0);
|
||||||
dictToRegister[@"Path"] = path;
|
dictToRegister[@"Path"] = path;
|
||||||
|
|
||||||
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
|
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
|
||||||
|
|||||||
@ -39,6 +39,7 @@ extern NSArray* trollStoreInactiveInstalledAppBundlePaths(void);
|
|||||||
extern NSArray* trollStoreInstalledAppContainerPaths(void);
|
extern NSArray* trollStoreInstalledAppContainerPaths(void);
|
||||||
extern NSString* trollStorePath(void);
|
extern NSString* trollStorePath(void);
|
||||||
extern NSString* trollStoreAppPath(void);
|
extern NSString* trollStoreAppPath(void);
|
||||||
|
extern NSString* installedStealthAppIdForOriginalAppId(NSString* originalAppId);
|
||||||
|
|
||||||
extern BOOL isRemovableSystemApp(NSString* appId);
|
extern BOOL isRemovableSystemApp(NSString* appId);
|
||||||
|
|
||||||
|
|||||||
@ -406,12 +406,64 @@ NSArray *trollStoreInactiveInstalledAppBundlePaths(void)
|
|||||||
return trollStoreInstalledAppBundlePathsInternal(TS_INACTIVE_MARKER);
|
return trollStoreInstalledAppBundlePathsInternal(TS_INACTIVE_MARKER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NSString* trollStoreContainerPathForAppIdentifier(NSString* appId)
|
||||||
|
{
|
||||||
|
if(![appId isKindOfClass:NSString.class] || appId.length == 0) return nil;
|
||||||
|
|
||||||
|
MCMAppContainer* appContainer = [MCMAppContainer containerWithIdentifier:appId createIfNecessary:NO existed:NULL error:nil];
|
||||||
|
NSString* appContainerPath = appContainer.url.path;
|
||||||
|
if(!appContainerPath) return nil;
|
||||||
|
|
||||||
|
NSString* appPath = [appContainerPath stringByAppendingPathComponent:@"TrollStore.app"];
|
||||||
|
if(![[NSFileManager defaultManager] fileExistsAtPath:appPath]) return nil;
|
||||||
|
return appContainerPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString* installedStealthAppIdForOriginalAppId(NSString* originalAppId)
|
||||||
|
{
|
||||||
|
if(![originalAppId isKindOfClass:NSString.class] || originalAppId.length == 0) return nil;
|
||||||
|
|
||||||
|
LSEnumerator* enumerator = [LSEnumerator enumeratorForApplicationProxiesWithOptions:0];
|
||||||
|
LSApplicationProxy* appProxy;
|
||||||
|
while(appProxy = [enumerator nextObject])
|
||||||
|
{
|
||||||
|
if(!appProxy.installed) continue;
|
||||||
|
|
||||||
|
NSString* appPath = appProxy.bundleURL.path;
|
||||||
|
if(![appPath isKindOfClass:NSString.class] || appPath.length == 0) continue;
|
||||||
|
|
||||||
|
NSDictionary* infoDict = [NSDictionary dictionaryWithContentsOfFile:[appPath stringByAppendingPathComponent:@"Info.plist"]];
|
||||||
|
NSString* installedOriginalAppId = infoDict[@"TSOriginalBundleIdentifier"];
|
||||||
|
NSString* installedAppId = infoDict[@"CFBundleIdentifier"];
|
||||||
|
if([installedOriginalAppId isKindOfClass:NSString.class] &&
|
||||||
|
[installedAppId isKindOfClass:NSString.class] &&
|
||||||
|
installedAppId.length > 0 &&
|
||||||
|
[installedOriginalAppId.lowercaseString isEqualToString:originalAppId.lowercaseString])
|
||||||
|
{
|
||||||
|
return installedAppId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
NSString* trollStorePath()
|
NSString* trollStorePath()
|
||||||
{
|
{
|
||||||
|
#ifndef TROLLSTORE_LITE
|
||||||
|
NSString* appContainerPath = trollStoreContainerPathForAppIdentifier(APP_ID);
|
||||||
|
if(appContainerPath) return appContainerPath;
|
||||||
|
|
||||||
|
appContainerPath = trollStoreContainerPathForAppIdentifier(@"com.opa334.trollstore");
|
||||||
|
if(appContainerPath) return appContainerPath;
|
||||||
|
|
||||||
|
NSString* stealthAppId = installedStealthAppIdForOriginalAppId(@"com.opa334.trollstore");
|
||||||
|
return trollStoreContainerPathForAppIdentifier(stealthAppId);
|
||||||
|
#else
|
||||||
NSError* mcmError;
|
NSError* mcmError;
|
||||||
MCMAppContainer* appContainer = [MCMAppContainer containerWithIdentifier:APP_ID createIfNecessary:NO existed:NULL error:&mcmError];
|
MCMAppContainer* appContainer = [MCMAppContainer containerWithIdentifier:APP_ID createIfNecessary:NO existed:NULL error:&mcmError];
|
||||||
if(!appContainer) return nil;
|
if(!appContainer) return nil;
|
||||||
return appContainer.url.path;
|
return appContainer.url.path;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString* trollStoreAppPath()
|
NSString* trollStoreAppPath()
|
||||||
|
|||||||
@ -11,12 +11,11 @@
|
|||||||
- (NSArray*)installedAppPaths;
|
- (NSArray*)installedAppPaths;
|
||||||
|
|
||||||
- (NSError*)errorForCode:(int)code;
|
- (NSError*)errorForCode:(int)code;
|
||||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut;
|
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force stealth:(BOOL)stealth log:(NSString**)logOut;
|
||||||
- (int)installIpa:(NSString*)pathToIpa;
|
|
||||||
- (int)uninstallApp:(NSString*)appId;
|
- (int)uninstallApp:(NSString*)appId;
|
||||||
- (int)uninstallAppByPath:(NSString*)path;
|
- (int)uninstallAppByPath:(NSString*)path;
|
||||||
- (BOOL)openApplicationWithBundleID:(NSString *)appID;
|
- (BOOL)openApplicationWithBundleID:(NSString *)appID;
|
||||||
- (int)enableJITForBundleID:(NSString *)appID;
|
- (int)enableJITForBundleID:(NSString *)appID;
|
||||||
- (int)changeAppRegistration:(NSString*)appPath toState:(NSString*)newState;
|
- (int)changeAppRegistration:(NSString*)appPath toState:(NSString*)newState;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -91,13 +91,16 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
|||||||
break;
|
break;
|
||||||
case 185:
|
case 185:
|
||||||
errorDescription = @"Failed to sign the app. The CoreTrust bypass returned a non zero status code.";
|
errorDescription = @"Failed to sign the app. The CoreTrust bypass returned a non zero status code.";
|
||||||
|
break;
|
||||||
|
case 186:
|
||||||
|
errorDescription = @"This app is already installed using the opposite install mode (Stealth vs Normal). Uninstall it first before switching modes.";
|
||||||
}
|
}
|
||||||
|
|
||||||
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
|
NSError* error = [NSError errorWithDomain:TrollStoreErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : errorDescription}];
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force log:(NSString**)logOut
|
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force stealth:(BOOL)stealth log:(NSString**)logOut
|
||||||
{
|
{
|
||||||
NSMutableArray* args = [NSMutableArray new];
|
NSMutableArray* args = [NSMutableArray new];
|
||||||
[args addObject:@"install"];
|
[args addObject:@"install"];
|
||||||
@ -105,6 +108,10 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
|||||||
{
|
{
|
||||||
[args addObject:@"force"];
|
[args addObject:@"force"];
|
||||||
}
|
}
|
||||||
|
if(stealth)
|
||||||
|
{
|
||||||
|
[args addObject:@"stealth"];
|
||||||
|
}
|
||||||
NSNumber* installationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"installationMethod"];
|
NSNumber* installationMethodToUseNum = [trollStoreUserDefaults() objectForKey:@"installationMethod"];
|
||||||
int installationMethodToUse = installationMethodToUseNum ? installationMethodToUseNum.intValue : 1;
|
int installationMethodToUse = installationMethodToUseNum ? installationMethodToUseNum.intValue : 1;
|
||||||
if(installationMethodToUse == 1)
|
if(installationMethodToUse == 1)
|
||||||
@ -122,11 +129,6 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)installIpa:(NSString*)pathToIpa
|
|
||||||
{
|
|
||||||
return [self installIpa:pathToIpa force:NO log:nil];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (int)uninstallApp:(NSString*)appId
|
- (int)uninstallApp:(NSString*)appId
|
||||||
{
|
{
|
||||||
if(!appId) return -200;
|
if(!appId) return -200;
|
||||||
@ -193,4 +195,4 @@ extern NSUserDefaults* trollStoreUserDefaults();
|
|||||||
return spawnRoot(rootHelperPath(), @[@"modify-registration", appPath, newState], nil, nil);
|
return spawnRoot(rootHelperPath(), @[@"modify-registration", appPath, newState], nil, nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -4,11 +4,10 @@
|
|||||||
|
|
||||||
+ (void)presentInstallationAlertIfEnabledForFile:(NSString*)pathToIPA isRemoteInstall:(BOOL)remoteInstall completion:(void (^)(BOOL, NSError*))completionBlock;
|
+ (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 stealthInstall:(BOOL)stealth completion:(void (^)(BOOL, NSError*))completion;
|
||||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completion;
|
|
||||||
|
|
||||||
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion;
|
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completion;
|
||||||
|
|
||||||
+ (void)installLdid;
|
+ (void)installLdid;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@ -9,7 +9,7 @@ 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 stealthInstall:(BOOL)stealth completion:(void (^)(BOOL, NSError*))completionBlock
|
||||||
{
|
{
|
||||||
dispatch_async(dispatch_get_main_queue(), ^
|
dispatch_async(dispatch_get_main_queue(), ^
|
||||||
{
|
{
|
||||||
@ -18,7 +18,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
|||||||
{
|
{
|
||||||
// Install IPA
|
// Install IPA
|
||||||
NSString* log;
|
NSString* log;
|
||||||
int ret = [[TSApplicationsManager sharedInstance] installIpa:pathToIPA force:force log:&log];
|
int ret = [[TSApplicationsManager sharedInstance] installIpa:pathToIPA force:force stealth:stealth log:&log];
|
||||||
|
|
||||||
NSError* error;
|
NSError* error;
|
||||||
if(ret != 0)
|
if(ret != 0)
|
||||||
@ -46,7 +46,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
|||||||
|
|
||||||
UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
|
UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
|
||||||
{
|
{
|
||||||
[self handleAppInstallFromFile:pathToIPA forceInstall:YES completion:completionBlock];
|
[self handleAppInstallFromFile:pathToIPA forceInstall:YES stealthInstall:stealth completion:completionBlock];
|
||||||
}];
|
}];
|
||||||
[errorAlert addAction:forceInstallAction];
|
[errorAlert addAction:forceInstallAction];
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
|||||||
{
|
{
|
||||||
if(installAlertConfiguration == 2 || (installAlertConfiguration == 1 && !remoteInstall))
|
if(installAlertConfiguration == 2 || (installAlertConfiguration == 1 && !remoteInstall))
|
||||||
{
|
{
|
||||||
[self handleAppInstallFromFile:pathToIPA completion:completionBlock];
|
[self handleAppInstallFromFile:pathToIPA forceInstall:NO stealthInstall:NO completion:completionBlock];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,10 +137,16 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
|||||||
installAlert.attributedMessage = [appInfo detailedInfoDescription];
|
installAlert.attributedMessage = [appInfo detailedInfoDescription];
|
||||||
UIAlertAction* installAction = [UIAlertAction actionWithTitle:@"Install" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action)
|
UIAlertAction* installAction = [UIAlertAction actionWithTitle:@"Install" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action)
|
||||||
{
|
{
|
||||||
[self handleAppInstallFromFile:pathToIPA completion:completionBlock];
|
[self handleAppInstallFromFile:pathToIPA forceInstall:NO stealthInstall:NO completion:completionBlock];
|
||||||
}];
|
}];
|
||||||
[installAlert addAction:installAction];
|
[installAlert addAction:installAction];
|
||||||
|
|
||||||
|
UIAlertAction* stealthInstallAction = [UIAlertAction actionWithTitle:@"Stealth Install" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action)
|
||||||
|
{
|
||||||
|
[self handleAppInstallFromFile:pathToIPA forceInstall:NO stealthInstall:YES completion:completionBlock];
|
||||||
|
}];
|
||||||
|
[installAlert addAction:stealthInstallAction];
|
||||||
|
|
||||||
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action)
|
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction* action)
|
||||||
{
|
{
|
||||||
if(completionBlock) completionBlock(NO, nil);
|
if(completionBlock) completionBlock(NO, nil);
|
||||||
@ -161,11 +167,6 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (void)handleAppInstallFromFile:(NSString*)pathToIPA completion:(void (^)(BOOL, NSError*))completionBlock
|
|
||||||
{
|
|
||||||
[self handleAppInstallFromFile:pathToIPA forceInstall:NO completion:completionBlock];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completionBlock
|
+ (void)handleAppInstallFromRemoteURL:(NSURL*)remoteURL completion:(void (^)(BOOL, NSError*))completionBlock
|
||||||
{
|
{
|
||||||
NSURLRequest* downloadRequest = [NSURLRequest requestWithURL:remoteURL];
|
NSURLRequest* downloadRequest = [NSURLRequest requestWithURL:remoteURL];
|
||||||
@ -257,4 +258,4 @@ extern NSUserDefaults* trollStoreUserDefaults(void);
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user