add project

This commit is contained in:
opa334
2022-09-02 17:19:48 +02:00
commit 057bd1a45f
166 changed files with 8422 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
TARGET := iphone:clang:14.5:14.0
INSTALL_TARGET_PROCESSES = TrollStore
include $(THEOS)/makefiles/common.mk
APPLICATION_NAME = TrollStore
TrollStore_FILES = $(wildcard *.m) ../Helper/Shared.m
TrollStore_FRAMEWORKS = UIKit CoreGraphics CoreServices
TrollStore_PRIVATE_FRAMEWORKS = Preferences
TrollStore_CFLAGS = -fobjc-arc
TrollStore_CODESIGN_FLAGS = -Sentitlements.plist
include $(THEOS_MAKE_PATH)/application.mk
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

+225
View File
@@ -0,0 +1,225 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>TrollStore</string>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon29x29</string>
<string>AppIcon40x40</string>
<string>AppIcon57x57</string>
<string>AppIcon60x60</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
</dict>
<key>CFBundleIcons~ipad</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon29x29</string>
<string>AppIcon40x40</string>
<string>AppIcon57x57</string>
<string>AppIcon60x60</string>
<string>AppIcon50x50</string>
<string>AppIcon72x72</string>
<string>AppIcon76x76</string>
</array>
<key>UIPrerenderedIcon</key>
<true/>
</dict>
</dict>
<key>CFBundleIdentifier</key>
<string>com.opa334.TrollStore</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleSupportedPlatforms</key>
<array>
<string>iPhoneOS</string>
</array>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIDeviceFamily</key>
<array>
<integer>1</integer>
<integer>2</integer>
</array>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UILaunchImageFile</key>
<string>LaunchImage</string>
<key>UILaunchImages</key>
<array>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 480}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage-700-568h</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{320, 568}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage-Portrait</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>7.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage-Landscape</string>
<key>UILaunchImageOrientation</key>
<string>Landscape</string>
<key>UILaunchImageSize</key>
<string>{768, 1024}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>8.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage-800-667h</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{375, 667}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>8.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage-800-Portrait-736h</string>
<key>UILaunchImageOrientation</key>
<string>Portrait</string>
<key>UILaunchImageSize</key>
<string>{414, 736}</string>
</dict>
<dict>
<key>UILaunchImageMinimumOSVersion</key>
<string>8.0</string>
<key>UILaunchImageName</key>
<string>LaunchImage-800-Landscape-736h</string>
<key>UILaunchImageOrientation</key>
<string>Landscape</string>
<key>UILaunchImageSize</key>
<string>{414, 736}</string>
</dict>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>TSSceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UTImportedTypeDeclarations</key>
<array>
<dict>
<key>UTTypeConformsTo</key>
<array>
<string>public.data</string>
</array>
<key>UTTypeDescription</key>
<string>iOS App</string>
<key>UTTypeIconFiles</key>
<array/>
<key>UTTypeIdentifier</key>
<string>com.apple.itunes.ipa</string>
<key>UTTypeTagSpecification</key>
<dict>
<key>public.filename-extension</key>
<array>
<string>ipa</string>
</array>
<key>public.mime-type</key>
<array/>
</dict>
</dict>
</array>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>iOS App</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key>
<array>
<string>com.apple.itunes.ipa</string>
</array>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>TrollStore Update</string>
<key>LSHandlerRank</key>
<string>Default</string>
<key>LSItemContentTypes</key>
<array>
<string>public.tar-archive</string>
</array>
</dict>
</array>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>TSRootBinaries</key>
<array>
<string>trollstorehelper</string>
<string>ldid</string>
</array>
</dict>
</plist>
View File
View File
Binary file not shown.
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>TROLLTROLL.*</string>
<key>com.apple.developer.team-identifier</key>
<string>TROLLTROLL</string>
<key>get-task-allow</key>
<true/>
<key>keychain-access-groups</key>
<array>
<string>TROLLTROLL.*</string>
<string>com.apple.token</string>
</array>
</dict>
</plist>
+5
View File
@@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>
@interface TSAppDelegate : UIResponder <UIApplicationDelegate>
@end
+23
View File
@@ -0,0 +1,23 @@
#import "TSAppDelegate.h"
#import "TSRootViewController.h"
@implementation TSAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
return YES;
}
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
@end
+5
View File
@@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>
@interface TSAppTableViewController : UITableViewController
@end
+59
View File
@@ -0,0 +1,59 @@
#import "TSAppTableViewController.h"
#import "TSApplicationsManager.h"
@implementation TSAppTableViewController
- (void)reloadTable
{
[self.tableView reloadData];
}
- (void)loadView
{
[super loadView];
[self.tableView registerClass:UITableViewCell.class forCellReuseIdentifier:@"ApplicationCell"];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(reloadTable)
name:@"ApplicationsChanged"
object:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.allowsMultipleSelectionDuringEditing = NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[TSApplicationsManager sharedInstance] installedAppPaths].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ApplicationCell" forIndexPath:indexPath];
NSString* appPath = [[TSApplicationsManager sharedInstance] installedAppPaths][indexPath.row];
// Configure the cell...
cell.textLabel.text = [[TSApplicationsManager sharedInstance] displayNameForAppPath:appPath];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
NSString* appPath = [[TSApplicationsManager sharedInstance] installedAppPaths][indexPath.row];
NSString* appId = [[TSApplicationsManager sharedInstance] appIdForAppPath:appPath];
[[TSApplicationsManager sharedInstance] uninstallApp:appId error:nil];
}
}
@end
+19
View File
@@ -0,0 +1,19 @@
#import <Foundation/Foundation.h>
#define TROLLSTORE_ROOT_PATH @"/var/containers/Bundle/TrollStore"
#define TROLLSTORE_MAIN_PATH [TROLLSTORE_ROOT_PATH stringByAppendingPathComponent:@"Main"]
#define TROLLSTORE_APPLICATIONS_PATH [TROLLSTORE_ROOT_PATH stringByAppendingPathComponent:@"Applications"]
@interface TSApplicationsManager : NSObject
+ (instancetype)sharedInstance;
- (NSArray*)installedAppPaths;
- (NSDictionary*)infoDictionaryForAppPath:(NSString*)appPath;
- (NSString*)appIdForAppPath:(NSString*)appPath;
- (NSString*)displayNameForAppPath:(NSString*)appPath;
- (int)installIpa:(NSString*)pathToIpa error:(NSError**)error;
- (int)uninstallApp:(NSString*)appId error:(NSError**)error;
@end
+67
View File
@@ -0,0 +1,67 @@
#import "TSApplicationsManager.h"
#import "TSUtil.h"
#import "../Helper/Shared.h"
@implementation TSApplicationsManager
+ (instancetype)sharedInstance
{
static TSApplicationsManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[TSApplicationsManager alloc] init];
});
return sharedInstance;
}
- (NSArray*)installedAppPaths
{
return trollStoreInstalledAppBundlePaths();
}
- (NSDictionary*)infoDictionaryForAppPath:(NSString*)appPath
{
NSString* infoPlistPath = [appPath stringByAppendingPathComponent:@"Info.plist"];
return [NSDictionary dictionaryWithContentsOfFile:infoPlistPath];
}
- (NSString*)appIdForAppPath:(NSString*)appPath
{
return [self infoDictionaryForAppPath:appPath][@"CFBundleIdentifier"];
}
- (NSString*)displayNameForAppPath:(NSString*)appPath
{
NSDictionary* infoDict = [self infoDictionaryForAppPath:appPath];
NSString* displayName = infoDict[@"CFBundleDisplayName"];
if(![displayName isKindOfClass:[NSString class]]) displayName = nil;
if(!displayName || [displayName isEqualToString:@""])
{
displayName = infoDict[@"CFBundleName"];
if(![displayName isKindOfClass:[NSString class]]) displayName = nil;
if(!displayName || [displayName isEqualToString:@""])
{
displayName = infoDict[@"CFBundleExecutable"];
if(![displayName isKindOfClass:[NSString class]]) displayName = [appPath lastPathComponent];
}
}
return displayName;
}
- (int)installIpa:(NSString*)pathToIpa error:(NSError**)error
{
int ret = spawnRoot(helperPath(), @[@"install", pathToIpa]) == 0;
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret;
}
- (int)uninstallApp:(NSString*)appId error:(NSError**)error
{
int ret = spawnRoot(helperPath(), @[@"uninstall", appId]) == 0;
[[NSNotificationCenter defaultCenter] postNotificationName:@"ApplicationsChanged" object:nil];
return ret;
}
@end
+5
View File
@@ -0,0 +1,5 @@
#import <UIKit/UIKit.h>
@interface TSRootViewController : UITabBarController
@end
+26
View File
@@ -0,0 +1,26 @@
#import "TSRootViewController.h"
#import "TSAppTableViewController.h"
#import "TSSettingsListController.h"
@implementation TSRootViewController
- (void)loadView {
[super loadView];
TSAppTableViewController* appTableVC = [[TSAppTableViewController alloc] init];
appTableVC.title = @"Apps";
TSSettingsListController* settingsListVC = [[TSSettingsListController alloc] init];
settingsListVC.title = @"Settings";
UINavigationController* appNavigationController = [[UINavigationController alloc] initWithRootViewController:appTableVC];
UINavigationController* settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsListVC];
appNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"square.stack.3d.up.fill"];
settingsNavigationController.tabBarItem.image = [UIImage systemImageNamed:@"gear"];
self.title = @"Root View Controller";
self.viewControllers = @[appNavigationController, settingsNavigationController];
}
@end
+6
View File
@@ -0,0 +1,6 @@
#import <UIKit/UIKit.h>
@interface TSSceneDelegate : UIResponder <UIWindowSceneDelegate>
@property (strong, nonatomic) UIWindow * window;
@property (nonatomic, strong) UITabBarController *rootViewController;
@end
+109
View File
@@ -0,0 +1,109 @@
#import "TSSceneDelegate.h"
#import "TSRootViewController.h"
#import "TSUtil.h"
#import "TSApplicationsManager.h"
@implementation TSSceneDelegate
- (void)handleURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{
for(UIOpenURLContext* context in URLContexts)
{
NSLog(@"openURLContexts %@", context.URL);
NSURL* url = context.URL;
if (url != nil && [url isFileURL]) {
BOOL shouldExit = NO;
[url startAccessingSecurityScopedResource];
NSURL* tmpCopyURL = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:url.lastPathComponent]];
[[NSFileManager defaultManager] copyItemAtURL:url toURL:tmpCopyURL error:nil];
if ([url.pathExtension isEqualToString:@"ipa"]) {
// Install IPA
NSError* error;
int ret = [[TSApplicationsManager sharedInstance] installIpa:tmpCopyURL.path error:&error];
NSLog(@"installed app! ret:%d, error: %@", ret, error);
}
else if([url.pathExtension isEqualToString:@"tar"])
{
// Update TrollStore itself
NSLog(@"Updating TrollStore...");
int ret = spawnRoot(helperPath(), @[@"install-trollstore", tmpCopyURL.path]);
if(ret == 0) shouldExit = YES;
NSLog(@"Updated TrollStore!");
}
[[NSFileManager defaultManager] removeItemAtURL:tmpCopyURL error:nil];
[url stopAccessingSecurityScopedResource];
if(shouldExit)
{
NSLog(@"Respring + Exit");
respring();
exit(0);
}
}
}
}
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
NSLog(@"scene:%@ willConnectToSession:%@ options:%@", scene, session, connectionOptions);
if(connectionOptions.URLContexts.count)
{
[self handleURLContexts:connectionOptions.URLContexts];
}
UIWindowScene* windowScene = (UIWindowScene*)scene;
_window = [[UIWindow alloc] initWithWindowScene:windowScene];
_rootViewController = [[TSRootViewController alloc] init];
_window.rootViewController = _rootViewController;
[_window makeKeyAndVisible];
}
- (void)sceneDidDisconnect:(UIScene *)scene {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
- (void)sceneDidBecomeActive:(UIScene *)scene {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
- (void)sceneWillResignActive:(UIScene *)scene {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
- (void)sceneWillEnterForeground:(UIScene *)scene {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
- (void)sceneDidEnterBackground:(UIScene *)scene {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts
{
NSLog(@"scene:%@ openURLContexts:%@", scene, URLContexts);
[self handleURLContexts:URLContexts];
}
@end
+9
View File
@@ -0,0 +1,9 @@
#import <Preferences/PSListController.h>
#import <Preferences/PSSpecifier.h>
@interface TSSettingsListController : PSListController
{
UIAlertController* _activityController;
PSSpecifier* _installPersistenceHelperSpecifier;
}
@end
+336
View File
@@ -0,0 +1,336 @@
#import "TSSettingsListController.h"
#import "TSUtil.h"
#import <Preferences/PSSpecifier.h>
#import "../Helper/CoreServices.h"
#import "../Helper/Shared.h"
@implementation TSSettingsListController
- (void)loadView
{
[super loadView];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadSpecifiers) name:UIApplicationWillEnterForegroundNotification object:nil];
}
- (void)startActivity:(NSString*)activity
{
if(_activityController) return;
_activityController = [UIAlertController alertControllerWithTitle:activity message:@"" preferredStyle:UIAlertControllerStyleAlert];
UIActivityIndicatorView* activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(5,5,50,50)];
activityIndicator.hidesWhenStopped = YES;
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleMedium;
[activityIndicator startAnimating];
[_activityController.view addSubview:activityIndicator];
[self presentViewController:_activityController animated:YES completion:nil];
}
- (void)stopActivityWithCompletion:(void (^)(void))completion
{
if(!_activityController) return;
[_activityController dismissViewControllerAnimated:YES completion:^
{
_activityController = nil;
if(completion)
{
completion();
}
}];
}
- (NSMutableArray*)specifiers
{
if(!_specifiers)
{
_specifiers = [NSMutableArray new];
PSSpecifier* utilitiesGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
utilitiesGroupSpecifier.name = @"Utilities";
[utilitiesGroupSpecifier setProperty:@"If an app does not immediately appear after installation, respring here and it should appear afterwards." forKey:@"footerText"];
[_specifiers addObject:utilitiesGroupSpecifier];
PSSpecifier* respringButtonSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Respring"
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
respringButtonSpecifier.identifier = @"respring";
[respringButtonSpecifier setProperty:@YES forKey:@"enabled"];
respringButtonSpecifier.buttonAction = @selector(respringButtonPressed);
[_specifiers addObject:respringButtonSpecifier];
PSSpecifier* rebuildIconCacheSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Rebuild Icon Cache"
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
rebuildIconCacheSpecifier.identifier = @"uicache";
[rebuildIconCacheSpecifier setProperty:@YES forKey:@"enabled"];
rebuildIconCacheSpecifier.buttonAction = @selector(rebuildIconCachePressed);
[_specifiers addObject:rebuildIconCacheSpecifier];
NSString* ldidPath = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"ldid"];
BOOL ldidInstalled = [[NSFileManager defaultManager] fileExistsAtPath:ldidPath];
PSSpecifier* signingGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
signingGroupSpecifier.name = @"Signing";
if(ldidInstalled)
{
[signingGroupSpecifier setProperty:@"ldid is installed and allows TrollStore to install unsigned IPA files." forKey:@"footerText"];
}
else
{
[signingGroupSpecifier setProperty:@"In order for TrollStore to be able to install unsigned IPAs, ldid has to be installed using this button. It can't be directly included in TrollStore because of licensing issues." forKey:@"footerText"];
}
[_specifiers addObject:signingGroupSpecifier];
if(ldidInstalled)
{
PSSpecifier* ldidInstalledSpecifier = [PSSpecifier preferenceSpecifierNamed:@"ldid: Installed"
target:self
set:nil
get:nil
detail:nil
cell:PSStaticTextCell
edit:nil];
ldidInstalledSpecifier.identifier = @"ldidInstalled";
[_specifiers addObject:ldidInstalledSpecifier];
}
else
{
PSSpecifier* installLdidSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Install ldid"
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
installLdidSpecifier.identifier = @"ldidInstalled";
[installLdidSpecifier setProperty:@YES forKey:@"enabled"];
installLdidSpecifier.buttonAction = @selector(installLdidPressed);
[_specifiers addObject:installLdidSpecifier];
}
PSSpecifier* persistenceGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
persistenceGroupSpecifier.name = @"Persistence";
[_specifiers addObject:persistenceGroupSpecifier];
if([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/TrollStorePersistenceHelper.app"])
{
[persistenceGroupSpecifier setProperty:@"When iOS rebuilds the icon cache, all TrollStore apps including TrollStore itself will be reverted to \"User\" state and either disappear or no longer launch. If that happens, you can use the TrollHelper app on the home screen to refresh the app registrations, which will make them work again." forKey:@"footerText"];
PSSpecifier* installedPersistenceHelperSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Helper Installed as Standalone App"
target:self
set:nil
get:nil
detail:nil
cell:PSStaticTextCell
edit:nil];
installedPersistenceHelperSpecifier.identifier = @"persistenceHelperInstalled";
[_specifiers addObject:installedPersistenceHelperSpecifier];
}
else
{
LSApplicationProxy* persistenceApp = findPersistenceHelperApp();
if(persistenceApp)
{
NSString* appName = [persistenceApp localizedName];
[persistenceGroupSpecifier setProperty:[NSString stringWithFormat:@"When iOS rebuilds the icon cache, all TrollStore apps including TrollStore itself will be reverted to \"User\" state and either disappear or no longer launch. If that happens, you can use the persistence helper installed into %@ to refresh the app registrations, which will make them work again.", appName] forKey:@"footerText"];
PSSpecifier* installedPersistenceHelperSpecifier = [PSSpecifier preferenceSpecifierNamed:[NSString stringWithFormat:@"Helper Installed into %@", appName]
target:self
set:nil
get:nil
detail:nil
cell:PSStaticTextCell
edit:nil];
installedPersistenceHelperSpecifier.identifier = @"persistenceHelperInstalled";
[_specifiers addObject:installedPersistenceHelperSpecifier];
PSSpecifier* uninstallPersistenceHelperSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Uninstall Persistence Helper"
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
uninstallPersistenceHelperSpecifier.identifier = @"uninstallPersistenceHelper";
[uninstallPersistenceHelperSpecifier setProperty:@YES forKey:@"enabled"];
[uninstallPersistenceHelperSpecifier setProperty:NSClassFromString(@"PSDeleteButtonCell") forKey:@"cellClass"];
uninstallPersistenceHelperSpecifier.buttonAction = @selector(uninstallPersistenceHelperPressed);
[_specifiers addObject:uninstallPersistenceHelperSpecifier];
}
else
{
[persistenceGroupSpecifier setProperty:@"When iOS rebuilds the icon cache, all TrollStore apps including TrollStore itself will be reverted to \"User\" state and either disappear or no longer launch. The only way to have persistence in a rootless environment is to replace a system application, here you can select a system app to replace with a persistence helper that can be used to refresh the registrations of all TrollStore related apps in case they disappear or no longer launch." forKey:@"footerText"];
_installPersistenceHelperSpecifier = [PSSpecifier preferenceSpecifierNamed:@"Install Persistence Helper"
target:self
set:nil
get:nil
detail:nil
cell:PSButtonCell
edit:nil];
_installPersistenceHelperSpecifier.identifier = @"installPersistenceHelper";
[_installPersistenceHelperSpecifier setProperty:@YES forKey:@"enabled"];
_installPersistenceHelperSpecifier.buttonAction = @selector(installPersistenceHelperPressed);
[_specifiers addObject:_installPersistenceHelperSpecifier];
}
}
PSSpecifier* otherGroupSpecifier = [PSSpecifier emptyGroupSpecifier];
[otherGroupSpecifier setProperty:[NSString stringWithFormat:@"TrollStore %@\n\n© 2022 Lars Fröder (opa334)\n\nCredits:\n@LinusHenze: CoreTrust bug\n@zhuowei: CoreTrust bug writeup and cert\n@ProcursusTeam: uicache and ldid build\n@cstar_ow: uicache\n@saurik: ldid", getTrollStoreVersion()] forKey:@"footerText"];
[_specifiers addObject:otherGroupSpecifier];
// Uninstall TrollStore
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];
}
[(UINavigationItem *)self.navigationItem setTitle:@"Settings"];
return _specifiers;
}
- (void)respringButtonPressed
{
respring();
}
- (void)rebuildIconCachePressed
{
[self startActivity:@"Rebuilding Icon Cache"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
{
spawnRoot(helperPath(), @[@"refresh-all"]);
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:nil];
});
});
}
- (void)installLdidPressed
{
NSURL* ldidURL = [NSURL URLWithString:@"https://github.com/opa334/ldid/releases/download/v2.1.5-procursus5/ldid"];
NSURLRequest* ldidRequest = [NSURLRequest requestWithURL:ldidURL];
[self startActivity:@"Installing ldid"];
NSURLSessionDownloadTask* downloadTask = [NSURLSession.sharedSession downloadTaskWithRequest:ldidRequest completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error)
{
if(error)
{
UIAlertController* errorAlert = [UIAlertController alertControllerWithTitle:@"Error" message:[NSString stringWithFormat:@"Error downloading ldid: %@", error] preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* closeAction = [UIAlertAction actionWithTitle:@"Close" style:UIAlertActionStyleDefault handler:nil];
[errorAlert addAction:closeAction];
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:^
{
[self presentViewController:errorAlert animated:YES completion:nil];
}];
});
}
else
{
spawnRoot(helperPath(), @[@"install-ldid", location.path]);
dispatch_async(dispatch_get_main_queue(), ^
{
[self stopActivityWithCompletion:nil];
[self reloadSpecifiers];
});
}
}];
[downloadTask resume];
}
- (void)installPersistenceHelperPressed
{
NSMutableArray* appCandidates = [NSMutableArray new];
[[LSApplicationWorkspace defaultWorkspace] enumerateApplicationsOfType:1 block:^(LSApplicationProxy* appProxy)
{
if(appProxy.installed && !appProxy.restricted)
{
if([appProxy.bundleURL.path hasPrefix:@"/private/var/containers"])
{
NSURL* trollStoreMarkURL = [appProxy.bundleURL.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"_TrollStore"];
if(![trollStoreMarkURL checkResourceIsReachableAndReturnError:nil])
{
[appCandidates addObject:appProxy];
}
}
}
}];
UIAlertController* selectAppAlert = [UIAlertController alertControllerWithTitle:@"Select App" message:@"Select a system app to install the TrollStore Persistence Helper into. The normal function of the app will not be available, so it is recommended to pick something useless like the Tips app." preferredStyle:UIAlertControllerStyleActionSheet];
for(LSApplicationProxy* appProxy in appCandidates)
{
UIAlertAction* installAction = [UIAlertAction actionWithTitle:[appProxy localizedName] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action)
{
spawnRoot(helperPath(), @[@"install-persistence-helper", appProxy.bundleIdentifier]);
[self reloadSpecifiers];
}];
[selectAppAlert addAction:installAction];
}
NSIndexPath* indexPath = [self indexPathForSpecifier:_installPersistenceHelperSpecifier];
UITableView* tableView = [self valueForKey:@"_table"];
selectAppAlert.popoverPresentationController.sourceView = tableView;
selectAppAlert.popoverPresentationController.sourceRect = [tableView rectForRowAtIndexPath:indexPath];
UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil];
[selectAppAlert addAction:cancelAction];
[self presentViewController:selectAppAlert animated:YES completion:nil];
}
- (void)uninstallPersistenceHelperPressed
{
spawnRoot(helperPath(), @[@"uninstall-persistence-helper"]);
[self reloadSpecifiers];
}
- (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"]);
exit(0);
}];
[uninstallWarningAlert addAction:continueAction];
[self presentViewController:uninstallWarningAlert animated:YES completion:nil];
}
@end
+6
View File
@@ -0,0 +1,6 @@
@import Foundation;
extern NSString* helperPath(void);
extern int spawnRoot(NSString* path, NSArray* args);
extern void respring(void);
extern NSString* getTrollStoreVersion(void);
+139
View File
@@ -0,0 +1,139 @@
#import "TSUtil.h"
#import <Foundation/Foundation.h>
#import <spawn.h>
#import <sys/sysctl.h>
#define POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE 1
extern int posix_spawnattr_set_persona_np(const posix_spawnattr_t* __restrict, uid_t, uint32_t);
extern int posix_spawnattr_set_persona_uid_np(const posix_spawnattr_t* __restrict, uid_t);
extern int posix_spawnattr_set_persona_gid_np(const posix_spawnattr_t* __restrict, uid_t);
NSString* helperPath(void)
{
return [[NSBundle mainBundle].bundlePath stringByAppendingPathComponent:@"trollstorehelper"];
}
int spawnRoot(NSString* path, NSArray* args)
{
NSMutableArray* argsM = args.mutableCopy ?: [NSMutableArray new];
[argsM insertObject:path.lastPathComponent atIndex:0];
NSUInteger argCount = [argsM count];
char **argsC = (char **)malloc((argCount + 1) * sizeof(char*));
for (NSUInteger i = 0; i < argCount; i++)
{
argsC[i] = strdup([[argsM objectAtIndex:i] UTF8String]);
}
argsC[argCount] = NULL;
int rv;
posix_spawnattr_t attr;
rv = posix_spawnattr_init(&attr);
if(rv != 0) return rv;
posix_spawnattr_set_persona_np(&attr, 99, POSIX_SPAWN_PERSONA_FLAGS_OVERRIDE);
posix_spawnattr_set_persona_uid_np(&attr, 0);
posix_spawnattr_set_persona_gid_np(&attr, 0);
pid_t task_pid;
int status = -200;
int spawnError = posix_spawn(&task_pid, [path UTF8String], NULL, &attr, (char* const*)argsC, NULL);
posix_spawnattr_destroy(&attr);
for (NSUInteger i = 0; i < argCount; i++)
{
free(argsC[i]);
}
free(argsC);
if(spawnError != 0)
{
NSLog(@"posix_spawn error %d\n", spawnError);
return spawnError;
}
do
{
if (waitpid(task_pid, &status, 0) != -1) {
printf("Child status %dn", WEXITSTATUS(status));
} else
{
perror("waitpid");
return -222;
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
return WEXITSTATUS(status);
}
void enumerateProcessesUsingBlock(void (^enumerator)(pid_t pid, NSString* executablePath, BOOL* stop))
{
static int maxArgumentSize = 0;
if (maxArgumentSize == 0) {
size_t size = sizeof(maxArgumentSize);
if (sysctl((int[]){ CTL_KERN, KERN_ARGMAX }, 2, &maxArgumentSize, &size, NULL, 0) == -1) {
perror("sysctl argument size");
maxArgumentSize = 4096; // Default
}
}
int mib[3] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL};
struct kinfo_proc *info;
size_t length;
int count;
if (sysctl(mib, 3, NULL, &length, NULL, 0) < 0)
return;
if (!(info = malloc(length)))
return;
if (sysctl(mib, 3, info, &length, NULL, 0) < 0) {
free(info);
return;
}
count = length / sizeof(struct kinfo_proc);
for (int i = 0; i < count; i++) {
@autoreleasepool {
pid_t pid = info[i].kp_proc.p_pid;
if (pid == 0) {
continue;
}
size_t size = maxArgumentSize;
char* buffer = (char *)malloc(length);
if (sysctl((int[]){ CTL_KERN, KERN_PROCARGS2, pid }, 3, buffer, &size, NULL, 0) == 0) {
NSString* executablePath = [NSString stringWithCString:(buffer+sizeof(int)) encoding:NSUTF8StringEncoding];
BOOL stop = NO;
enumerator(pid, executablePath, &stop);
if(stop)
{
free(buffer);
break;
}
}
free(buffer);
}
}
free(info);
}
void killall(NSString* processName)
{
enumerateProcessesUsingBlock(^(pid_t pid, NSString* executablePath, BOOL* stop)
{
if([executablePath.lastPathComponent isEqualToString:processName])
{
kill(pid, SIGTERM);
}
});
}
void respring(void)
{
killall(@"SpringBoard");
exit(0);
}
NSString* getTrollStoreVersion(void)
{
return [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleVersion"];
}
+8
View File
@@ -0,0 +1,8 @@
Package: com.opa334.trollstore
Name: TrollStore
Version: 1.0
Architecture: iphoneos-arm
Description: An awesome application!
Maintainer: opa334
Author: opa334
Section: Utilities
+34
View File
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>application-identifier</key>
<string>com.opa334.TrollStore</string>
<key>platform-application</key>
<true/>
<key>com.apple.security.exception.files.absolute-path.read-write</key>
<array>
<string>/</string>
</array>
<key>com.apple.private.security.no-sandbox</key>
<true/>
<key>com.apple.private.persona-mgmt</key>
<true/>
<key>com.apple.private.security.system-application</key>
<true/>
<key>com.apple.private.security.container-manager</key>
<true/>
<key>com.apple.private.coreservices.canmaplsdatabase</key>
<true/>
<key>com.apple.lsapplicationworkspace.rebuildappdatabases</key>
<true/>
<key>com.apple.private.MobileContainerManager.allowed</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.InstallDaemonOpsEnabled</key>
<true/>
<key>com.apple.private.MobileInstallationHelperService.allowed</key>
<true/>
<key>com.apple.private.uninstall.deletion</key>
<true/>
</dict>
</plist>
+8
View File
@@ -0,0 +1,8 @@
#import <Foundation/Foundation.h>
#import "TSAppDelegate.h"
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass(TSAppDelegate.class));
}
}