mirror of
				https://github.com/opa334/TrollStore.git
				synced 2025-11-04 07:32:36 +08:00 
			
		
		
		
	Merge branch 'main' into exp-value-picker
This commit is contained in:
		
						commit
						aceff0e0dc
					
				@ -1,6 +1,6 @@
 | 
			
		||||
Package: com.opa334.trollstoreroothelper
 | 
			
		||||
Name: trollstoreroothelper
 | 
			
		||||
Version: 1.0.1
 | 
			
		||||
Version: 1.0.3
 | 
			
		||||
Architecture: iphoneos-arm
 | 
			
		||||
Description: An awesome tool of some sort!!
 | 
			
		||||
Maintainer: opa334
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										211
									
								
								Helper/main.m
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								Helper/main.m
									
									
									
									
									
								
							@ -8,9 +8,54 @@
 | 
			
		||||
#import <objc/runtime.h>
 | 
			
		||||
#import "CoreServices.h"
 | 
			
		||||
#import "Shared.h"
 | 
			
		||||
#import <mach-o/getsect.h>
 | 
			
		||||
#import <mach-o/dyld.h>
 | 
			
		||||
#import <mach/mach.h>
 | 
			
		||||
#import <mach-o/loader.h>
 | 
			
		||||
#import <mach-o/nlist.h>
 | 
			
		||||
#import <mach-o/reloc.h>
 | 
			
		||||
#import <mach-o/dyld_images.h>
 | 
			
		||||
#import <mach-o/fat.h>
 | 
			
		||||
#import <sys/utsname.h>
 | 
			
		||||
 | 
			
		||||
#import <SpringBoardServices/SpringBoardServices.h>
 | 
			
		||||
 | 
			
		||||
#ifdef __LP64__
 | 
			
		||||
#define segment_command_universal segment_command_64
 | 
			
		||||
#define mach_header_universal mach_header_64
 | 
			
		||||
#define MH_MAGIC_UNIVERSAL MH_MAGIC_64
 | 
			
		||||
#define MH_CIGAM_UNIVERSAL MH_CIGAM_64
 | 
			
		||||
#else
 | 
			
		||||
#define segment_command_universal segment_command
 | 
			
		||||
#define mach_header_universal mach_header
 | 
			
		||||
#define MH_MAGIC_UNIVERSAL MH_MAGIC
 | 
			
		||||
#define MH_CIGAM_UNIVERSAL MH_CIGAM
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x) & 0xff) << 24))
 | 
			
		||||
uint32_t s32(uint32_t toSwap, BOOL shouldSwap)
 | 
			
		||||
{
 | 
			
		||||
	return shouldSwap ? SWAP32(toSwap) : toSwap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define CPU_SUBTYPE_ARM64E_NEW_ABI 0x80000002
 | 
			
		||||
 | 
			
		||||
struct CSSuperBlob {
 | 
			
		||||
	uint32_t magic;
 | 
			
		||||
	uint32_t length;
 | 
			
		||||
	uint32_t count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CSBlob {
 | 
			
		||||
	uint32_t type;
 | 
			
		||||
	uint32_t offset;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CS_MAGIC_EMBEDDED_SIGNATURE 0xfade0cc0
 | 
			
		||||
#define CS_MAGIC_EMBEDDED_SIGNATURE_REVERSED 0xc00cdefa
 | 
			
		||||
#define CS_MAGIC_EMBEDDED_ENTITLEMENTS 0xfade7171
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier);
 | 
			
		||||
@interface SBSHomeScreenService : NSObject
 | 
			
		||||
- (void)reloadIcons;
 | 
			
		||||
@ -176,28 +221,111 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput)
 | 
			
		||||
	return WEXITSTATUS(status);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
NSString* dumpEntitlements(NSString* binaryPath)
 | 
			
		||||
NSDictionary* dumpEntitlements(NSString* binaryPath)
 | 
			
		||||
{
 | 
			
		||||
	NSString* output;
 | 
			
		||||
	NSString* errorOutput;
 | 
			
		||||
	char* entitlementsData = NULL;
 | 
			
		||||
	uint32_t entitlementsLength = 0;
 | 
			
		||||
 | 
			
		||||
	int ldidRet = runLdid(@[@"-e", binaryPath], &output, &errorOutput);
 | 
			
		||||
	FILE* machoFile = fopen(binaryPath.UTF8String, "rb");
 | 
			
		||||
	struct mach_header_universal header;
 | 
			
		||||
	fread(&header,sizeof(header),1,machoFile);
 | 
			
		||||
 | 
			
		||||
	NSLog(@"entitlements dump exited with status %d", ldidRet);
 | 
			
		||||
	if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM)
 | 
			
		||||
	{
 | 
			
		||||
		fseek(machoFile,0,SEEK_SET);
 | 
			
		||||
 | 
			
		||||
		struct fat_header fatHeader;
 | 
			
		||||
		fread(&fatHeader,sizeof(fatHeader),1,machoFile);
 | 
			
		||||
 | 
			
		||||
		BOOL swpFat = fatHeader.magic == FAT_CIGAM;
 | 
			
		||||
 | 
			
		||||
		for(int i = 0; i < s32(fatHeader.nfat_arch, swpFat); i++)
 | 
			
		||||
		{
 | 
			
		||||
			struct fat_arch fatArch;
 | 
			
		||||
			fseek(machoFile,sizeof(fatHeader) + sizeof(fatArch) * i,SEEK_SET);
 | 
			
		||||
			fread(&fatArch,sizeof(fatArch),1,machoFile);
 | 
			
		||||
 | 
			
		||||
			if(s32(fatArch.cputype, swpFat) != CPU_TYPE_ARM64)
 | 
			
		||||
			{
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			fseek(machoFile,s32(fatArch.offset, swpFat),SEEK_SET);
 | 
			
		||||
			struct mach_header_universal header;
 | 
			
		||||
			fread(&header,sizeof(header),1,machoFile);
 | 
			
		||||
 | 
			
		||||
			BOOL swp = header.magic == MH_CIGAM_UNIVERSAL;
 | 
			
		||||
 | 
			
		||||
			// This code is cursed, don't stare at it too long or it will stare back at you
 | 
			
		||||
			uint32_t offset = s32(fatArch.offset, swpFat) + sizeof(header);
 | 
			
		||||
			for(int c = 0; c < s32(header.ncmds, swp); c++)
 | 
			
		||||
			{
 | 
			
		||||
				fseek(machoFile,offset,SEEK_SET);
 | 
			
		||||
				struct load_command cmd;
 | 
			
		||||
				fread(&cmd,sizeof(cmd),1,machoFile);
 | 
			
		||||
				uint32_t normalizedCmd = s32(cmd.cmd,swp);
 | 
			
		||||
				if(normalizedCmd == LC_CODE_SIGNATURE)
 | 
			
		||||
				{
 | 
			
		||||
					struct linkedit_data_command codeSignCommand;
 | 
			
		||||
					fseek(machoFile,offset,SEEK_SET);
 | 
			
		||||
					fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile);
 | 
			
		||||
					uint32_t codeSignCmdOffset = s32(fatArch.offset, swpFat) + s32(codeSignCommand.dataoff, swp);
 | 
			
		||||
					fseek(machoFile, codeSignCmdOffset, SEEK_SET);
 | 
			
		||||
					struct CSSuperBlob superBlob;
 | 
			
		||||
					fread(&superBlob, sizeof(superBlob), 1, machoFile);
 | 
			
		||||
					if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE)
 | 
			
		||||
					{
 | 
			
		||||
						uint32_t itemCount = SWAP32(superBlob.count);
 | 
			
		||||
						for(int i = 0; i < itemCount; i++)
 | 
			
		||||
						{
 | 
			
		||||
							fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET);
 | 
			
		||||
							struct CSBlob blob;
 | 
			
		||||
							fread(&blob, sizeof(struct CSBlob), 1, machoFile);
 | 
			
		||||
							fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET);
 | 
			
		||||
							uint32_t blobMagic;
 | 
			
		||||
							fread(&blobMagic, sizeof(uint32_t), 1, machoFile);
 | 
			
		||||
							if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS)
 | 
			
		||||
							{
 | 
			
		||||
								uint32_t entitlementsLengthTmp;
 | 
			
		||||
								fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile);
 | 
			
		||||
								entitlementsLength = SWAP32(entitlementsLengthTmp);
 | 
			
		||||
								entitlementsData = malloc(entitlementsLength - 8);
 | 
			
		||||
								fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile);
 | 
			
		||||
								break;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				offset += cmd.cmdsize;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fclose(machoFile);
 | 
			
		||||
 | 
			
		||||
	NSData* entitlementsNSData = nil;
 | 
			
		||||
 | 
			
		||||
	if(entitlementsData)
 | 
			
		||||
	{
 | 
			
		||||
		entitlementsNSData = [NSData dataWithBytes:entitlementsData length:entitlementsLength];
 | 
			
		||||
		free(entitlementsData);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(entitlementsNSData)
 | 
			
		||||
	{
 | 
			
		||||
		NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:entitlementsNSData options:NSPropertyListImmutable format:nil error:nil];
 | 
			
		||||
		NSLog(@"%@ dumped entitlements %@", binaryPath, plist);
 | 
			
		||||
		return plist;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		NSLog(@"Failed to dump entitlements of %@... This is bad", binaryPath);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	NSLog(@"- dump error output start -");
 | 
			
		||||
 | 
			
		||||
	printMultilineNSString(errorOutput);
 | 
			
		||||
 | 
			
		||||
	NSLog(@"- dump error output end -");
 | 
			
		||||
 | 
			
		||||
	NSLog(@"- dumped entitlements output start -");
 | 
			
		||||
 | 
			
		||||
	printMultilineNSString(output);
 | 
			
		||||
 | 
			
		||||
	NSLog(@"- dumped entitlements output end -");
 | 
			
		||||
 | 
			
		||||
	return output;
 | 
			
		||||
	return nil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BOOL signApp(NSString* appPath, NSError** error)
 | 
			
		||||
@ -217,8 +345,8 @@ BOOL signApp(NSString* appPath, NSError** error)
 | 
			
		||||
	NSString* errorOutput;
 | 
			
		||||
	int ldidRet;
 | 
			
		||||
 | 
			
		||||
	NSString* entitlements = dumpEntitlements(executablePath);
 | 
			
		||||
	if(entitlements.length == 0)
 | 
			
		||||
	NSDictionary* entitlements = dumpEntitlements(executablePath);
 | 
			
		||||
	if(!entitlements)
 | 
			
		||||
	{
 | 
			
		||||
		NSLog(@"app main binary has no entitlements, signing app with fallback entitlements...");
 | 
			
		||||
		// app has no entitlements, sign with fallback entitlements
 | 
			
		||||
@ -229,7 +357,7 @@ BOOL signApp(NSString* appPath, NSError** error)
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// app has entitlements, keep them
 | 
			
		||||
		ldidRet = runLdid(@[@"-S", @"-M", certArg, appPath], nil, &errorOutput);
 | 
			
		||||
		ldidRet = runLdid(@[@"-s", certArg, appPath], nil, &errorOutput);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	NSLog(@"ldid exited with status %d", ldidRet);
 | 
			
		||||
@ -246,8 +374,10 @@ BOOL signApp(NSString* appPath, NSError** error)
 | 
			
		||||
// 170: failed to create container for app bundle
 | 
			
		||||
// 171: a non trollstore app with the same identifier is already installled
 | 
			
		||||
// 172: no info.plist found in app
 | 
			
		||||
int installApp(NSString* appPath, BOOL sign, NSError** error)
 | 
			
		||||
int installApp(NSString* appPath, BOOL sign, BOOL force, NSError** error)
 | 
			
		||||
{
 | 
			
		||||
	NSLog(@"[installApp force = %d]", force);
 | 
			
		||||
 | 
			
		||||
	NSString* appId = appIdForAppPath(appPath);
 | 
			
		||||
	if(!appId) return 172;
 | 
			
		||||
 | 
			
		||||
@ -281,12 +411,15 @@ int installApp(NSString* appPath, BOOL sign, NSError** error)
 | 
			
		||||
 | 
			
		||||
	// Make sure there isn't already an app store app installed with the same identifier
 | 
			
		||||
	NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"];
 | 
			
		||||
	if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil])
 | 
			
		||||
	if(existed && !isEmpty && ![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil] && !force)
 | 
			
		||||
	{
 | 
			
		||||
		NSLog(@"[installApp] already installed and not a TrollStore app... bailing out");
 | 
			
		||||
		return 171;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Mark app as TrollStore app
 | 
			
		||||
	[[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil];
 | 
			
		||||
 | 
			
		||||
	// Apply correct permissions
 | 
			
		||||
	NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:[NSURL fileURLWithPath:appPath] includingPropertiesForKeys:nil options:0 errorHandler:nil];
 | 
			
		||||
	NSURL* fileURL;
 | 
			
		||||
@ -342,7 +475,7 @@ int installApp(NSString* appPath, BOOL sign, NSError** error)
 | 
			
		||||
		while(fileURL = [enumerator nextObject])
 | 
			
		||||
		{
 | 
			
		||||
			// do not under any circumstance delete this file as it makes iOS loose the app registration
 | 
			
		||||
			if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"])
 | 
			
		||||
			if([fileURL.lastPathComponent isEqualToString:@".com.apple.mobile_container_manager.metadata.plist"] || [fileURL.lastPathComponent isEqualToString:@"_TrollStore"])
 | 
			
		||||
			{
 | 
			
		||||
				NSLog(@"[installApp] skip removal of %@", fileURL);
 | 
			
		||||
				continue;
 | 
			
		||||
@ -359,9 +492,6 @@ int installApp(NSString* appPath, BOOL sign, NSError** error)
 | 
			
		||||
	BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appPath toPath:newAppPath error:error];
 | 
			
		||||
	if(suc)
 | 
			
		||||
	{
 | 
			
		||||
		// Mark app as TrollStore app
 | 
			
		||||
		[[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil];
 | 
			
		||||
 | 
			
		||||
		NSLog(@"[installApp] app installed, adding to icon cache now...");
 | 
			
		||||
		registerPath((char*)newAppPath.UTF8String, 0);
 | 
			
		||||
		return 0;
 | 
			
		||||
@ -382,6 +512,7 @@ int uninstallApp(NSString* appId, NSError** error)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer") containerWithIdentifier:appId createIfNecessary:NO existed:nil error:nil];
 | 
			
		||||
	NSLog(@"1");
 | 
			
		||||
	NSString *containerPath = [appContainer url].path;
 | 
			
		||||
	if(containerPath)
 | 
			
		||||
	{
 | 
			
		||||
@ -391,11 +522,11 @@ int uninstallApp(NSString* appId, NSError** error)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// delete group container paths
 | 
			
		||||
	for(NSURL* groupURL in [appProxy groupContainerURLs])
 | 
			
		||||
	[[appProxy groupContainerURLs] enumerateKeysAndObjectsUsingBlock:^(NSString* groupID, NSURL* groupURL, BOOL* stop)
 | 
			
		||||
	{
 | 
			
		||||
		[[NSFileManager defaultManager] removeItemAtPath:groupURL.path error:error];
 | 
			
		||||
		NSLog(@"deleting %@", groupURL.path);
 | 
			
		||||
	}
 | 
			
		||||
		[[NSFileManager defaultManager] removeItemAtURL:groupURL error:nil];
 | 
			
		||||
		NSLog(@"deleting %@", groupURL);
 | 
			
		||||
	}];
 | 
			
		||||
 | 
			
		||||
	// delete app plugin paths
 | 
			
		||||
	for(LSPlugInKitProxy* pluginProxy in appProxy.plugInKitPlugins)
 | 
			
		||||
@ -427,7 +558,7 @@ int uninstallApp(NSString* appId, NSError** error)
 | 
			
		||||
// 166: IPA does not exist or is not accessible
 | 
			
		||||
// 167: IPA does not appear to contain an app
 | 
			
		||||
 | 
			
		||||
int installIpa(NSString* ipaPath, NSError** error)
 | 
			
		||||
int installIpa(NSString* ipaPath, BOOL force, NSError** error)
 | 
			
		||||
{
 | 
			
		||||
	if(![[NSFileManager defaultManager] fileExistsAtPath:ipaPath]) return 166;
 | 
			
		||||
 | 
			
		||||
@ -455,7 +586,7 @@ int installIpa(NSString* ipaPath, NSError** error)
 | 
			
		||||
	}
 | 
			
		||||
	if(!tmpAppPath) return 167;
 | 
			
		||||
	
 | 
			
		||||
	int ret = installApp(tmpAppPath, YES, error);
 | 
			
		||||
	int ret = installApp(tmpAppPath, YES, force, error);
 | 
			
		||||
	
 | 
			
		||||
	[[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil];
 | 
			
		||||
 | 
			
		||||
@ -530,7 +661,7 @@ BOOL installTrollStore(NSString* pathToTar)
 | 
			
		||||
		_installPersistenceHelper(persistenceHelperApp, trollStorePersistenceHelper, trollStoreRootHelper);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return installApp(tmpTrollStore, NO, nil);;
 | 
			
		||||
	return installApp(tmpTrollStore, NO, YES, nil);;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void refreshAppRegistrations()
 | 
			
		||||
@ -663,9 +794,19 @@ int main(int argc, char *argv[], char *envp[]) {
 | 
			
		||||
		NSString* cmd = [NSString stringWithUTF8String:argv[1]];
 | 
			
		||||
		if([cmd isEqualToString:@"install"])
 | 
			
		||||
		{
 | 
			
		||||
			NSLog(@"argc = %d", argc);
 | 
			
		||||
			BOOL force = NO;
 | 
			
		||||
			if(argc <= 2) return -3;
 | 
			
		||||
			if(argc > 3)
 | 
			
		||||
			{
 | 
			
		||||
				NSLog(@"argv3 = %s", argv[3]);
 | 
			
		||||
				if(!strcmp(argv[3], "force"))
 | 
			
		||||
				{
 | 
			
		||||
					force = YES;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			NSString* ipaPath = [NSString stringWithUTF8String:argv[2]];
 | 
			
		||||
			ret = installIpa(ipaPath, &error);
 | 
			
		||||
			ret = installIpa(ipaPath, force, &error);
 | 
			
		||||
		} else if([cmd isEqualToString:@"uninstall"])
 | 
			
		||||
		{
 | 
			
		||||
			if(argc <= 2) return -3;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										306
									
								
								Helper/uicache.m
									
									
									
									
									
								
							
							
						
						
									
										306
									
								
								Helper/uicache.m
									
									
									
									
									
								
							@ -4,89 +4,247 @@
 | 
			
		||||
#import <objc/runtime.h>
 | 
			
		||||
#import "dlfcn.h"
 | 
			
		||||
 | 
			
		||||
void registerPath(char *path, int unregister)
 | 
			
		||||
// uicache on steroids
 | 
			
		||||
 | 
			
		||||
extern NSDictionary* dumpEntitlements(NSString* binaryPath);
 | 
			
		||||
 | 
			
		||||
NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups)
 | 
			
		||||
{
 | 
			
		||||
    if(!path) return;
 | 
			
		||||
	if(!entitlements) return nil;
 | 
			
		||||
 | 
			
		||||
    LSApplicationWorkspace *workspace =
 | 
			
		||||
        [LSApplicationWorkspace defaultWorkspace];
 | 
			
		||||
    if (unregister && ![[NSFileManager defaultManager] fileExistsAtPath:[NSString stringWithUTF8String:path]]) {
 | 
			
		||||
        LSApplicationProxy *app = [LSApplicationProxy
 | 
			
		||||
            applicationProxyForIdentifier:[NSString stringWithUTF8String:path]];
 | 
			
		||||
        if (app.bundleURL)
 | 
			
		||||
            path = (char *)[[app bundleURL] fileSystemRepresentation];
 | 
			
		||||
    }
 | 
			
		||||
	NSString* entitlementForGroups;
 | 
			
		||||
	NSString* mcmClass;
 | 
			
		||||
	if(systemGroups)
 | 
			
		||||
	{
 | 
			
		||||
		entitlementForGroups = @"com.apple.security.system-groups";
 | 
			
		||||
		mcmClass = @"MCMSystemDataContainer";
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		entitlementForGroups = @"com.apple.security.application-groups";
 | 
			
		||||
		mcmClass = @"MCMSharedDataContainer";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    NSString *rawPath = [NSString stringWithUTF8String:path];
 | 
			
		||||
    rawPath = [rawPath stringByResolvingSymlinksInPath];
 | 
			
		||||
	NSArray* groupIDs = entitlements[entitlementForGroups];
 | 
			
		||||
	if(groupIDs && [groupIDs isKindOfClass:[NSArray class]])
 | 
			
		||||
	{
 | 
			
		||||
		NSMutableDictionary* groupContainers = [NSMutableDictionary new];
 | 
			
		||||
 | 
			
		||||
    NSDictionary *infoPlist = [NSDictionary
 | 
			
		||||
        dictionaryWithContentsOfFile:
 | 
			
		||||
            [rawPath stringByAppendingPathComponent:@"Info.plist"]];
 | 
			
		||||
    NSString *bundleID = [infoPlist objectForKey:@"CFBundleIdentifier"];
 | 
			
		||||
		for(NSString* groupID in groupIDs)
 | 
			
		||||
		{
 | 
			
		||||
			MCMContainer* container = [NSClassFromString(mcmClass) containerWithIdentifier:groupID createIfNecessary:YES existed:nil error:nil];
 | 
			
		||||
			if(container.url)
 | 
			
		||||
			{
 | 
			
		||||
				groupContainers[groupID] = container.url.path;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    NSURL *url = [NSURL fileURLWithPath:rawPath];
 | 
			
		||||
		return groupContainers.copy;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
    if (bundleID && !unregister) {
 | 
			
		||||
        MCMContainer *appContainer = [objc_getClass("MCMAppDataContainer")
 | 
			
		||||
            containerWithIdentifier:bundleID
 | 
			
		||||
                  createIfNecessary:YES
 | 
			
		||||
                            existed:nil
 | 
			
		||||
                              error:nil];
 | 
			
		||||
        NSString *containerPath = [appContainer url].path;
 | 
			
		||||
	return nil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
        NSMutableDictionary *plist = [NSMutableDictionary dictionary];
 | 
			
		||||
        [plist setObject:@"System" forKey:@"ApplicationType"];
 | 
			
		||||
        [plist setObject:@1 forKey:@"BundleNameIsLocalized"];
 | 
			
		||||
        [plist setObject:bundleID forKey:@"CFBundleIdentifier"];
 | 
			
		||||
        [plist setObject:@0 forKey:@"CompatibilityState"];
 | 
			
		||||
        if (containerPath) [plist setObject:containerPath forKey:@"Container"];
 | 
			
		||||
        [plist setObject:@0 forKey:@"IsDeletable"];
 | 
			
		||||
        [plist setObject:rawPath forKey:@"Path"];
 | 
			
		||||
BOOL constructContainerizationForEntitlements(NSDictionary* entitlements)
 | 
			
		||||
{
 | 
			
		||||
	NSNumber* noContainer = entitlements[@"com.apple.private.security.no-container"];
 | 
			
		||||
	if(noContainer && [noContainer isKindOfClass:[NSNumber class]])
 | 
			
		||||
	{
 | 
			
		||||
		if(noContainer.boolValue)
 | 
			
		||||
		{
 | 
			
		||||
			return NO;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        NSString *pluginsPath =
 | 
			
		||||
            [rawPath stringByAppendingPathComponent:@"PlugIns"];
 | 
			
		||||
        NSArray *plugins = [[NSFileManager defaultManager]
 | 
			
		||||
            contentsOfDirectoryAtPath:pluginsPath
 | 
			
		||||
                                error:nil];
 | 
			
		||||
	NSNumber* containerRequired = entitlements[@"com.apple.private.security.container-required"];
 | 
			
		||||
	if(containerRequired && [containerRequired isKindOfClass:[NSNumber class]])
 | 
			
		||||
	{
 | 
			
		||||
		if(!containerRequired.boolValue)
 | 
			
		||||
		{
 | 
			
		||||
			return NO;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
        NSMutableDictionary *bundlePlugins = [NSMutableDictionary dictionary];
 | 
			
		||||
        for (NSString *pluginName in plugins) {
 | 
			
		||||
            NSString *fullPath =
 | 
			
		||||
                [pluginsPath stringByAppendingPathComponent:pluginName];
 | 
			
		||||
	return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            NSDictionary *infoPlist = [NSDictionary
 | 
			
		||||
                dictionaryWithContentsOfFile:
 | 
			
		||||
                    [fullPath stringByAppendingPathComponent:@"Info.plist"]];
 | 
			
		||||
            NSString *pluginBundleID =
 | 
			
		||||
                [infoPlist objectForKey:@"CFBundleIdentifier"];
 | 
			
		||||
            if (!pluginBundleID) continue;
 | 
			
		||||
            MCMContainer *pluginContainer =
 | 
			
		||||
                [objc_getClass("MCMPluginKitPluginDataContainer")
 | 
			
		||||
                    containerWithIdentifier:pluginBundleID
 | 
			
		||||
                          createIfNecessary:YES
 | 
			
		||||
                                    existed:nil
 | 
			
		||||
                                      error:nil];
 | 
			
		||||
            NSString *pluginContainerPath = [pluginContainer url].path;
 | 
			
		||||
NSString* constructTeamIdentifierForEntitlements(NSDictionary* entitlements)
 | 
			
		||||
{
 | 
			
		||||
	NSString* teamIdentifier = entitlements[@"com.apple.developer.team-identifier"];
 | 
			
		||||
	if(teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]])
 | 
			
		||||
	{
 | 
			
		||||
		return teamIdentifier;
 | 
			
		||||
	}
 | 
			
		||||
	return nil;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
            NSMutableDictionary *pluginPlist = [NSMutableDictionary dictionary];
 | 
			
		||||
            [pluginPlist setObject:@"PluginKitPlugin"
 | 
			
		||||
                            forKey:@"ApplicationType"];
 | 
			
		||||
            [pluginPlist setObject:@1 forKey:@"BundleNameIsLocalized"];
 | 
			
		||||
            [pluginPlist setObject:pluginBundleID forKey:@"CFBundleIdentifier"];
 | 
			
		||||
            [pluginPlist setObject:@0 forKey:@"CompatibilityState"];
 | 
			
		||||
            [pluginPlist setObject:pluginContainerPath forKey:@"Container"];
 | 
			
		||||
            [pluginPlist setObject:fullPath forKey:@"Path"];
 | 
			
		||||
            [pluginPlist setObject:bundleID forKey:@"PluginOwnerBundleID"];
 | 
			
		||||
            [bundlePlugins setObject:pluginPlist forKey:pluginBundleID];
 | 
			
		||||
        }
 | 
			
		||||
        [plist setObject:bundlePlugins forKey:@"_LSBundlePlugins"];
 | 
			
		||||
        if (![workspace registerApplicationDictionary:plist]) {
 | 
			
		||||
            fprintf(stderr, "Error: Unable to register %s\n", path);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (![workspace unregisterApplication:url]) {
 | 
			
		||||
            fprintf(stderr, "Error: Unable to unregister %s\n", path);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
NSDictionary* constructEnvironmentVariablesForContainerPath(NSString* containerPath)
 | 
			
		||||
{
 | 
			
		||||
	NSString* tmpDir = [containerPath stringByAppendingPathComponent:@"tmp"];
 | 
			
		||||
	return @{
 | 
			
		||||
		@"CFFIXED_USER_HOME" : containerPath,
 | 
			
		||||
		@"HOME" : containerPath,
 | 
			
		||||
		@"TMPDIR" : tmpDir
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void registerPath(char* cPath, int unregister)
 | 
			
		||||
{
 | 
			
		||||
	if(!cPath) return;
 | 
			
		||||
	NSString* path = [NSString stringWithUTF8String:cPath];
 | 
			
		||||
 | 
			
		||||
	LSApplicationWorkspace* workspace = [LSApplicationWorkspace defaultWorkspace];
 | 
			
		||||
	if(unregister && ![[NSFileManager defaultManager] fileExistsAtPath:path])
 | 
			
		||||
	{
 | 
			
		||||
		LSApplicationProxy* app = [LSApplicationProxy applicationProxyForIdentifier:path];
 | 
			
		||||
		if(app.bundleURL)
 | 
			
		||||
		{
 | 
			
		||||
			path = [app bundleURL].path;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	path = [path stringByResolvingSymlinksInPath];
 | 
			
		||||
 | 
			
		||||
	NSDictionary* appInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Info.plist"]];
 | 
			
		||||
	NSString* appBundleID = [appInfoPlist objectForKey:@"CFBundleIdentifier"];
 | 
			
		||||
 | 
			
		||||
	if(appBundleID && !unregister)
 | 
			
		||||
	{
 | 
			
		||||
		MCMContainer* appContainer = [NSClassFromString(@"MCMAppDataContainer") containerWithIdentifier:appBundleID createIfNecessary:YES existed:nil error:nil];
 | 
			
		||||
		NSString* containerPath = [appContainer url].path;
 | 
			
		||||
 | 
			
		||||
		NSMutableDictionary* dictToRegister = [NSMutableDictionary dictionary];
 | 
			
		||||
 | 
			
		||||
		// Add entitlements
 | 
			
		||||
 | 
			
		||||
		NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
 | 
			
		||||
		NSDictionary* entitlements = dumpEntitlements(appExecutablePath);
 | 
			
		||||
		if(entitlements)
 | 
			
		||||
		{
 | 
			
		||||
			dictToRegister[@"Entitlements"] = entitlements;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Misc
 | 
			
		||||
 | 
			
		||||
		dictToRegister[@"ApplicationType"] = @"System";
 | 
			
		||||
		dictToRegister[@"BundleNameIsLocalized"] = @1;
 | 
			
		||||
		dictToRegister[@"CFBundleIdentifier"] = appBundleID;
 | 
			
		||||
		dictToRegister[@"CodeInfoIdentifier"] = appBundleID;
 | 
			
		||||
		dictToRegister[@"CompatibilityState"] = @0;
 | 
			
		||||
		if(containerPath)
 | 
			
		||||
		{
 | 
			
		||||
			dictToRegister[@"Container"] = containerPath;
 | 
			
		||||
			dictToRegister[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(containerPath);
 | 
			
		||||
		}
 | 
			
		||||
		dictToRegister[@"IsDeletable"] = @0;
 | 
			
		||||
		dictToRegister[@"Path"] = path;
 | 
			
		||||
		dictToRegister[@"IsContainerized"] = @(constructContainerizationForEntitlements(entitlements));
 | 
			
		||||
 | 
			
		||||
		NSString* teamIdentifier = constructTeamIdentifierForEntitlements(entitlements);
 | 
			
		||||
		if(teamIdentifier) dictToRegister[@"TeamIdentifier"] = teamIdentifier;
 | 
			
		||||
 | 
			
		||||
		// Add group containers
 | 
			
		||||
 | 
			
		||||
		NSDictionary* appGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO);
 | 
			
		||||
		NSDictionary* systemGroupContainers = constructGroupsContainersForEntitlements(entitlements, NO);
 | 
			
		||||
		NSMutableDictionary* groupContainers = [NSMutableDictionary new];
 | 
			
		||||
		[groupContainers addEntriesFromDictionary:appGroupContainers];
 | 
			
		||||
		[groupContainers addEntriesFromDictionary:systemGroupContainers];
 | 
			
		||||
		if(groupContainers.count)
 | 
			
		||||
		{
 | 
			
		||||
			if(appGroupContainers.count)
 | 
			
		||||
			{
 | 
			
		||||
				dictToRegister[@"HasAppGroupContainers"] = @YES;
 | 
			
		||||
			}
 | 
			
		||||
			if(systemGroupContainers.count)
 | 
			
		||||
			{
 | 
			
		||||
				dictToRegister[@"HasSystemGroupContainers"] = @YES;
 | 
			
		||||
			}
 | 
			
		||||
			dictToRegister[@"GroupContainers"] = groupContainers.copy;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Add plugins
 | 
			
		||||
 | 
			
		||||
		NSString* pluginsPath = [path stringByAppendingPathComponent:@"PlugIns"];
 | 
			
		||||
		NSArray* plugins = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:pluginsPath error:nil];
 | 
			
		||||
 | 
			
		||||
		NSMutableDictionary* bundlePlugins = [NSMutableDictionary dictionary];
 | 
			
		||||
		for (NSString* pluginName in plugins)
 | 
			
		||||
		{
 | 
			
		||||
			NSString* pluginPath = [pluginsPath stringByAppendingPathComponent:pluginName];
 | 
			
		||||
 | 
			
		||||
			NSDictionary* pluginInfoPlist = [NSDictionary dictionaryWithContentsOfFile:[pluginPath stringByAppendingPathComponent:@"Info.plist"]];
 | 
			
		||||
			NSString* pluginBundleID = [pluginInfoPlist objectForKey:@"CFBundleIdentifier"];
 | 
			
		||||
 | 
			
		||||
			if(!pluginBundleID) continue;
 | 
			
		||||
			MCMContainer* pluginContainer = [NSClassFromString(@"MCMPluginKitPluginDataContainer") containerWithIdentifier:pluginBundleID createIfNecessary:YES existed:nil error:nil];
 | 
			
		||||
			NSString* pluginContainerPath = [pluginContainer url].path;
 | 
			
		||||
 | 
			
		||||
			NSMutableDictionary* pluginDict = [NSMutableDictionary dictionary];
 | 
			
		||||
 | 
			
		||||
			// Add entitlements
 | 
			
		||||
 | 
			
		||||
			NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]];
 | 
			
		||||
			NSDictionary* pluginEntitlements = dumpEntitlements(pluginExecutablePath);
 | 
			
		||||
			if(pluginEntitlements)
 | 
			
		||||
			{
 | 
			
		||||
				pluginDict[@"Entitlements"] = pluginEntitlements;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// Misc
 | 
			
		||||
 | 
			
		||||
			pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
 | 
			
		||||
			pluginDict[@"BundleNameIsLocalized"] = @1;
 | 
			
		||||
			pluginDict[@"CFBundleIdentifier"] = pluginBundleID;
 | 
			
		||||
			pluginDict[@"CodeInfoIdentifier"] = pluginBundleID;
 | 
			
		||||
			pluginDict[@"CompatibilityState"] = @0;
 | 
			
		||||
			if(pluginContainerPath)
 | 
			
		||||
			{
 | 
			
		||||
				pluginDict[@"Container"] = pluginContainerPath;
 | 
			
		||||
				pluginDict[@"EnvironmentVariables"] = constructEnvironmentVariablesForContainerPath(pluginContainerPath);
 | 
			
		||||
			}
 | 
			
		||||
			pluginDict[@"Path"] = pluginPath;
 | 
			
		||||
			pluginDict[@"PluginOwnerBundleID"] = appBundleID;
 | 
			
		||||
			pluginDict[@"IsContainerized"] = @(constructContainerizationForEntitlements(pluginEntitlements));
 | 
			
		||||
 | 
			
		||||
			NSString* pluginTeamIdentifier = constructTeamIdentifierForEntitlements(pluginEntitlements);
 | 
			
		||||
			if(pluginTeamIdentifier) pluginDict[@"TeamIdentifier"] = pluginTeamIdentifier;
 | 
			
		||||
 | 
			
		||||
			// Add plugin group containers
 | 
			
		||||
 | 
			
		||||
			NSDictionary* pluginAppGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO);
 | 
			
		||||
			NSDictionary* pluginSystemGroupContainers = constructGroupsContainersForEntitlements(pluginEntitlements, NO);
 | 
			
		||||
			NSMutableDictionary* pluginGroupContainers = [NSMutableDictionary new];
 | 
			
		||||
			[pluginGroupContainers addEntriesFromDictionary:pluginAppGroupContainers];
 | 
			
		||||
			[pluginGroupContainers addEntriesFromDictionary:pluginSystemGroupContainers];
 | 
			
		||||
			if(pluginGroupContainers.count)
 | 
			
		||||
			{
 | 
			
		||||
				if(pluginAppGroupContainers.count)
 | 
			
		||||
				{
 | 
			
		||||
					pluginDict[@"HasAppGroupContainers"] = @YES;
 | 
			
		||||
				}
 | 
			
		||||
				if(pluginSystemGroupContainers.count)
 | 
			
		||||
				{
 | 
			
		||||
					pluginDict[@"HasSystemGroupContainers"] = @YES;
 | 
			
		||||
				}
 | 
			
		||||
				pluginDict[@"GroupContainers"] = pluginGroupContainers.copy;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[bundlePlugins setObject:pluginDict forKey:pluginBundleID];
 | 
			
		||||
		}
 | 
			
		||||
		[dictToRegister setObject:bundlePlugins forKey:@"_LSBundlePlugins"];
 | 
			
		||||
 | 
			
		||||
		if(![workspace registerApplicationDictionary:dictToRegister])
 | 
			
		||||
		{
 | 
			
		||||
			NSLog(@"Error: Unable to register %@", path);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		NSURL* url = [NSURL fileURLWithPath:path];
 | 
			
		||||
		if(![workspace unregisterApplication:url])
 | 
			
		||||
		{
 | 
			
		||||
			NSLog(@"Error: Unable to unregister %@", path);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -285,6 +285,8 @@ int writeRemountPrivatePreboot(void)
 | 
			
		||||
    
 | 
			
		||||
    [self updateStatus:@"Done!"];
 | 
			
		||||
    
 | 
			
		||||
    NSLog(@"%@", helperOutput);
 | 
			
		||||
    
 | 
			
		||||
    // Print installed message
 | 
			
		||||
    if(ret == 0)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
@ -65,8 +65,9 @@ int IOGPU_get_command_queue_extra_refills_needed(void)
 | 
			
		||||
    || strstr(u.machine, "iPhone12,")
 | 
			
		||||
    || strstr(u.machine, "iPhone13,")
 | 
			
		||||
    || strstr(u.machine, "iPhone14,")
 | 
			
		||||
    || strstr(u.machine, "iPad13,")
 | 
			
		||||
    || strstr(u.machine, "iPad7,")
 | 
			
		||||
    || strstr(u.machine, "iPad12,")
 | 
			
		||||
    || strstr(u.machine, "iPad13,")
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        return 1;
 | 
			
		||||
@ -74,10 +75,12 @@ int IOGPU_get_command_queue_extra_refills_needed(void)
 | 
			
		||||
    // iPhone 8, X
 | 
			
		||||
    // iPhone XS, XR
 | 
			
		||||
    // iPad Pro A12Z
 | 
			
		||||
    // iPad 8 A12
 | 
			
		||||
    else if (
 | 
			
		||||
       strstr(u.machine, "iPhone10,")
 | 
			
		||||
    || strstr(u.machine, "iPhone11,")
 | 
			
		||||
    || strstr(u.machine, "iPad8,")
 | 
			
		||||
    || strstr(u.machine, "iPad11,")
 | 
			
		||||
    )
 | 
			
		||||
    {
 | 
			
		||||
        return 3;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								LICENSE
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								LICENSE
									
									
									
									
									
								
							@ -10,6 +10,7 @@ License: MIT
 | 
			
		||||
Files: Helper/uicache.m
 | 
			
		||||
Copyright: Copyright (c) 2019 CoolStar,
 | 
			
		||||
           Modified work Copyright (c) 2020-2022 Procursus Team <team@procurs.us>
 | 
			
		||||
           Modified work Copyright (c) 2022 Lars Fröder <opa334@protonmail.com>
 | 
			
		||||
License: BSD-4-Clause
 | 
			
		||||
 | 
			
		||||
Files: Installer/TrollInstaller/exploit
 | 
			
		||||
 | 
			
		||||
@ -52,7 +52,7 @@
 | 
			
		||||
		<string>iPhoneOS</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>1.0</string>
 | 
			
		||||
	<string>1.0.3</string>
 | 
			
		||||
	<key>LSRequiresIPhoneOS</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@ -76,6 +76,19 @@
 | 
			
		||||
			[refreshAppRegistrationsSpecifier setProperty:@YES forKey:@"enabled"];
 | 
			
		||||
			refreshAppRegistrationsSpecifier.buttonAction = @selector(refreshAppRegistrations);
 | 
			
		||||
			[_specifiers addObject:refreshAppRegistrationsSpecifier];
 | 
			
		||||
 | 
			
		||||
			PSSpecifier* uninstallTrollStoreSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall TrollStore"
 | 
			
		||||
										target:self
 | 
			
		||||
										set:nil
 | 
			
		||||
										get:nil
 | 
			
		||||
										detail:nil
 | 
			
		||||
										cell:PSButtonCell
 | 
			
		||||
										edit:nil];
 | 
			
		||||
			uninstallTrollStoreSpecifier.identifier = @"uninstallTrollStore";
 | 
			
		||||
			[uninstallTrollStoreSpecifier setProperty:@YES forKey:@"enabled"];
 | 
			
		||||
			[uninstallTrollStoreSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"];
 | 
			
		||||
			uninstallTrollStoreSpecifier.buttonAction = @selector(uninstallTrollStorePressed);
 | 
			
		||||
			[_specifiers addObject:uninstallTrollStoreSpecifier];
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
@ -201,6 +214,22 @@
 | 
			
		||||
	[downloadTask resume];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallTrollStorePressed
 | 
			
		||||
{
 | 
			
		||||
	UIAlertController* uninstallWarningAlert = [UIAlertController alertControllerWithTitle:@"Warning" message:@"About to uninstall TrollStore and all of the apps installed by it. Continue?" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
	
 | 
			
		||||
	UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
 | 
			
		||||
	[uninstallWarningAlert addAction:cancelAction];
 | 
			
		||||
 | 
			
		||||
	UIAlertAction* continueAction = [UIAlertAction actionWithTitle:@"Continue" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action)
 | 
			
		||||
	{
 | 
			
		||||
		spawnRoot(helperPath(), @[@"uninstall-trollstore"]);
 | 
			
		||||
		[self reloadSpecifiers];
 | 
			
		||||
	}];
 | 
			
		||||
	[uninstallWarningAlert addAction:continueAction];
 | 
			
		||||
 | 
			
		||||
	[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)uninstallPersistenceHelperPressed
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
Package: com.opa334.trollstorehelper
 | 
			
		||||
Name: TrollStore Helper
 | 
			
		||||
Version: 1.0
 | 
			
		||||
Version: 1.0.3
 | 
			
		||||
Architecture: iphoneos-arm
 | 
			
		||||
Description: Helper app to install and manage TrollStore!
 | 
			
		||||
Maintainer: opa334
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@
 | 
			
		||||
		<string>iPhoneOS</string>
 | 
			
		||||
	</array>
 | 
			
		||||
	<key>CFBundleVersion</key>
 | 
			
		||||
	<string>1.0.1</string>
 | 
			
		||||
	<string>1.0.3</string>
 | 
			
		||||
	<key>LSRequiresIPhoneOS</key>
 | 
			
		||||
	<true/>
 | 
			
		||||
	<key>UIDeviceFamily</key>
 | 
			
		||||
 | 
			
		||||
@ -14,6 +14,7 @@
 | 
			
		||||
- (NSString*)displayNameForAppPath:(NSString*)appPath;
 | 
			
		||||
 | 
			
		||||
- (NSError*)errorForCode:(int)code;
 | 
			
		||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force;
 | 
			
		||||
- (int)installIpa:(NSString*)pathToIpa;
 | 
			
		||||
- (int)uninstallApp:(NSString*)appId;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -67,7 +67,7 @@
 | 
			
		||||
        errorDescription = @"Failed to create container for app bundle.";
 | 
			
		||||
        break;
 | 
			
		||||
        case 171:
 | 
			
		||||
        errorDescription = @"A non-TrollStore app with the same identifier is already installed. If you are absolutely sure it is not, try refreshing icon cache in TrollStore settings or try rebooting your device.";
 | 
			
		||||
        errorDescription = @"A non-TrollStore app with the same identifier is already installed. If you are absolutely sure it is not, you can force install it.";
 | 
			
		||||
        break;
 | 
			
		||||
        case 172:
 | 
			
		||||
        errorDescription = @"The app does not seem to contain an Info.plist";
 | 
			
		||||
@ -78,13 +78,26 @@
 | 
			
		||||
    return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (int)installIpa:(NSString*)pathToIpa
 | 
			
		||||
- (int)installIpa:(NSString*)pathToIpa force:(BOOL)force
 | 
			
		||||
{
 | 
			
		||||
    int ret = spawnRoot(helperPath(), @[@"install", pathToIpa]);
 | 
			
		||||
    int ret;
 | 
			
		||||
    if(force)
 | 
			
		||||
    {
 | 
			
		||||
        ret = spawnRoot(helperPath(), @[@"install", pathToIpa, @"force"]);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        ret = spawnRoot(helperPath(), @[@"install", pathToIpa]);
 | 
			
		||||
    }
 | 
			
		||||
    [[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (int)installIpa:(NSString*)pathToIpa
 | 
			
		||||
{
 | 
			
		||||
    return [self installIpa:pathToIpa force:NO];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (int)uninstallApp:(NSString*)appId
 | 
			
		||||
{
 | 
			
		||||
    int ret = spawnRoot(helperPath(), @[@"uninstall", appId]);
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
 | 
			
		||||
@implementation TSSceneDelegate
 | 
			
		||||
 | 
			
		||||
- (void)handleURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts scene:(UIWindowScene*)scene
 | 
			
		||||
- (void)doIPAInstall:(NSString*)ipaPath scene:(UIWindowScene*)scene force:(BOOL)force completion:(void (^)(void))completion
 | 
			
		||||
{
 | 
			
		||||
    UIWindow* keyWindow = nil;
 | 
			
		||||
    for(UIWindow* window in scene.windows)
 | 
			
		||||
@ -17,6 +17,60 @@
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
    UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
 | 
			
		||||
    activityIndicator.hidesWhenStopped = YES;
 | 
			
		||||
    activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
 | 
			
		||||
    [activityIndicator startAnimating];
 | 
			
		||||
    [infoAlert.view addSubview:activityIndicator];
 | 
			
		||||
 | 
			
		||||
    [keyWindow.rootViewController presentViewController:infoAlert animated:YES completion:nil];
 | 
			
		||||
 | 
			
		||||
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
    {
 | 
			
		||||
        // Install IPA
 | 
			
		||||
        int ret = [[TSApplicationsManager sharedInstance] installIpa:ipaPath force:force];
 | 
			
		||||
        NSError* error = [[TSApplicationsManager sharedInstance] errorForCode:ret];
 | 
			
		||||
 | 
			
		||||
        NSLog(@"installed app! ret:%d, error: %@", ret, error);
 | 
			
		||||
        dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
        {
 | 
			
		||||
            [infoAlert dismissViewControllerAnimated:YES completion:^
 | 
			
		||||
            {
 | 
			
		||||
                if(ret != 0)
 | 
			
		||||
                {
 | 
			
		||||
                    UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                    UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
 | 
			
		||||
                    {
 | 
			
		||||
                        if(ret == 171)
 | 
			
		||||
                        {
 | 
			
		||||
                            completion();
 | 
			
		||||
                        }
 | 
			
		||||
                    }];
 | 
			
		||||
                    if(ret == 171)
 | 
			
		||||
                    {
 | 
			
		||||
                        UIAlertAction* forceInstallAction = [UIAlertAction actionWithTitle:@"Force Installation" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
 | 
			
		||||
                        {
 | 
			
		||||
                            [self doIPAInstall:ipaPath scene:scene force:YES completion:completion];
 | 
			
		||||
                        }];
 | 
			
		||||
                        [errorAlert addAction:forceInstallAction];
 | 
			
		||||
                    }
 | 
			
		||||
                    [errorAlert addAction:closeAction];
 | 
			
		||||
 | 
			
		||||
                    [keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if(ret != 171)
 | 
			
		||||
                {
 | 
			
		||||
                    completion();
 | 
			
		||||
                }
 | 
			
		||||
            }];
 | 
			
		||||
        });
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)handleURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts scene:(UIWindowScene*)scene
 | 
			
		||||
{
 | 
			
		||||
    for(UIOpenURLContext* context in URLContexts)
 | 
			
		||||
    {
 | 
			
		||||
        NSLog(@"openURLContexts %@", context.URL);
 | 
			
		||||
@ -39,43 +93,13 @@
 | 
			
		||||
                    respring();
 | 
			
		||||
                    exit(0);
 | 
			
		||||
                }
 | 
			
		||||
            };  
 | 
			
		||||
            };
 | 
			
		||||
            
 | 
			
		||||
            if ([url.pathExtension isEqualToString:@"ipa"])
 | 
			
		||||
            {
 | 
			
		||||
                UIAlertController* infoAlert = [UIAlertController alertControllerWithTitle:@"Installing" message:@"" preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
 | 
			
		||||
                activityIndicator.hidesWhenStopped = YES;
 | 
			
		||||
                activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
 | 
			
		||||
                [activityIndicator startAnimating];
 | 
			
		||||
                [infoAlert.view addSubview:activityIndicator];
 | 
			
		||||
 | 
			
		||||
                [keyWindow.rootViewController presentViewController:infoAlert animated:YES completion:nil];
 | 
			
		||||
 | 
			
		||||
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
 | 
			
		||||
                {
 | 
			
		||||
                    // Install IPA
 | 
			
		||||
                    int ret = [[TSApplicationsManager sharedInstance] installIpa:tmpCopyURL.path];
 | 
			
		||||
                    NSError* error = [[TSApplicationsManager sharedInstance] errorForCode:ret];
 | 
			
		||||
 | 
			
		||||
                    NSLog(@"installed app! ret:%d, error: %@", ret, error);
 | 
			
		||||
                    dispatch_async(dispatch_get_main_queue(), ^
 | 
			
		||||
                    {
 | 
			
		||||
                        [infoAlert dismissViewControllerAnimated:YES completion:^
 | 
			
		||||
                        {
 | 
			
		||||
                            if(ret != 0)
 | 
			
		||||
                            {
 | 
			
		||||
                                UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:[NSString stringWithFormat:@"Install Error %d", ret] message:[error localizedDescription] preferredStyle:UIAlertControllerStyleAlert];
 | 
			
		||||
                                UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
 | 
			
		||||
                                [errorAlert addAction:closeAction];
 | 
			
		||||
 | 
			
		||||
                                [keyWindow.rootViewController presentViewController:errorAlert animated:YES completion:nil];
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            doneBlock(NO);
 | 
			
		||||
                        }];
 | 
			
		||||
                    });
 | 
			
		||||
                });
 | 
			
		||||
                [self doIPAInstall:url.path scene:(UIWindowScene*)scene force:NO completion:^{
 | 
			
		||||
                    doneBlock(NO);
 | 
			
		||||
                }];
 | 
			
		||||
            }
 | 
			
		||||
            else if([url.pathExtension isEqualToString:@"tar"])
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
Package: com.opa334.trollstore
 | 
			
		||||
Name: TrollStore
 | 
			
		||||
Version: 1.0.1
 | 
			
		||||
Version: 1.0.3
 | 
			
		||||
Architecture: iphoneos-arm
 | 
			
		||||
Description: An awesome application!
 | 
			
		||||
Maintainer: opa334
 | 
			
		||||
 | 
			
		||||
@ -36,6 +36,8 @@ make clean
 | 
			
		||||
make package FINALPACKAGE=1
 | 
			
		||||
cd -
 | 
			
		||||
 | 
			
		||||
rm ../PersistenceHelper/Resources/trollstorehelper
 | 
			
		||||
 | 
			
		||||
cp ../PersistenceHelper/.theos/obj/TrollStorePersistenceHelper.app/TrollStorePersistenceHelper ./out/TrollStore.app/PersistenceHelper
 | 
			
		||||
ldid -S -M -Kcert.p12 ./out/TrollStore.app/PersistenceHelper
 | 
			
		||||
 | 
			
		||||
@ -45,3 +47,19 @@ cd out
 | 
			
		||||
COPYFILE_DISABLE=1 tar -czvf TrollStore.tar ./TrollStore.app
 | 
			
		||||
rm -rf ./TrollStore.app
 | 
			
		||||
cd -
 | 
			
		||||
 | 
			
		||||
# Step five: compile installer
 | 
			
		||||
xcodebuild -project ../Installer/TrollInstaller/TrollInstaller.xcodeproj -scheme TrollInstaller -destination generic/platform=iOS -archivePath ./out/Installer.xcarchive archive
 | 
			
		||||
 | 
			
		||||
if [[ -f "./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision" ]]; then
 | 
			
		||||
    rm ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app/embedded.mobileprovision
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
ldid -s ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app
 | 
			
		||||
mkdir ./out/Payload
 | 
			
		||||
mv ./out/Installer.xcarchive/Products/Applications/TrollInstaller.app ./out/Payload/TrollInstaller.app
 | 
			
		||||
cd out
 | 
			
		||||
zip -vr TrollInstaller.ipa Payload
 | 
			
		||||
cd -
 | 
			
		||||
rm -rf ./out/Payload
 | 
			
		||||
rm -rf ./out/Installer.xcarchive
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user