diff --git a/Bootstrap.xcodeproj/project.pbxproj b/Bootstrap.xcodeproj/project.pbxproj index 8d6071b8..9b91894d 100644 --- a/Bootstrap.xcodeproj/project.pbxproj +++ b/Bootstrap.xcodeproj/project.pbxproj @@ -436,7 +436,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.4.2; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.roothide.Bootstrap; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -470,7 +470,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 0.4.2; OTHER_LDFLAGS = ""; PRODUCT_BUNDLE_IDENTIFIER = com.roothide.Bootstrap; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/Bootstrap.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate b/Bootstrap.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate index 05f99d0c..12cc42c9 100644 Binary files a/Bootstrap.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate and b/Bootstrap.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Bootstrap/AppDelegate.h b/Bootstrap/AppDelegate.h index 9b044570..4c50fad2 100644 --- a/Bootstrap/AppDelegate.h +++ b/Bootstrap/AppDelegate.h @@ -6,6 +6,7 @@ @interface AppDelegate : UIResponder +(void)showHudMsg:(NSString*)msg; ++(void)showHudMsg:(NSString*)msg detail:(NSString*)info; +(void)dismissHud; + (void)showAlert:(UIAlertController*)alert; diff --git a/Bootstrap/AppDelegate.m b/Bootstrap/AppDelegate.m index fb4f3644..fc791355 100644 --- a/Bootstrap/AppDelegate.m +++ b/Bootstrap/AppDelegate.m @@ -38,6 +38,16 @@ +(void)showHudMsg:(NSString*)msg }); } ++(void)showHudMsg:(NSString*)msg detail:(NSString*)info +{ + dispatch_async(dispatch_get_main_queue(), ^{ + switchHud = [MBProgressHUD showHUDAddedTo:UIApplication.sharedApplication.keyWindow animated:YES]; + [switchHud showAnimated:YES]; + switchHud.label.text = msg; + switchHud.detailsLabel.text = info; + }); +} + +(void)dismissHud { dispatch_async(dispatch_get_main_queue(), ^{ [switchHud hideAnimated:YES]; diff --git a/Bootstrap/AppViewController.m b/Bootstrap/AppViewController.m index 655cc566..85d77843 100644 --- a/Bootstrap/AppViewController.m +++ b/Bootstrap/AppViewController.m @@ -9,7 +9,7 @@ @interface PrivateApi_LSApplicationWorkspace - (NSArray*)allInstalledApplications; -- (bool)openApplicationWithBundleID:(id)arg1; +- (BOOL)openApplicationWithBundleID:(id)arg1; - (NSArray*)privateURLSchemes; - (NSArray*)publicURLSchemes; - (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 @@ -93,10 +93,10 @@ - (void)viewDidLoad { [refreshControl addTarget:self action:@selector(startRefresh) forControlEvents:UIControlEventValueChanged]; self.tableView.refreshControl = refreshControl; - [self updateData]; + [self updateData:YES]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(startRefresh) + selector:@selector(startRefresh2) name:UIApplicationWillEnterForegroundNotification object:nil]; } @@ -104,10 +104,18 @@ - (void)viewDidLoad { - (void)startRefresh { [self.tableView.refreshControl beginRefreshing]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ - [self updateData]; + [self updateData:YES]; + dispatch_async(dispatch_get_main_queue(), ^{ + [self.tableView.refreshControl endRefreshing]; + }); + }); +} + +- (void)startRefresh2 { + [self.tableView.refreshControl beginRefreshing]; + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + [self updateData:NO]; dispatch_async(dispatch_get_main_queue(), ^{ - [self reloadSearch]; - [self.tableView reloadData]; [self.tableView.refreshControl endRefreshing]; }); }); @@ -119,7 +127,7 @@ - (void)viewWillAppear:(BOOL)animated { [self.tableView.refreshControl endRefreshing]; } -- (void)updateData { +- (void)updateData:(BOOL)sort { NSMutableArray* applications = [NSMutableArray new]; PrivateApi_LSApplicationWorkspace* _workspace = [NSClassFromString(@"LSApplicationWorkspace") new]; NSArray* allInstalledApplications = [_workspace allInstalledApplications]; @@ -152,15 +160,67 @@ - (void)updateData { if([app.bundleURL.path.lastPathComponent isEqualToString:@"Bootstrap.app"]) continue; + + if([app.bundleIdentifier isEqualToString:NSBundle.mainBundle.bundleIdentifier] + || [app.bundleIdentifier isEqualToString:@"com.roothide.Bootstrap"]) + continue; [applications addObject:app]; } - NSArray *appsSortedByName = [applications sortedArrayUsingComparator:^NSComparisonResult(AppList *app1, AppList *app2) { - return [app1.name localizedStandardCompare:app2.name]; - }]; + if(sort) + { + NSArray *appsSortedByName = [applications sortedArrayUsingComparator:^NSComparisonResult(AppList *app1, AppList *app2) { + struct stat st; + BOOL enabled1 = lstat([app1.bundleURL.path stringByAppendingPathComponent:@".jbroot"].fileSystemRepresentation, &st)==0; + BOOL enabled2 = lstat([app2.bundleURL.path stringByAppendingPathComponent:@".jbroot"].fileSystemRepresentation, &st)==0; + if(enabled1 || enabled2) { + return [@(enabled2) compare:@(enabled1)]; + } + + if(app1.isHiddenApp || app2.isHiddenApp) { + return [@(app1.isHiddenApp) compare:@(app2.isHiddenApp)]; + } + + return [app1.name localizedStandardCompare:app2.name]; + }]; + + self->appsArray = appsSortedByName; + } + else + { + NSMutableArray *newapps = [NSMutableArray array]; + [applications enumerateObjectsUsingBlock:^(AppList *newobj, NSUInteger idx, BOOL * _Nonnull stop) { + __block BOOL hasBeenContained = NO; + [self->appsArray enumerateObjectsUsingBlock:^(AppList *obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([obj.bundleIdentifier isEqualToString:newobj.bundleIdentifier]) { + hasBeenContained = YES; + *stop = YES; + } + }]; + if (!hasBeenContained) { + [newapps addObject:newobj]; + } + }]; + + NSMutableArray *tmpArray = [NSMutableArray array]; + [self->appsArray enumerateObjectsUsingBlock:^(AppList *obj, NSUInteger idx, BOOL * _Nonnull stop) { + [applications enumerateObjectsUsingBlock:^(AppList *newobj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([obj.bundleIdentifier isEqualToString:newobj.bundleIdentifier]) { + [tmpArray addObject:newobj]; + *stop = YES; + } + }]; + }]; + + [tmpArray addObjectsFromArray:newapps]; + self->appsArray = tmpArray.copy; + } - self->appsArray = appsSortedByName; + dispatch_async(dispatch_get_main_queue(), ^{ + [self reloadSearch]; + [self.tableView reloadData]; + }); } #pragma mark - Table view data source @@ -206,10 +266,14 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N AppList* app = isFiltered? filteredApps[indexPath.row] : appsArray[indexPath.row]; - UIImage *image = app.icon; - cell.imageView.image = [self imageWithImage:image scaledToSize:CGSizeMake(40, 40)]; + if(!app.isHiddenApp) { + UIImage *image = app.icon; + cell.imageView.image = [self imageWithImage:image scaledToSize:CGSizeMake(40, 40)]; + cell.textLabel.text = app.name; + } else { + cell.textLabel.text = app.bundleIdentifier; + } - cell.textLabel.text = app.name; cell.detailTextLabel.text = app.bundleIdentifier; UISwitch *theSwitch = [[UISwitch alloc] init]; @@ -223,6 +287,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [theSwitch addTarget:self action:@selector(switchChanged:) forControlEvents:UIControlEventValueChanged]; cell.accessoryView = theSwitch; + + UILongPressGestureRecognizer *gest = [[UILongPressGestureRecognizer alloc] + initWithTarget:self action:@selector(cellLongPress:)]; + [cell.contentView addGestureRecognizer:gest]; + gest.view.tag = indexPath.row | indexPath.section<<32; + gest.minimumPressDuration = 1; + return cell; } @@ -255,14 +326,26 @@ - (void)switchChanged:(id)sender { killAllForApp(app.bundleURL.path.UTF8String); //refresh app cache list - [self updateData]; - dispatch_async(dispatch_get_main_queue(), ^{ - [self reloadSearch]; - [self.tableView reloadData]; - }); + [self updateData:NO]; [AppDelegate dismissHud]; }); } + +- (void)cellLongPress:(UIGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateBegan) + { + long tag = recognizer.view.tag; + NSIndexPath* indexPath = [NSIndexPath indexPathForRow:tag&0xFFFFFFFF inSection:tag>>32]; + + AppList* app = isFiltered? filteredApps[indexPath.row] : appsArray[indexPath.row]; + + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + PrivateApi_LSApplicationWorkspace* _workspace = [NSClassFromString(@"LSApplicationWorkspace") new]; + [_workspace openApplicationWithBundleID:app.bundleIdentifier]; + }); + } +} @end diff --git a/Bootstrap/Base.lproj/Main.storyboard b/Bootstrap/Base.lproj/Main.storyboard index dc3f5f90..48b1f903 100644 --- a/Bootstrap/Base.lproj/Main.storyboard +++ b/Bootstrap/Base.lproj/Main.storyboard @@ -28,7 +28,7 @@ - + @@ -38,7 +38,7 @@ - - + + - + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. @@ -82,7 +82,7 @@ + + @@ -105,8 +121,11 @@ + + + diff --git a/Bootstrap/ViewController.m b/Bootstrap/ViewController.m index 103c883f..f6db7578 100644 --- a/Bootstrap/ViewController.m +++ b/Bootstrap/ViewController.m @@ -5,6 +5,7 @@ #include "AppViewController.h" #include "bootstrap.h" #include "credits.h" +#include "AppList.h" #import #include @@ -25,6 +26,9 @@ @interface ViewController () @property (weak, nonatomic) IBOutlet UIButton *respringBtn; @property (weak, nonatomic) IBOutlet UIButton *uninstallBtn; @property (weak, nonatomic) IBOutlet UIButton *rebuildappsBtn; +@property (weak, nonatomic) IBOutlet UIButton *rebuildIconCacheBtn; +@property (weak, nonatomic) IBOutlet UIButton *reinstallPackageManagerBtn; +@property (weak, nonatomic) IBOutlet UILabel *opensshLabel; @end @@ -63,15 +67,32 @@ - (void)viewDidLoad { if(isSystemBootstrapped()) { - self.bootstraBtn.enabled = NO; - [self.bootstraBtn setTitle:Localized(@"Bootstrapped") forState:UIControlStateDisabled]; + if(checkBootstrapVersion()) { + self.bootstraBtn.enabled = NO; + [self.bootstraBtn setTitle:Localized(@"Bootstrapped") forState:UIControlStateDisabled]; + } else { + self.bootstraBtn.enabled = YES; + [self.bootstraBtn setTitle:Localized(@"Update") forState:UIControlStateNormal]; + } self.respringBtn.enabled = YES; self.appEnablerBtn.enabled = YES; self.rebuildappsBtn.enabled = YES; + self.rebuildIconCacheBtn.enabled = YES; + self.reinstallPackageManagerBtn.enabled = YES; self.uninstallBtn.enabled = NO; self.uninstallBtn.hidden = NO; + if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.rebuildiconcache")]) { + [NSFileManager.defaultManager removeItemAtPath:jbroot(@"/basebin/.rebuildiconcache") error:nil]; + + [AppDelegate showHudMsg:Localized(@"Rebuilding")]; + } + + if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.launchctl_support")]) { + self.opensshState.hidden = YES; + self.opensshLabel.hidden = YES; + } } else if(isBootstrapInstalled()) { @@ -82,6 +103,8 @@ - (void)viewDidLoad { self.respringBtn.enabled = NO; self.appEnablerBtn.enabled = NO; self.rebuildappsBtn.enabled = NO; + self.rebuildIconCacheBtn.enabled = NO; + self.reinstallPackageManagerBtn.enabled = NO; self.uninstallBtn.hidden = NO; } else if(NSProcessInfo.processInfo.operatingSystemVersion.majorVersion>=15) @@ -92,6 +115,8 @@ - (void)viewDidLoad { self.respringBtn.enabled = NO; self.appEnablerBtn.enabled = NO; self.rebuildappsBtn.enabled = NO; + self.rebuildIconCacheBtn.enabled = NO; + self.reinstallPackageManagerBtn.enabled = NO; self.uninstallBtn.hidden = YES; } else { self.bootstraBtn.enabled = NO; @@ -100,6 +125,8 @@ - (void)viewDidLoad { self.respringBtn.enabled = NO; self.appEnablerBtn.enabled = NO; self.rebuildappsBtn.enabled = NO; + self.rebuildIconCacheBtn.enabled = NO; + self.reinstallPackageManagerBtn.enabled = NO; self.uninstallBtn.hidden = YES; [AppDelegate showMesage:Localized(@"the current ios version is not supported yet, we may add support in a future version.") title:Localized(@"Unsupported")]; @@ -112,14 +139,14 @@ - (void)viewDidLoad { uname(&systemInfo); [AppDelegate addLogText:[NSString stringWithFormat:@"device-model: %s",systemInfo.machine]]; - [AppDelegate addLogText:[NSString stringWithFormat:@"app-version: %@/%@",NSBundle.mainBundle.infoDictionary[@"CFBundleVersion"],NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"]]]; + [AppDelegate addLogText:[NSString stringWithFormat:@"app-version: %@",NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"]]]; [AppDelegate addLogText:[NSString stringWithFormat:@"boot-session: %@",getBootSession()]]; [AppDelegate addLogText: isBootstrapInstalled()? @"bootstrap installed":@"bootstrap not installed"]; [AppDelegate addLogText: isSystemBootstrapped()? @"system bootstrapped":@"system not bootstrapped"]; - dispatch_async(dispatch_get_global_queue(0, 0), ^{ + if(!isBootstrapInstalled()) dispatch_async(dispatch_get_global_queue(0, 0), ^{ usleep(1000*500); [AppDelegate addLogText:@"\n:::Credits:::\n"]; usleep(1000*500); @@ -140,31 +167,61 @@ - (void)viewDidLoad { if(isSystemBootstrapped()) { - if(spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"check"], nil, nil) != 0) - { - UIAlertController *alert = [UIAlertController alertControllerWithTitle:Localized(@"Server Not Running") message:Localized(@"for unknown reasons the bootstrap server is not running, the only thing we can do is to restart it now.") preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:Localized(@"Restart Server") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ - - NSString* log=nil; - NSString* err=nil; - if(spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"daemon",@"-f"], &log, &err)==0) { - [AppDelegate addLogText:Localized(@"bootstrap server restart successful")]; - [self updateOpensshStatus]; - } else { - [AppDelegate showMesage:[NSString stringWithFormat:@"%@\nERR:%@"] title:Localized(@"Error")]; - } - - }]]; - - [AppDelegate showAlert:alert]; - } else { + if([self checkServer]) { [AppDelegate addLogText:Localized(@"bootstrap server check successful")]; - [self updateOpensshStatus]; } + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkServer) + name:UIApplicationWillEnterForegroundNotification object:nil]; + } + + if(isBootstrapInstalled() || isSystemBootstrapped()) { + if([UIApplication.sharedApplication canOpenURL:[NSURL URLWithString:@"filza://"]] + || [LSPlugInKitProxy pluginKitProxyForIdentifier:@"com.tigisoftware.Filza.Sharing"]) + { + [AppDelegate showMesage:Localized(@"It seems that you have the Filza app installed, which may be detected as jailbroken. You can enable Tweak for it to hide it.") title:Localized(@"Warnning")]; + } + } +} + +-(BOOL)checkServer +{ + static bool alerted = false; + if(alerted) return NO; + + BOOL ret=NO; + + if(spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"check"], nil, nil) != 0) + { + ret = NO; + alerted = true; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:Localized(@"Server Not Running") message:Localized(@"for unknown reasons the bootstrap server is not running, the only thing we can do is to restart it now.") preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:Localized(@"Restart Server") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ + + alerted = false; + + NSString* log=nil; + NSString* err=nil; + if(spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"daemon",@"-f"], &log, &err)==0) { + [AppDelegate addLogText:Localized(@"bootstrap server restart successful")]; + [self updateOpensshStatus]; + } else { + [AppDelegate showMesage:[NSString stringWithFormat:@"%@\nERR:%@"] title:Localized(@"Error")]; + } + + }]]; + + [AppDelegate showAlert:alert]; + } else { + [self updateOpensshStatus]; + ret = YES; } + + return ret; } --(void) updateOpensshStatus { +-(void)updateOpensshStatus { dispatch_async(dispatch_get_main_queue(), ^{ if(isSystemBootstrapped()) { self.opensshState.on = spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"openssh",@"check"], nil, nil)==0; @@ -183,7 +240,7 @@ - (IBAction)respring:(id)sender { } - (IBAction)rebuildapps:(id)sender { - STRAPLOG("Status: Rebuilding Apps"); + [AppDelegate addLogText:@"Status: Rebuilding Apps"]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [AppDelegate showHudMsg:Localized(@"Applying")]; @@ -200,6 +257,100 @@ - (IBAction)rebuildapps:(id)sender { }); } +- (IBAction)reinstallPackageManager:(id)sender { + + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + [AppDelegate showHudMsg:Localized(@"Applying")]; + + NSString* log=nil; + NSString* err=nil; + + BOOL success=YES; + + [AppDelegate addLogText:@"Status: Reinstalling Sileo"]; + NSString* sileoDeb = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"sileo.deb"]; + if(spawnBootstrap((char*[]){"/usr/bin/dpkg", "-i", rootfsPrefix(sileoDeb).fileSystemRepresentation, NULL}, &log, &err) != 0) { + [AppDelegate addLogText:[NSString stringWithFormat:@"failed:%@\nERR:%@", log, err]]; + success = NO; + } + + if(spawnBootstrap((char*[]){"/usr/bin/uicache", "-p", "/Applications/Sileo.app", NULL}, &log, &err) != 0) { + [AppDelegate addLogText:[NSString stringWithFormat:@"failed:%@\nERR:%@", log, err]]; + success = NO; + } + + [AppDelegate addLogText:@"Status: Reinstalling Zebra"]; + NSString* zebraDeb = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"zebra.deb"]; + if(spawnBootstrap((char*[]){"/usr/bin/dpkg", "-i", rootfsPrefix(zebraDeb).fileSystemRepresentation, NULL}, nil, nil) != 0) { + [AppDelegate addLogText:[NSString stringWithFormat:@"failed:%@\nERR:%@", log, err]]; + success = NO; + } + + if(spawnBootstrap((char*[]){"/usr/bin/uicache", "-p", "/Applications/Zebra.app", NULL}, &log, &err) != 0) { + [AppDelegate addLogText:[NSString stringWithFormat:@"failed:%@\nERR:%@", log, err]]; + success = NO; + } + + if(success) { + [AppDelegate showMesage:@"Sileo and Zebra reinstalled!" title:@""]; + } + [AppDelegate dismissHud]; + }); +} + +int rebuildIconCache() +{ + AppList* tsapp = [AppList appWithBundleIdentifier:@"com.opa334.TrollStore"]; + if(!tsapp) { + STRAPLOG("trollstore not found!"); + return -1; + } + + STRAPLOG("rebuild icon cache..."); + ASSERT([LSApplicationWorkspace.defaultWorkspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:YES]); + + NSString* log=nil; + NSString* err=nil; + + if(spawnRoot([tsapp.bundleURL.path stringByAppendingPathComponent:@"trollstorehelper"], @[@"refresh"], &log, &err) != 0) { + STRAPLOG("refresh tsapps failed:%@\nERR:%@", log, err); + return -1; + } + + [[NSString new] writeToFile:jbroot(@"/basebin/.rebuildiconcache") atomically:YES encoding:NSUTF8StringEncoding error:nil]; + [LSApplicationWorkspace.defaultWorkspace openApplicationWithBundleID:NSBundle.mainBundle.bundleIdentifier]; + + int status = spawnBootstrap((char*[]){"/bin/sh", "/basebin/rebuildapps.sh", NULL}, &log, &err); + if(status==0) { + killAllForApp("/usr/libexec/backboardd"); + } else { + STRAPLOG("rebuildapps failed:%@\nERR:\n%@",log,err); + } + + if([NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/basebin/.rebuildiconcache")]) { + [NSFileManager.defaultManager removeItemAtPath:jbroot(@"/basebin/.rebuildiconcache") error:nil]; + } + + return status; +} + +- (IBAction)rebuildIconCache:(id)sender { + [AppDelegate addLogText:@"Status: Rebuilding Icon Cache"]; + + dispatch_async(dispatch_get_global_queue(0, 0), ^{ + [AppDelegate showHudMsg:Localized(@"Rebuilding") detail:Localized(@"Don't exit Bootstrap app until show the lock screen.")]; + + NSString* log=nil; + NSString* err=nil; + int status = spawnRoot(NSBundle.mainBundle.executablePath, @[@"rebuildiconcache"], &log, &err); + if(status != 0) { + [AppDelegate showMesage:[NSString stringWithFormat:@"%@\n\nstderr:\n%@",log,err] title:[NSString stringWithFormat:@"code(%d)",status]]; + } + + [AppDelegate dismissHud]; + }); +} + - (IBAction)appenabler:(id)sender { AppViewController *vc = [[AppViewController alloc] init]; @@ -242,6 +393,22 @@ - (IBAction)openssh:(id)sender { } - (IBAction)bootstrap:(id)sender { + + if(isSystemBootstrapped()) + { + ASSERT(checkBootstrapVersion()==false); + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:Localized(@"Update") message:Localized(@"The current bootstrapped version is inconsistent with the Bootstrap app version, and you need to reboot the device to update it.") preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:Localized(@"Cancel") style:UIAlertActionStyleDefault handler:nil]]; + [alert addAction:[UIAlertAction actionWithTitle:Localized(@"Reboot Device") style:UIAlertActionStyleDestructive handler:^(UIAlertAction *action) { + ASSERT(spawnRoot(NSBundle.mainBundle.executablePath, @[@"reboot"], nil, nil)==0); + }]]; + + [AppDelegate showAlert:alert]; + return; + } + if(![self checkTSVersion]) { [AppDelegate showMesage:Localized(@"Your trollstore version is too old, Bootstrap only supports trollstore>=2.0") title:Localized(@"Error")]; return; @@ -253,7 +420,7 @@ - (IBAction)bootstrap:(id)sender { } UIImpactFeedbackGenerator* generator = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleSoft]; - generator.impactOccurred; + [generator impactOccurred]; if(find_jbroot()) //make sure jbroot() function available { @@ -295,7 +462,8 @@ - (IBAction)bootstrap:(id)sender { NSString* log=nil; NSString* err=nil; - if([NSUserDefaults.appDefaults boolForKey:@"openssh"] && [NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/usr/libexec/sshd-keygen-wrapper")]) { + if([NSUserDefaults.appDefaults boolForKey:@"openssh"] && [NSFileManager.defaultManager fileExistsAtPath:jbroot(@"/usr/libexec/sshd-keygen-wrapper")]) + { NSString* log=nil; NSString* err=nil; status = spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"openssh",@"start"], &log, &err); @@ -305,6 +473,7 @@ - (IBAction)bootstrap:(id)sender { [AppDelegate addLogText:[NSString stringWithFormat:@"openssh launch faild(%d):\n%@\n%@", status, log, err]]; } + [generator impactOccurred]; [AppDelegate addLogText:@"respring now..."]; sleep(1); status = spawnBootstrap((char*[]){"/usr/bin/sbreload", NULL}, &log, &err); @@ -328,11 +497,15 @@ - (IBAction)unbootstrap:(id)sender { [AppDelegate dismissHud]; - if(status == 0) { - [AppDelegate showMesage:@"" title:@"bootstrap uninstalled"]; - } else { - [AppDelegate showMesage:[NSString stringWithFormat:@"%@\n\nstderr:\n%@",log,err] title:[NSString stringWithFormat:@"code(%d)",status]]; - } + NSString* msg = (status==0) ? @"bootstrap uninstalled" : [NSString stringWithFormat:@"code(%d)\n%@\n\nstderr:\n%@",status,log,err]; + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:msg preferredStyle:UIAlertControllerStyleAlert]; + [alert addAction:[UIAlertAction actionWithTitle:Localized(@"OK") style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ + exit(0); + }]]; + + [AppDelegate showAlert:alert]; + }); }]]; diff --git a/Bootstrap/basebin/bootstrap.dylib b/Bootstrap/basebin/bootstrap.dylib index 55548974..9d8a011e 100755 Binary files a/Bootstrap/basebin/bootstrap.dylib and b/Bootstrap/basebin/bootstrap.dylib differ diff --git a/Bootstrap/basebin/bootstrapd b/Bootstrap/basebin/bootstrapd index 8b0a874f..db3dea3f 100755 Binary files a/Bootstrap/basebin/bootstrapd and b/Bootstrap/basebin/bootstrapd differ diff --git a/Bootstrap/basebin/devtest b/Bootstrap/basebin/devtest index 16076217..001366d2 100755 Binary files a/Bootstrap/basebin/devtest and b/Bootstrap/basebin/devtest differ diff --git a/Bootstrap/basebin/fastPathSign b/Bootstrap/basebin/fastPathSign index a05b7ef0..09555ed4 100755 Binary files a/Bootstrap/basebin/fastPathSign and b/Bootstrap/basebin/fastPathSign differ diff --git a/Bootstrap/basebin/preload b/Bootstrap/basebin/preload index 9b538405..df9e3bc7 100755 Binary files a/Bootstrap/basebin/preload and b/Bootstrap/basebin/preload differ diff --git a/Bootstrap/basebin/preload.dylib b/Bootstrap/basebin/preload.dylib index d6658dc5..9283a10a 100755 Binary files a/Bootstrap/basebin/preload.dylib and b/Bootstrap/basebin/preload.dylib differ diff --git a/Bootstrap/basebin/rebuildapp b/Bootstrap/basebin/rebuildapp index 4d83d1d4..eff30a8f 100755 Binary files a/Bootstrap/basebin/rebuildapp and b/Bootstrap/basebin/rebuildapp differ diff --git a/Bootstrap/basebin/test.sh b/Bootstrap/basebin/test.sh new file mode 100644 index 00000000..ac654a1e --- /dev/null +++ b/Bootstrap/basebin/test.sh @@ -0,0 +1,3 @@ +set jbroot_path $(realpath ..) +export DYLD_INSERT_LIBRARIES=$jbroot_path/basebin/bootstrap.dylib +DYLD_INSERT_LIBRARIES=$jbroot_path/basebin/bootstrap.dylib $jbroot_path/usr/bin/zsh diff --git a/Bootstrap/basebin/uicache b/Bootstrap/basebin/uicache index eb9372df..524c6b52 100755 Binary files a/Bootstrap/basebin/uicache and b/Bootstrap/basebin/uicache differ diff --git a/Bootstrap/bootstrap.h b/Bootstrap/bootstrap.h index df89f8ae..de788f8f 100644 --- a/Bootstrap/bootstrap.h +++ b/Bootstrap/bootstrap.h @@ -1,7 +1,7 @@ #ifndef bootstrap_h #define bootstrap_h -#define BOOTSTRAP_VERSION (4) +#define BOOTSTRAP_VERSION (5) void rebuildSignature(NSString *directoryPath); @@ -13,5 +13,6 @@ bool isBootstrapInstalled(); bool isSystemBootstrapped(); +bool checkBootstrapVersion(); #endif /* bootstrap_h */ diff --git a/Bootstrap/bootstrap.m b/Bootstrap/bootstrap.m index 120bfa34..5124bce0 100644 --- a/Bootstrap/bootstrap.m +++ b/Bootstrap/bootstrap.m @@ -6,6 +6,7 @@ #include "sources.h" #include "bootstrap.h" #include "NSUserDefaults+appDefaults.h" +#include "AppList.h" extern int decompress_tar_zstd(const char* src_file_path, const char* dst_file_path); @@ -125,7 +126,7 @@ int rebuildBasebin() return 0; } -int startBootstrapd() +int startBootstrapServer() { NSString* log=nil; NSString* err=nil; @@ -208,7 +209,7 @@ int InstallBootstrap(NSString* jbroot_path) ASSERT(rebuildBasebin() == 0); STRAPLOG("Status: Starting Bootstrapd"); - ASSERT(startBootstrapd() == 0); + ASSERT(startBootstrapServer() == 0); STRAPLOG("Status: Finalizing Bootstrap"); NSString* log=nil; @@ -234,11 +235,14 @@ int InstallBootstrap(NSString* jbroot_path) NSString* sileoDeb = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"sileo.deb"]; ASSERT(spawnBootstrap((char*[]){"/usr/bin/dpkg", "-i", rootfsPrefix(sileoDeb).fileSystemRepresentation, NULL}, nil, nil) == 0); + ASSERT(spawnBootstrap((char*[]){"/usr/bin/uicache", "-p", "/Applications/Sileo.app", NULL}, nil, nil) == 0); NSString* zebraDeb = [NSBundle.mainBundle.bundlePath stringByAppendingPathComponent:@"zebra.deb"]; ASSERT(spawnBootstrap((char*[]){"/usr/bin/dpkg", "-i", rootfsPrefix(zebraDeb).fileSystemRepresentation, NULL}, nil, nil) == 0); + ASSERT(spawnBootstrap((char*[]){"/usr/bin/uicache", "-p", "/Applications/Zebra.app", NULL}, nil, nil) == 0); ASSERT([[NSString stringWithFormat:@"%d",BOOTSTRAP_VERSION] writeToFile:jbroot(@"/.bootstrapped") atomically:YES encoding:NSUTF8StringEncoding error:nil]); + ASSERT([fm copyItemAtPath:jbroot(@"/.bootstrapped") toPath:[jbroot_secondary stringByAppendingPathComponent:@".bootstrapped"] error:nil]); STRAPLOG("Status: Bootstrap Installed"); @@ -248,7 +252,7 @@ int InstallBootstrap(NSString* jbroot_path) int ReRandomizeBootstrap() { - //jbroot() disabled + //jbroot() unavailable NSFileManager* fm = NSFileManager.defaultManager; @@ -288,13 +292,13 @@ int ReRandomizeBootstrap() ASSERT([fm createSymbolicLinkAtPath:[jbroot_secondary stringByAppendingPathComponent:@".jbroot"] withDestinationPath:jbroot_path error:nil]); - //jbroot() enabled + //jbroot() available now STRAPLOG("Status: Building Base Binaries"); ASSERT(rebuildBasebin() == 0); STRAPLOG("Status: Starting Bootstrapd"); - ASSERT(startBootstrapd() == 0); + ASSERT(startBootstrapServer() == 0); STRAPLOG("Status: Updating Symlinks"); ASSERT(spawnBootstrap((char*[]){"/bin/sh", "/usr/libexec/updatelinks.sh", NULL}, nil, nil) == 0); @@ -310,6 +314,12 @@ int bootstrap() NSFileManager* fm = NSFileManager.defaultManager; + struct stat st; + if(lstat("/var/jb", &st)==0) { + //remove /var/jb to avoid incorrect library loading via @rpath + ASSERT([fm removeItemAtPath:@"/var/jb" error:nil]); + } + NSString* jbroot_path = find_jbroot(); if(!jbroot_path) { @@ -351,7 +361,7 @@ int bootstrap() STRAPLOG("Status: Rebuilding Apps"); ASSERT(spawnBootstrap((char*[]){"/bin/sh", "/basebin/rebuildapps.sh", NULL}, nil, nil) == 0); - NSDictionary* bootinfo = @{@"bootsession":getBootSession()}; + NSDictionary* bootinfo = @{@"bootsession":getBootSession(), @"bootversion":NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"]}; ASSERT([bootinfo writeToFile:jbroot(@"/basebin/.bootinfo.plist") atomically:YES]); STRAPLOG("Status: Bootstrap Successful"); @@ -359,18 +369,14 @@ int bootstrap() return 0; } - - -@interface LSApplicationWorkspace : NSObject -+ (id)defaultWorkspace; -- (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 - internal:(BOOL)arg2 - user:(BOOL)arg3; -@end - int unbootstrap() { - SYSLOG("unbootstrap..."); + STRAPLOG("unbootstrap..."); + + //try + spawnRoot(jbroot(@"/basebin/bootstrapd"), @[@"exit"], nil, nil); + + //jbroot unavailable now NSFileManager* fm = NSFileManager.defaultManager; @@ -382,7 +388,7 @@ int unbootstrap() continue; if(is_jbroot_name(item.UTF8String)) { - SYSLOG("remove %@ @ %@", item, dirpath); + STRAPLOG("remove %@ @ %@", item, dirpath); ASSERT([fm removeItemAtPath:[dirpath stringByAppendingPathComponent:item] error:nil]); } } @@ -396,7 +402,7 @@ int unbootstrap() continue; if(is_jbroot_name(item.UTF8String)) { - SYSLOG("remove %@ @ %@", item, dirpath); + STRAPLOG("remove %@ @ %@", item, dirpath); ASSERT([fm removeItemAtPath:[dirpath stringByAppendingPathComponent:item] error:nil]); } } @@ -405,6 +411,17 @@ int unbootstrap() [LSApplicationWorkspace.defaultWorkspace _LSPrivateRebuildApplicationDatabasesForSystemApps:YES internal:YES user:YES]; + AppList* tsapp = [AppList appWithBundleIdentifier:@"com.opa334.TrollStore"]; + if(tsapp) { + NSString* log=nil; + NSString* err=nil; + if(spawnRoot([tsapp.bundleURL.path stringByAppendingPathComponent:@"trollstorehelper"], @[@"refresh"], &log, &err) != 0) { + STRAPLOG("refresh tsapps failed:%@\nERR:%@", log, err); + } + } else { + STRAPLOG("trollstore not found!"); + } + killAllForApp("/usr/libexec/backboardd"); return 0; @@ -434,3 +451,16 @@ bool isSystemBootstrapped() return [bootsession isEqualToString:getBootSession()]; } + +bool checkBootstrapVersion() +{ + if(!isBootstrapInstalled()) return false; + + NSDictionary* bootinfo = [NSDictionary dictionaryWithContentsOfFile:jbroot(@"/basebin/.bootinfo.plist")]; + if(!bootinfo) return false; + + NSString* bootversion = bootinfo[@"bootversion"]; + if(!bootversion) return false; + + return [bootversion isEqualToString:NSBundle.mainBundle.infoDictionary[@"CFBundleShortVersionString"]]; +} diff --git a/Bootstrap/credits.h b/Bootstrap/credits.h index af43871b..6d13fc3a 100644 --- a/Bootstrap/credits.h +++ b/Bootstrap/credits.h @@ -2,10 +2,13 @@ #define credits_h // dictionary will be sorted alphabetically NSDictionary* CREDITS = @{ +@"Nick Chan" : @"https://github.com/asdfugil", @"opa334" : @"http://github.com/opa334", @"hayden" : @"https://procursus.social/@hayden", @"CKatri" : @"https://procursus.social/@cameron", @"Alfie" : @"https://alfiecg.uk", +@"Mineek" : @"https://github.com/mineek", +@"hrtowii" : @"https://github.com/hrtowii", @"BomberFish" : @"https://twitter.com/bomberfish77", @"Évelyne" : @"http://github.com/evelyneee", @"sourcelocation" : @"http://github.com/sourcelocation", @@ -28,7 +31,6 @@ NSDictionary* CREDITS = @{ @"Nebula" : @"https://itsnebula.net", @"DuyKhanhTran" : @"https://twitter.com/TranKha50277352", @"Nathan" : @"https://github.com/verygenericname", -@"Nick Chan" : @"https://nickchan.lol", @"Muirey03" : @"https://twitter.com/Muirey03", @"absidue" : @"https://github.com/absidue", @"MasterMike" : @"https://ios.cfw.guide", @@ -55,6 +57,7 @@ NSDictionary* CREDITS = @{ @"akusio" : @"https://twitter.com/akusio_rr", @"xsf1re" : @"https://twitter.com/xsf1re", @"PoomSmart" : @"https://twitter.com/poomsmart", +@"katana" : @"https://twitter.com/nsbedtime", @"Elias Sfeir" : @"https://twitter.com/eliassfeir1", @"SquidGesture" : @"https://twitter.com/lclrc", @"yandevelop" : @"https://twitter.com/yandevelop", diff --git a/Bootstrap/main.m b/Bootstrap/main.m index 736fed88..d4097cd8 100644 --- a/Bootstrap/main.m +++ b/Bootstrap/main.m @@ -23,6 +23,15 @@ int main(int argc, char * argv[]) { } else if(strcmp(argv[1], "disableapp")==0) { int disableForApp(NSString* bundlePath); exit(disableForApp(@(argv[2]))); + } else if(strcmp(argv[1], "rebuildiconcache")==0) { + int rebuildIconCache(); + exit(rebuildIconCache()); + } else if(strcmp(argv[1], "reboot")==0) { + sync(); + sleep(1); + reboot(0); + sleep(5); + exit(-1); } else if(strcmp(argv[1], "testprefs")==0) { SYSLOG("locale=%@", [NSUserDefaults.appDefaults valueForKey:@"locale"]); [NSUserDefaults.appDefaults setValue:@"CA" forKey:@"locale"]; diff --git a/Bootstrap/utils.h b/Bootstrap/utils.h index ff5a7494..f796c068 100644 --- a/Bootstrap/utils.h +++ b/Bootstrap/utils.h @@ -32,4 +32,18 @@ BOOL isDefaultInstallationPath(NSString* _path); void killAllForApp(const char* bundlePath); +@interface LSApplicationWorkspace : NSObject ++ (id)defaultWorkspace; +- (BOOL)openApplicationWithBundleID:(id)arg1; +- (BOOL)_LSPrivateRebuildApplicationDatabasesForSystemApps:(BOOL)arg1 + internal:(BOOL)arg2 + user:(BOOL)arg3; +@end + +@interface LSPlugInKitProxy : NSObject ++(id)pluginKitProxyForIdentifier:(id)arg1 ; +- (NSString *)bundleIdentifier; +@property (nonatomic,readonly) NSURL *dataContainerURL; +@end + #endif /* utils_h */ diff --git a/Bootstrap/utils.m b/Bootstrap/utils.m index 16dc3eff..62de795e 100644 --- a/Bootstrap/utils.m +++ b/Bootstrap/utils.m @@ -283,7 +283,7 @@ int spawnRoot(NSString* path, NSArray* args, NSString** stdOut, NSString** stdEr return retval; } -void machoEnumerateArchs(FILE* machoFile, void (^archEnumBlock)(struct mach_header_64* header, uint32_t offset, bool* stop)) +void machoEnumerateArchs(FILE* machoFile, bool (^archEnumBlock)(struct mach_header_64* header, uint32_t offset)) { struct mach_header_64 mh={0}; if(fseek(machoFile,0,SEEK_SET)!=0)return; @@ -308,15 +308,13 @@ void machoEnumerateArchs(FILE* machoFile, void (^archEnumBlock)(struct mach_head if(mh.magic != MH_MAGIC_64 && mh.magic != MH_CIGAM_64) continue; //require Macho64 - bool stop = false; - archEnumBlock(&mh, OSSwapBigToHostInt32(fatArch.offset), &stop); - if(stop) break; + if(!archEnumBlock(&mh, OSSwapBigToHostInt32(fatArch.offset))) + break; } } else if(mh.magic == MH_MAGIC_64 || mh.magic == MH_CIGAM_64) //require Macho64 { - bool stop=false; - archEnumBlock(&mh, 0, &stop); + archEnumBlock(&mh, 0); } } @@ -327,17 +325,24 @@ void machoGetInfo(FILE* candidateFile, bool *isMachoOut, bool *isLibraryOut) __block bool isMacho=false; __block bool isLibrary = false; - machoEnumerateArchs(candidateFile, ^(struct mach_header_64* header, uint32_t offset, bool* stop) { - isMacho = true; - isLibrary = OSSwapLittleToHostInt32(header->filetype) != MH_EXECUTE; - *stop = true; + machoEnumerateArchs(candidateFile, ^bool(struct mach_header_64* header, uint32_t offset) { + switch(OSSwapLittleToHostInt32(header->filetype)) { + case MH_DYLIB: + case MH_BUNDLE: + isLibrary = true; + case MH_EXECUTE: + isMacho = true; + return false; + + default: + return true; + } }); if (isMachoOut) *isMachoOut = isMacho; if (isLibraryOut) *isLibraryOut = isLibrary; } - #define APP_PATH_PREFIX "/private/var/containers/Bundle/Application/" BOOL isDefaultInstallationPath(NSString* _path) diff --git a/Makefile b/Makefile index 130951f0..e0e75904 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ XCODE_SCHEME = Bootstrap XCODEPROJ_NAME = Bootstrap -Bootstrap_XCODEFLAGS = MARKETING_VERSION=$(THEOS_PACKAGE_BASE_VERSION) \ +Bootstrap_XCODEFLAGS = \ IPHONEOS_DEPLOYMENT_TARGET="$(IPHONEOS_DEPLOYMENT_TARGET)" \ CODE_SIGN_IDENTITY="" \ AD_HOC_CODE_SIGNING_ALLOWED=YES