mirror of
https://github.com/opa334/TrollStore.git
synced 2026-07-02 03:00:39 +08:00
TrollStore 1.2, new build setup, deprecate installers in favor of TrollHelperOTA, add jailbreak guide, add better version compatibility notes
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
TARGET := iphone:clang:14.5:14.0
|
||||
ARCHS = arm64
|
||||
|
||||
include $(THEOS)/makefiles/common.mk
|
||||
|
||||
TOOL_NAME = trollstorehelper
|
||||
|
||||
trollstorehelper_FILES = $(wildcard *.m) $(wildcard ../Shared/*.m)
|
||||
trollstorehelper_CFLAGS = -fobjc-arc -I../Shared
|
||||
trollstorehelper_CODESIGN_FLAGS = -Sentitlements.plist -K../cert.p12
|
||||
trollstorehelper_INSTALL_PATH = /usr/local/bin
|
||||
trollstorehelper_LIBRARIES = archive
|
||||
trollstorehelper_PRIVATE_FRAMEWORKS = SpringBoardServices BackBoardServices
|
||||
|
||||
include $(THEOS_MAKE_PATH)/tool.mk
|
||||
@@ -0,0 +1,9 @@
|
||||
Package: com.opa334.trollstoreroothelper
|
||||
Name: trollstoreroothelper
|
||||
Version: 1.2
|
||||
Architecture: iphoneos-arm
|
||||
Description: An awesome tool of some sort!!
|
||||
Maintainer: opa334
|
||||
Author: opa334
|
||||
Section: System
|
||||
Tag: role::hacker
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>platform-application</key>
|
||||
<true/>
|
||||
<key>com.apple.private.security.container-required</key>
|
||||
<false/>
|
||||
<key>com.apple.security.exception.files.absolute-path.read-write</key>
|
||||
<array>
|
||||
<string>/</string>
|
||||
</array>
|
||||
<key>com.apple.private.security.container-manager</key>
|
||||
<true/>
|
||||
<key>com.apple.private.coreservices.canmaplsdatabase</key>
|
||||
<true/>
|
||||
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
|
||||
<true/>
|
||||
<key>com.apple.private.security.storage.AppBundles</key>
|
||||
<true/>
|
||||
<key>com.apple.private.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.backboardd.launchapplications</key>
|
||||
<true/>
|
||||
<key>com.apple.multitasking.termination</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
+1182
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,351 @@
|
||||
#import <stdio.h>
|
||||
#import "unarchive.h"
|
||||
@import Foundation;
|
||||
#import "uicache.h"
|
||||
#import <sys/stat.h>
|
||||
#import <dlfcn.h>
|
||||
#import <spawn.h>
|
||||
#import "path.h"
|
||||
#import "CoreServices.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer")
|
||||
|
||||
typedef CFPropertyListRef (*_CFPreferencesCopyValueWithContainerType)(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
|
||||
typedef void (*_CFPreferencesSetValueWithContainerType)(CFStringRef key, CFPropertyListRef value, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
|
||||
typedef Boolean (*_CFPreferencesSynchronizeWithContainerType)(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
|
||||
typedef CFArrayRef (*_CFPreferencesCopyKeyListWithContainerType)(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
|
||||
typedef CFDictionaryRef (*_CFPreferencesCopyMultipleWithContainerType)(CFArrayRef keysToFetch, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
|
||||
|
||||
extern char*** _NSGetArgv();
|
||||
NSString* safe_getExecutablePath()
|
||||
{
|
||||
char* executablePathC = **_NSGetArgv();
|
||||
return [NSString stringWithUTF8String:executablePathC];
|
||||
}
|
||||
|
||||
NSDictionary* infoDictionaryForAppPath(NSString* appPath)
|
||||
{
|
||||
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"];
|
||||
return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
|
||||
}
|
||||
|
||||
NSString* appIdForAppPath(NSString* appPath)
|
||||
{
|
||||
return infoDictionaryForAppPath(appPath)[@"CFBundleIdentifier"];
|
||||
}
|
||||
|
||||
NSString* appPathForAppId(NSString* appId, NSError** error)
|
||||
{
|
||||
NSString* appPath = [TROLLSTORE_APPLICATIONS_PATH stringByAppendingPathComponent:appId];
|
||||
|
||||
NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:appPath error:error];
|
||||
if(!items) return nil;
|
||||
|
||||
for(NSString* item in items)
|
||||
{
|
||||
if([item.pathExtension isEqualToString:@"app"])
|
||||
{
|
||||
return [appPath stringByAppendingPathComponent:item];
|
||||
}
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
static void dump_file_content(int fd)
|
||||
{
|
||||
ssize_t num_read;
|
||||
char line_buf[256];
|
||||
int cur_pos = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char c;
|
||||
num_read = read(fd, &c, sizeof(c));
|
||||
if(num_read <= 0)
|
||||
|
||||
if(c == '\n' || cur_pos >= 255 || num_read <= 0)
|
||||
{
|
||||
line_buf[cur_pos] = '\n';
|
||||
NSLog(@"%s", (char*)line_buf);
|
||||
if(c == '\n') cur_pos++;
|
||||
|
||||
if(num_read > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
line_buf[cur_pos++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL signApp(NSString* appPath, NSError** error)
|
||||
{
|
||||
NSString* ldidPath = [[safe_getExecutablePath() stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"ldid"];
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:ldidPath])
|
||||
{
|
||||
NSLog(@"WARNING: ldid not found, not signing application");
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSString* certPath = [TROLLSTORE_MAIN_PATH stringByAppendingPathComponent:@"TrollStore.app/cert.p12"];
|
||||
NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath];
|
||||
|
||||
int out[2];
|
||||
posix_spawn_file_actions_t action;
|
||||
posix_spawn_file_actions_init(&action);
|
||||
pipe(out);
|
||||
posix_spawn_file_actions_adddup2(&action, out[1], STDERR_FILENO);
|
||||
posix_spawn_file_actions_addclose(&action, out[0]);
|
||||
|
||||
char* args[] = { "ldid", "-S", "-M", (char*)certArg.UTF8String, (char*)appPath.UTF8String, NULL };
|
||||
|
||||
NSLog(@"%@ ldid -S -M %@ %@", ldidPath, certArg, appPath);
|
||||
|
||||
pid_t task_pid;
|
||||
int status = -200;
|
||||
int spawnError = posix_spawn(&task_pid, [ldidPath UTF8String], &action, NULL, args, NULL);
|
||||
|
||||
if(spawnError != 0)
|
||||
{
|
||||
NSLog(@"posix_spawn error %d\n", spawnError);
|
||||
return spawnError;
|
||||
}
|
||||
|
||||
waitpid(task_pid, &status, WEXITED);
|
||||
|
||||
NSLog(@"ldid exited with status %d", status);
|
||||
|
||||
waitpid(task_pid, &status, 0);
|
||||
|
||||
NSLog(@"ldid exited with status %d", status);
|
||||
|
||||
NSLog(@"ldid output:");
|
||||
|
||||
close(out[1]);
|
||||
dump_file_content(out[0]);
|
||||
|
||||
NSLog(@"end ldid output:");
|
||||
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
BOOL installApp(NSString* appPath, NSString* appId, BOOL sign, NSError** error)
|
||||
{
|
||||
if(sign)
|
||||
{
|
||||
// if it fails to sign, we don't care
|
||||
signApp(appPath, error);
|
||||
}
|
||||
|
||||
BOOL existed;
|
||||
NSError* mcmError;
|
||||
MCMAppContainer* appContainer = [objc_getClass("MCMAppContainer") containerWithIdentifier:appId createIfNecessary:YES existed:&existed error:&mcmError];
|
||||
NSLog(@"installApp appContainer: %@, mcmError: %@", appContainer, mcmError);
|
||||
if(!appContainer || mcmError)
|
||||
{
|
||||
if(error) *error = mcmError;
|
||||
return NO;
|
||||
}
|
||||
|
||||
//TODO: if TrollStore, preserve by moving it into appPath if needed ldid if needed
|
||||
|
||||
NSURL* trollStoreMarkURL = [appContainer.url URLByAppendingPathComponent:@"_TrollStore"];
|
||||
if(existed)
|
||||
{
|
||||
// trying to update an app not installed by TrollStore... bailing out
|
||||
if(![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil])
|
||||
{
|
||||
NSLog(@"installApp already installed and not a TrollStore app... bailing out");
|
||||
return NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
// update existing app... clean old app directory
|
||||
NSLog(@"installApp found existing TrollStore app, cleaning directory");
|
||||
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtURL:appContainer.url includingPropertiesForKeys:nil options:0 errorHandler:nil];
|
||||
NSURL* fileURL;
|
||||
while(fileURL = [enumerator nextObject])
|
||||
{
|
||||
[[NSFileManager defaultManager] removeItemAtURL:fileURL error:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[NSFileManager defaultManager] createFileAtPath:trollStoreMarkURL.path contents:[NSData data] attributes:nil];
|
||||
|
||||
NSString* newAppPath = [appContainer.url.path stringByAppendingPathComponent:appPath.lastPathComponent];
|
||||
|
||||
NSLog(@"installApp new app path: %@", newAppPath);
|
||||
|
||||
BOOL suc = [[NSFileManager defaultManager] copyItemAtPath:appPath toPath:newAppPath error:error];
|
||||
|
||||
NSLog(@"installApp copied app? %d, adding to uicache now...", suc);
|
||||
|
||||
registerPath((char*)newAppPath.UTF8String, 0);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
BOOL uninstallApp(NSString* appId, NSError** error)
|
||||
{
|
||||
NSString* appPath = appPathForAppId(appId, error);
|
||||
if(!appPath) return NO;
|
||||
|
||||
registerPath((char*)appPath.UTF8String, 1);
|
||||
|
||||
return [[NSFileManager defaultManager] removeItemAtPath:[appPath stringByDeletingLastPathComponent] error:error];
|
||||
}
|
||||
|
||||
BOOL installIpa(NSString* ipaPath, NSError** error)
|
||||
{
|
||||
BOOL suc = NO;
|
||||
NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
||||
|
||||
suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:error];
|
||||
if(!suc) return NO;
|
||||
|
||||
extract(ipaPath, tmpPath);
|
||||
|
||||
NSString* tmpPayloadPath = [tmpPath stringByAppendingPathComponent:@"Payload"];
|
||||
|
||||
NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpPayloadPath error:error];
|
||||
if(!items) return NO;
|
||||
|
||||
NSString* tmpAppPath;
|
||||
for(NSString* item in items)
|
||||
{
|
||||
if([item.pathExtension isEqualToString:@"app"])
|
||||
{
|
||||
tmpAppPath = [tmpPayloadPath stringByAppendingPathComponent:item];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!tmpAppPath) return NO;
|
||||
|
||||
NSString* appId = appIdForAppPath(tmpAppPath);
|
||||
|
||||
suc = installApp(tmpAppPath, appId, YES, error);
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:tmpAppPath error:nil];
|
||||
|
||||
return suc;
|
||||
}
|
||||
|
||||
void uninstallAllApps(void)
|
||||
{
|
||||
NSArray* items = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:TROLLSTORE_APPLICATIONS_PATH error:nil];
|
||||
for(NSString* appId in items)
|
||||
{
|
||||
NSString* appPath = appPathForAppId(appId, nil);
|
||||
registerPath((char*)appPath.UTF8String, 1);
|
||||
}
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:TROLLSTORE_ROOT_PATH error:nil];
|
||||
}
|
||||
|
||||
BOOL uninstallTrollStore(void)
|
||||
{
|
||||
NSString* trollStore = [TROLLSTORE_MAIN_PATH stringByAppendingPathComponent:@"TrollStore.app"];
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:trollStore]) return NO;
|
||||
|
||||
registerPath((char*)trollStore.UTF8String, 1);
|
||||
return [[NSFileManager defaultManager] removeItemAtPath:trollStore error:nil];
|
||||
}
|
||||
|
||||
BOOL installTrollStore(NSString* pathToTar)
|
||||
{
|
||||
_CFPreferencesSetValueWithContainerType _CFPreferencesSetValueWithContainer = (_CFPreferencesSetValueWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesSetValueWithContainer");
|
||||
_CFPreferencesSynchronizeWithContainerType _CFPreferencesSynchronizeWithContainer = (_CFPreferencesSynchronizeWithContainerType)dlsym(RTLD_DEFAULT, "_CFPreferencesSynchronizeWithContainer");
|
||||
_CFPreferencesSetValueWithContainer(CFSTR("SBShowNonDefaultSystemApps"), kCFBooleanTrue, CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
|
||||
_CFPreferencesSynchronizeWithContainer(CFSTR("com.apple.springboard"), CFSTR("mobile"), kCFPreferencesAnyHost, kCFPreferencesNoContainer);
|
||||
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:pathToTar]) return NO;
|
||||
if(![pathToTar.pathExtension isEqualToString:@"tar"]) return NO;
|
||||
|
||||
NSString* tmpPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString];
|
||||
BOOL suc = [[NSFileManager defaultManager] createDirectoryAtPath:tmpPath withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
if(!suc) return NO;
|
||||
|
||||
extract(pathToTar, tmpPath);
|
||||
|
||||
NSLog(@"installTrollStore extracted %@ to %@", pathToTar, tmpPath);
|
||||
|
||||
NSString* tmpTrollStore = [tmpPath stringByAppendingPathComponent:@"TrollStore.app"];
|
||||
if(![[NSFileManager defaultManager] fileExistsAtPath:tmpTrollStore]) return NO;
|
||||
|
||||
NSLog(@"installTrollStore temp TrollStore path: %@", tmpTrollStore);
|
||||
|
||||
NSString* tmpTrollStoreMain = [tmpTrollStore stringByAppendingPathComponent:@"TrollStore"];
|
||||
NSString* tmpTrollStoreRootHelper = [tmpTrollStore stringByAppendingPathComponent:@"trollstorehelper"];
|
||||
NSString* tmpTrollStoreLdid = [tmpTrollStore stringByAppendingPathComponent:@"ldid"];
|
||||
|
||||
// make executable
|
||||
chmod(tmpTrollStoreMain.UTF8String, 0755);
|
||||
chmod(tmpTrollStoreRootHelper.UTF8String, 0755);
|
||||
chmod(tmpTrollStoreLdid.UTF8String, 0755);
|
||||
|
||||
// set owners
|
||||
chown(tmpTrollStoreMain.UTF8String, 33, 33);
|
||||
chown(tmpTrollStoreRootHelper.UTF8String, 0, 0); // set root helper binary owner to root
|
||||
chown(tmpTrollStoreLdid.UTF8String, 0, 0);
|
||||
|
||||
NSLog(@"installTrollStore extracted and prepared TrollStore app, now installing...");
|
||||
|
||||
installApp(tmpTrollStore, @"com.apple.TrollStore", NO, nil);
|
||||
|
||||
[[NSFileManager defaultManager] removeItemAtPath:tmpPath error:nil];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[]) {
|
||||
@autoreleasepool {
|
||||
if(argc <= 1) return -1;
|
||||
|
||||
NSLog(@"trollstore helper go, uid: %d, gid: %d", getuid(), getgid());
|
||||
NSLog(@"ok %d", argc);
|
||||
|
||||
NSBundle* mcmBundle = [NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/MobileContainerManager.framework"];
|
||||
[mcmBundle load];
|
||||
|
||||
BOOL suc = NO;
|
||||
NSError* error;
|
||||
|
||||
NSString* cmd = [NSString stringWithUTF8String:argv[1]];
|
||||
if([cmd isEqualToString:@"install"])
|
||||
{
|
||||
if(argc <= 2) return -2;
|
||||
NSString* ipaPath = [NSString stringWithUTF8String:argv[2]];
|
||||
suc = installIpa(ipaPath, &error);
|
||||
} else if([cmd isEqualToString:@"uninstall"])
|
||||
{
|
||||
if(argc <= 2) return -2;
|
||||
NSString* appId = [NSString stringWithUTF8String:argv[2]];
|
||||
suc = uninstallApp(appId, &error);
|
||||
} else if([cmd isEqualToString:@"install-trollstore"])
|
||||
{
|
||||
if(argc <= 2) return -2;
|
||||
NSString* tsTar = [NSString stringWithUTF8String:argv[2]];
|
||||
suc = installTrollStore(tsTar);
|
||||
NSLog(@"installed troll store? %d", suc);
|
||||
} else if([cmd isEqualToString:@"uninstall-trollstore"])
|
||||
{
|
||||
uninstallTrollStore();
|
||||
uninstallAllApps();
|
||||
}
|
||||
|
||||
if(!suc)
|
||||
{
|
||||
NSLog(@"error: %@", error);
|
||||
}
|
||||
|
||||
return !suc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
extern void registerPath(char *path, int unregister);
|
||||
@@ -0,0 +1,260 @@
|
||||
@import Foundation;
|
||||
@import CoreServices;
|
||||
#import "CoreServices.h"
|
||||
#import <objc/runtime.h>
|
||||
#import "dlfcn.h"
|
||||
|
||||
// uicache on steroids
|
||||
|
||||
extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath);
|
||||
|
||||
NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups)
|
||||
{
|
||||
if(!entitlements) return nil;
|
||||
|
||||
NSString* entitlementForGroups;
|
||||
NSString* mcmClass;
|
||||
if(systemGroups)
|
||||
{
|
||||
entitlementForGroups = @"com.apple.security.system-groups";
|
||||
mcmClass = @"MCMSystemDataContainer";
|
||||
}
|
||||
else
|
||||
{
|
||||
entitlementForGroups = @"com.apple.security.application-groups";
|
||||
mcmClass = @"MCMSharedDataContainer";
|
||||
}
|
||||
|
||||
NSArray* groupIDs = entitlements[entitlementForGroups];
|
||||
if(groupIDs && [groupIDs isKindOfClass:[NSArray class]])
|
||||
{
|
||||
NSMutableDictionary* groupContainers = [NSMutableDictionary new];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return groupContainers.copy;
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
BOOL constructContainerizationForEntitlements(NSDictionary* entitlements)
|
||||
{
|
||||
NSNumber* noContainer = entitlements[@"com.apple.private.security.no-container"];
|
||||
if(noContainer && [noContainer isKindOfClass:[NSNumber class]])
|
||||
{
|
||||
if(noContainer.boolValue)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
NSNumber* containerRequired = entitlements[@"com.apple.private.security.container-required"];
|
||||
if(containerRequired && [containerRequired isKindOfClass:[NSNumber class]])
|
||||
{
|
||||
if(!containerRequired.boolValue)
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSString* constructTeamIdentifierForEntitlements(NSDictionary* entitlements)
|
||||
{
|
||||
NSString* teamIdentifier = entitlements[@"com.apple.developer.team-identifier"];
|
||||
if(teamIdentifier && [teamIdentifier isKindOfClass:[NSString class]])
|
||||
{
|
||||
return teamIdentifier;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
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 = dumpEntitlementsFromBinaryAtPath(appExecutablePath);
|
||||
if(entitlements)
|
||||
{
|
||||
dictToRegister[@"Entitlements"] = entitlements;
|
||||
}
|
||||
|
||||
// Misc
|
||||
|
||||
dictToRegister[@"ApplicationType"] = @"System";
|
||||
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));
|
||||
dictToRegister[@"SignerOrganization"] = @"Apple Inc.";
|
||||
dictToRegister[@"SignatureVersion"] = @132352;
|
||||
dictToRegister[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
|
||||
dictToRegister[@"IsAdHocSigned"] = @YES;
|
||||
dictToRegister[@"LSInstallType"] = @1;
|
||||
dictToRegister[@"HasMIDBasedSINF"] = @0;
|
||||
dictToRegister[@"MissingSINF"] = @0;
|
||||
dictToRegister[@"FamilyID"] = @0;
|
||||
dictToRegister[@"IsOnDemandInstallCapable"] = @0;
|
||||
|
||||
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 = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath);
|
||||
if(pluginEntitlements)
|
||||
{
|
||||
pluginDict[@"Entitlements"] = pluginEntitlements;
|
||||
}
|
||||
|
||||
// Misc
|
||||
|
||||
pluginDict[@"ApplicationType"] = @"PluginKitPlugin";
|
||||
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));
|
||||
pluginDict[@"SignerOrganization"] = @"Apple Inc.";
|
||||
pluginDict[@"SignatureVersion"] = @132352;
|
||||
pluginDict[@"SignerIdentity"] = @"Apple iPhone OS Application Signing";
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
@import Foundation;
|
||||
|
||||
extern int extract(NSString* fileToExtract, NSString* extractionPath);
|
||||
@@ -0,0 +1,87 @@
|
||||
#import "unarchive.h"
|
||||
|
||||
#include <libarchive/archive.h>
|
||||
#include <libarchive/archive_entry.h>
|
||||
|
||||
static int
|
||||
copy_data(struct archive *ar, struct archive *aw)
|
||||
{
|
||||
int r;
|
||||
const void *buff;
|
||||
size_t size;
|
||||
la_int64_t offset;
|
||||
|
||||
for (;;) {
|
||||
r = archive_read_data_block(ar, &buff, &size, &offset);
|
||||
if (r == ARCHIVE_EOF)
|
||||
return (ARCHIVE_OK);
|
||||
if (r < ARCHIVE_OK)
|
||||
return (r);
|
||||
r = archive_write_data_block(aw, buff, size, offset);
|
||||
if (r < ARCHIVE_OK) {
|
||||
fprintf(stderr, "%s\n", archive_error_string(aw));
|
||||
return (r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int extract(NSString* fileToExtract, NSString* extractionPath)
|
||||
{
|
||||
struct archive *a;
|
||||
struct archive *ext;
|
||||
struct archive_entry *entry;
|
||||
int flags;
|
||||
int r;
|
||||
|
||||
/* Select which attributes we want to restore. */
|
||||
flags = ARCHIVE_EXTRACT_TIME;
|
||||
flags |= ARCHIVE_EXTRACT_PERM;
|
||||
flags |= ARCHIVE_EXTRACT_ACL;
|
||||
flags |= ARCHIVE_EXTRACT_FFLAGS;
|
||||
|
||||
a = archive_read_new();
|
||||
archive_read_support_format_all(a);
|
||||
archive_read_support_filter_all(a);
|
||||
ext = archive_write_disk_new();
|
||||
archive_write_disk_set_options(ext, flags);
|
||||
archive_write_disk_set_standard_lookup(ext);
|
||||
if ((r = archive_read_open_filename(a, fileToExtract.UTF8String, 10240)))
|
||||
return 1;
|
||||
for (;;)
|
||||
{
|
||||
r = archive_read_next_header(a, &entry);
|
||||
if (r == ARCHIVE_EOF)
|
||||
break;
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(a));
|
||||
if (r < ARCHIVE_WARN)
|
||||
return 1;
|
||||
|
||||
NSString* currentFile = [NSString stringWithUTF8String:archive_entry_pathname(entry)];
|
||||
NSString* fullOutputPath = [extractionPath stringByAppendingPathComponent:currentFile];
|
||||
//printf("extracting %s to %s\n", currentFile.UTF8String, fullOutputPath.UTF8String);
|
||||
archive_entry_set_pathname(entry, fullOutputPath.UTF8String);
|
||||
|
||||
r = archive_write_header(ext, entry);
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(ext));
|
||||
else if (archive_entry_size(entry) > 0) {
|
||||
r = copy_data(a, ext);
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN)
|
||||
return 1;
|
||||
}
|
||||
r = archive_write_finish_entry(ext);
|
||||
if (r < ARCHIVE_OK)
|
||||
fprintf(stderr, "%s\n", archive_error_string(ext));
|
||||
if (r < ARCHIVE_WARN)
|
||||
return 1;
|
||||
}
|
||||
archive_read_close(a);
|
||||
archive_read_free(a);
|
||||
archive_write_close(ext);
|
||||
archive_write_free(ext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user