diff --git a/.clang-format b/.clang-format index eda6b7e..ce90664 100644 --- a/.clang-format +++ b/.clang-format @@ -1,9 +1,31 @@ +# Base Style BasedOnStyle: LLVM +Language: ObjC + +# Indentation IndentWidth: 4 ObjCBlockIndentWidth: 4 UseTab: Never ColumnLimit: 100 AccessModifierOffset: -4 +IndentCaseLabels: true +NamespaceIndentation: Inner + +# Alignment +AlignConsecutiveAssignments: Consecutive +AlignConsecutiveDeclarations: Consecutive +AlignConsecutiveMacros: Consecutive +AlignTrailingComments: true +AlignOperands: true +AlignAfterOpenBracket: Align + +# Objective-C specific +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: true +ObjCBreakBeforeNestedBlockParam: true +ObjCBinPackProtocolList: Never + +# Breaking and wrapping AllowShortBlocksOnASingleLine: Empty AllowShortFunctionsOnASingleLine: Empty AllowShortCaseLabelsOnASingleLine: false @@ -11,4 +33,36 @@ AllowShortEnumsOnASingleLine: false AllowShortIfStatementsOnASingleLine: Never AllowShortLambdasOnASingleLine: Empty AllowShortLoopsOnASingleLine: false -AlignConsecutiveAssignments: Consecutive \ No newline at end of file +BreakBeforeBraces: Custom +BraceWrapping: + AfterObjCDeclaration: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + +# Spaces +SpaceAfterCStyleCast: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: true +SpacesInParentheses: false +SpacesInSquareBrackets: false + +# Import ordering +SortIncludes: true +IncludeBlocks: Regroup +IncludeCategories: + # System headers with brackets + - Regex: "^<" + Priority: 1 + # Main header (matching filename) + - Regex: '^"[^/]*\.h"$' + Priority: 2 + # Local/Project headers + - Regex: '^"' + Priority: 3 \ No newline at end of file diff --git a/Headers/LoaderConfig.h b/Headers/LoaderConfig.h index a8cb7f3..fd80958 100644 --- a/Headers/LoaderConfig.h +++ b/Headers/LoaderConfig.h @@ -1,8 +1,8 @@ #import -@interface LoaderConfig : NSObject -@property(nonatomic, assign) BOOL customLoadUrlEnabled; -@property(nonatomic, strong) NSURL *customLoadUrl; +@interface LoaderConfig : NSObject +@property (nonatomic, assign) BOOL customLoadUrlEnabled; +@property (nonatomic, strong) NSURL *customLoadUrl; + (instancetype)defaultConfig; + (instancetype)getLoaderConfig; - (instancetype)init; diff --git a/Headers/Logger.h b/Headers/Logger.h index fce7b0e..09b7f20 100644 --- a/Headers/Logger.h +++ b/Headers/Logger.h @@ -1,4 +1,4 @@ #import -#define LOG_PREFIX @"[Bunny]" +#define LOG_PREFIX @"[Bunny]" #define BunnyLog(fmt, ...) NSLog((LOG_PREFIX @" " fmt), ##__VA_ARGS__) \ No newline at end of file diff --git a/Headers/Settings.h b/Headers/Settings.h index 9160c7e..37385fa 100644 --- a/Headers/Settings.h +++ b/Headers/Settings.h @@ -7,4 +7,4 @@ @end extern id gBridge; -void showSettingsSheet(void); \ No newline at end of file +void showSettingsSheet(void); \ No newline at end of file diff --git a/Headers/Utils.h b/Headers/Utils.h index 7766cac..b75427d 100644 --- a/Headers/Utils.h +++ b/Headers/Utils.h @@ -4,24 +4,24 @@ @class BunnySettingsViewController; extern BOOL isJailbroken; -BOOL isSafeModeEnabled(void); -NSURL *getPyoncordDirectory(void); -UIColor *hexToUIColor(NSString *hex); -NSString *getDeviceIdentifier(void); -void showErrorAlert(NSString *title, NSString *message, void (^completion)(void)); -void reloadApp(UIViewController *viewController); -void deletePlugins(void); -void deleteThemes(void); -void deleteAllData(UIViewController *presenter); -void refetchBundle(UIViewController *presenter); -void toggleSafeMode(void); -void setCustomBundleURL(NSURL *url, UIViewController *presenter); -void resetCustomBundleURL(UIViewController *presenter); -void showBundleSelector(UIViewController *presenter); -void removeCachedBundle(void); -void gracefulExit(UIViewController *presenter); -void deletePluginsAndReload(UIViewController *presenter); -void deleteThemesAndReload(UIViewController *presenter); -void handleBadBundleAttempt(UIViewController *presenter); +BOOL isSafeModeEnabled(void); +NSURL *getPyoncordDirectory(void); +UIColor *hexToUIColor(NSString *hex); +NSString *getDeviceIdentifier(void); +void showErrorAlert(NSString *title, NSString *message, void (^completion)(void)); +void reloadApp(UIViewController *viewController); +void deletePlugins(void); +void deleteThemes(void); +void deleteAllData(UIViewController *presenter); +void refetchBundle(UIViewController *presenter); +void toggleSafeMode(void); +void setCustomBundleURL(NSURL *url, UIViewController *presenter); +void resetCustomBundleURL(UIViewController *presenter); +void showBundleSelector(UIViewController *presenter); +void removeCachedBundle(void); +void gracefulExit(UIViewController *presenter); +void deletePluginsAndReload(UIViewController *presenter); +void deleteThemesAndReload(UIViewController *presenter); +void handleBadBundleAttempt(UIViewController *presenter); NSString *decryptString(NSString *encrypted); \ No newline at end of file diff --git a/Sources/Fonts.x b/Sources/Fonts.x index 3fd06b0..ed0dd4b 100644 --- a/Sources/Fonts.x +++ b/Sources/Fonts.x @@ -1,17 +1,20 @@ -#import "Fonts.h" -#import "Logger.h" -#import "Utils.h" #import #import #import +#import "Fonts.h" +#import "Logger.h" +#import "Utils.h" + NSMutableDictionary *fontMap; %hook UIFont -+ (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size { ++ (UIFont *)fontWithName:(NSString *)name size:(CGFloat)size +{ NSString *replacementName = fontMap[name]; - if (replacementName) { + if (replacementName) + { UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; UIFontDescriptor *fallbackDescriptor = @@ -28,9 +31,11 @@ NSMutableDictionary *fontMap; return %orig; } -+ (UIFont *)fontWithDescriptor:(UIFontDescriptor *)descriptor size:(CGFloat)size { ++ (UIFont *)fontWithDescriptor:(UIFontDescriptor *)descriptor size:(CGFloat)size +{ NSString *replacementName = fontMap[descriptor.postscriptName]; - if (replacementName) { + if (replacementName) + { UIFontDescriptor *replacementDescriptor = [UIFontDescriptor fontDescriptorWithName:replacementName size:size]; UIFontDescriptor *finalDescriptor = @@ -43,17 +48,21 @@ NSMutableDictionary *fontMap; return %orig; } -+ (UIFont *)systemFontOfSize:(CGFloat)size { ++ (UIFont *)systemFontOfSize:(CGFloat)size +{ NSString *replacementName = fontMap[@"systemFont"]; - if (replacementName) { + if (replacementName) + { return [UIFont fontWithName:replacementName size:size]; } return %orig; } -+ (UIFont *)preferredFontForTextStyle:(UIFontTextStyle)style { ++ (UIFont *)preferredFontForTextStyle:(UIFontTextStyle)style +{ NSString *replacementName = fontMap[@"systemFont"]; - if (replacementName) { + if (replacementName) + { return [UIFont fontWithName:replacementName size:[UIFont systemFontSize]]; } return %orig; @@ -61,10 +70,12 @@ NSMutableDictionary *fontMap; %end -void patchFonts(NSDictionary *mainFonts, NSString *fontDefName) { +void patchFonts(NSDictionary *mainFonts, NSString *fontDefName) +{ BunnyLog(@"patchFonts called with fonts: %@ and def name: %@", mainFonts, fontDefName); - if (!fontMap) { + if (!fontMap) + { BunnyLog(@"Creating new fontMap"); fontMap = [NSMutableDictionary dictionary]; } @@ -73,15 +84,17 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD stringWithContentsOfURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fonts.json"] encoding:NSUTF8StringEncoding error:nil]; - if (fontJson) { + if (fontJson) + { BunnyLog(@"Found existing fonts.json: %@", fontJson); } - for (NSString *fontName in mainFonts) { + for (NSString *fontName in mainFonts) + { NSString *url = mainFonts[fontName]; BunnyLog(@"Replacing font %@ with URL: %@", fontName, url); - NSURL *fontURL = [NSURL URLWithString:url]; + NSURL *fontURL = [NSURL URLWithString:url]; NSString *fontExtension = fontURL.pathExtension; NSURL *fontCachePath = [[[getPyoncordDirectory() URLByAppendingPathComponent:@"downloads" @@ -95,7 +108,8 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD stringWithFormat:@"%@.%@", fontName, fontExtension]]; NSURL *parentDir = [fontCachePath URLByDeletingLastPathComponent]; - if (![[NSFileManager defaultManager] fileExistsAtPath:parentDir.path]) { + if (![[NSFileManager defaultManager] fileExistsAtPath:parentDir.path]) + { BunnyLog(@"Creating parent directory: %@", parentDir.path); [[NSFileManager defaultManager] createDirectoryAtURL:parentDir withIntermediateDirectories:YES @@ -103,33 +117,39 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD error:nil]; } - if (![[NSFileManager defaultManager] fileExistsAtPath:fontCachePath.path]) { + if (![[NSFileManager defaultManager] fileExistsAtPath:fontCachePath.path]) + { BunnyLog(@"Downloading font %@ from %@", fontName, url); NSData *data = [NSData dataWithContentsOfURL:fontURL]; - if (data) { + if (data) + { BunnyLog(@"Writing font data to: %@", fontCachePath.path); [data writeToURL:fontCachePath atomically:YES]; } } NSData *fontData = [NSData dataWithContentsOfURL:fontCachePath]; - if (fontData) { + if (fontData) + { BunnyLog(@"Registering font %@ with provider", fontName); CGDataProviderRef provider = - CGDataProviderCreateWithCFData((__bridge CFDataRef)fontData); + CGDataProviderCreateWithCFData((__bridge CFDataRef) fontData); CGFontRef font = CGFontCreateWithDataProvider(provider); - if (font) { + if (font) + { CFStringRef postScriptName = CGFontCopyPostScriptName(font); CTFontRef existingFont = CTFontCreateWithName(postScriptName, 0, NULL); - if (existingFont) { + if (existingFont) + { CFErrorRef unregisterError = NULL; - if (!CTFontManagerUnregisterGraphicsFont(font, &unregisterError)) { + if (!CTFontManagerUnregisterGraphicsFont(font, &unregisterError)) + { BunnyLog(@"Failed to deregister font %@: %@", - (__bridge NSString *)postScriptName, + (__bridge NSString *) postScriptName, unregisterError - ? (__bridge NSString *)CFErrorCopyDescription(unregisterError) + ? (__bridge NSString *) CFErrorCopyDescription(unregisterError) : @"Unknown error"); if (unregisterError) CFRelease(unregisterError); @@ -138,23 +158,28 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD } CFErrorRef error = NULL; - if (CTFontManagerRegisterGraphicsFont(font, &error)) { - fontMap[fontName] = (__bridge NSString *)postScriptName; + if (CTFontManagerRegisterGraphicsFont(font, &error)) + { + fontMap[fontName] = (__bridge NSString *) postScriptName; BunnyLog(@"Successfully registered font %@ to %@", fontName, - (__bridge NSString *)postScriptName); + (__bridge NSString *) postScriptName); NSError *jsonError; - NSData *jsonData = [NSJSONSerialization dataWithJSONObject:fontMap + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:fontMap options:0 error:&jsonError]; - if (!jsonError) { + if (!jsonError) + { [jsonData writeToURL:[getPyoncordDirectory() URLByAppendingPathComponent:@"fontMap.json"] atomically:YES]; } - } else { - NSString *errorDesc = error ? (__bridge NSString *)CFErrorCopyDescription(error) - : @"Unknown error"; + } + else + { + NSString *errorDesc = error + ? (__bridge NSString *) CFErrorCopyDescription(error) + : @"Unknown error"; BunnyLog(@"Failed to register font %@: %@", fontName, errorDesc); if (error) CFRelease(error); @@ -168,8 +193,10 @@ void patchFonts(NSDictionary *mainFonts, NSString *fontD } } -%ctor { - @autoreleasepool { +%ctor +{ + @autoreleasepool + { fontMap = [NSMutableDictionary dictionary]; BunnyLog(@"Font hooks initialized"); %init; diff --git a/Sources/Sideloading.x b/Sources/Sideloading.x index 5739a2b..88d7899 100644 --- a/Sources/Sideloading.x +++ b/Sources/Sideloading.x @@ -1,5 +1,3 @@ -#import "Logger.h" -#import "Utils.h" #import #import #import @@ -7,74 +5,82 @@ #import #import +#import "Logger.h" +#import "Utils.h" + typedef struct __CMSDecoder *CMSDecoderRef; -extern CFTypeRef SecCMSDecodeGetContent(CFDataRef message); -extern OSStatus CMSDecoderCreate(CMSDecoderRef *cmsDecoder); -extern OSStatus CMSDecoderUpdateMessage(CMSDecoderRef cmsDecoder, const void *content, - size_t contentLength); -extern OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder); -extern OSStatus CMSDecoderCopyContent(CMSDecoderRef cmsDecoder, CFDataRef *content); +extern CFTypeRef SecCMSDecodeGetContent(CFDataRef message); +extern OSStatus CMSDecoderCreate(CMSDecoderRef *cmsDecoder); +extern OSStatus CMSDecoderUpdateMessage(CMSDecoderRef cmsDecoder, const void *content, + size_t contentLength); +extern OSStatus CMSDecoderFinalizeMessage(CMSDecoderRef cmsDecoder); +extern OSStatus CMSDecoderCopyContent(CMSDecoderRef cmsDecoder, CFDataRef *content); #define DISCORD_BUNDLE_ID @"com.hammerandchisel.discord" -#define DISCORD_NAME @"Discord" +#define DISCORD_NAME @"Discord" typedef NS_ENUM(NSInteger, BundleIDError) { BundleIDErrorIcon, BundleIDErrorPasskey }; -static void showBundleIDError(BundleIDError error) { +static void showBundleIDError(BundleIDError error) +{ NSString *message; NSString *title; void (^completion)(void) = nil; - switch (error) { - case BundleIDErrorIcon: - message = @"For this to work change the Bundle ID so that it matches your " - @"provisioning profile's App ID (excluding the Team ID prefix)."; - title = @"Cannot Change Icon"; - break; - case BundleIDErrorPasskey: - message = @"Passkeys are not supported when sideloading Discord. " - @"Please use a different login method."; - title = @"Cannot Use Passkey"; - completion = ^{ exit(0); }; - break; + switch (error) + { + case BundleIDErrorIcon: + message = @"For this to work change the Bundle ID so that it matches your " + @"provisioning profile's App ID (excluding the Team ID prefix)."; + title = @"Cannot Change Icon"; + break; + case BundleIDErrorPasskey: + message = @"Passkeys are not supported when sideloading Discord. " + @"Please use a different login method."; + title = @"Cannot Use Passkey"; + completion = ^{ exit(0); }; + break; } showErrorAlert(title, message, completion); } -static NSString *getAccessGroupID(void) { +static NSString *getAccessGroupID(void) +{ NSDictionary *query = @{ - (__bridge NSString *)kSecClass : (__bridge NSString *)kSecClassGenericPassword, - (__bridge NSString *)kSecAttrAccount : @"bundleSeedID", - (__bridge NSString *)kSecAttrService : @"", - (__bridge NSString *)kSecReturnAttributes : @YES + (__bridge NSString *) kSecClass : (__bridge NSString *) kSecClassGenericPassword, + (__bridge NSString *) kSecAttrAccount : @"bundleSeedID", + (__bridge NSString *) kSecAttrService : @"", + (__bridge NSString *) kSecReturnAttributes : @YES }; CFDictionaryRef result = NULL; - OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, (CFTypeRef *) &result); - if (status == errSecItemNotFound) { - status = SecItemAdd((__bridge CFDictionaryRef)query, (CFTypeRef *)&result); + if (status == errSecItemNotFound) + { + status = SecItemAdd((__bridge CFDictionaryRef) query, (CFTypeRef *) &result); } if (status != errSecSuccess) return nil; NSString *accessGroup = - [(__bridge NSDictionary *)result objectForKey:(__bridge NSString *)kSecAttrAccessGroup]; + [(__bridge NSDictionary *) result objectForKey:(__bridge NSString *) kSecAttrAccessGroup]; if (result) CFRelease(result); return accessGroup; } -static BOOL isSelfCall(void) { +static BOOL isSelfCall(void) +{ NSArray *address = [NSThread callStackReturnAddresses]; - Dl_info info = {0}; - if (dladdr((void *)[address[2] longLongValue], &info) == 0) + Dl_info info = {0}; + if (dladdr((void *) [address[2] longLongValue], &info) == 0) return NO; NSString *path = [NSString stringWithUTF8String:info.dli_fname]; return [path hasPrefix:NSBundle.mainBundle.bundlePath]; @@ -83,11 +89,13 @@ static BOOL isSelfCall(void) { %group Sideloading %hook NSBundle -- (NSString *)bundleIdentifier { +- (NSString *)bundleIdentifier +{ return isSelfCall() ? DISCORD_BUNDLE_ID : %orig; } -- (NSDictionary *)infoDictionary { +- (NSDictionary *)infoDictionary +{ if (!isSelfCall()) return %orig; @@ -98,7 +106,8 @@ static BOOL isSelfCall(void) { return info; } -- (id)objectForInfoDictionaryKey:(NSString *)key { +- (id)objectForInfoDictionaryKey:(NSString *)key +{ if (!isSelfCall()) return %orig; @@ -111,31 +120,35 @@ static BOOL isSelfCall(void) { %end %hook NSFileManager -- (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier { +- (NSURL *)containerURLForSecurityApplicationGroupIdentifier:(NSString *)groupIdentifier +{ BunnyLog(@"containerURLForSecurityApplicationGroupIdentifier called! %@", groupIdentifier ?: @"nil"); - NSArray *paths = [self URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; - NSURL *lastPath = [paths lastObject]; + NSArray *paths = [self URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; + NSURL *lastPath = [paths lastObject]; return [lastPath URLByAppendingPathComponent:@"AppGroup"]; } %end %hook UIPasteboard -- (NSString *)_accessGroup { +- (NSString *)_accessGroup +{ return getAccessGroupID(); } %end %hook UIApplication -- (void)setAlternateIconName:(NSString *)iconName - completionHandler:(void (^)(NSError *))completion { +- (void)setAlternateIconName:(NSString *)iconName completionHandler:(void (^)(NSError *))completion +{ void (^wrappedCompletion)(NSError *) = ^(NSError *error) { - if (error) { + if (error) + { showBundleIDError(BundleIDErrorIcon); } - if (completion) { + if (completion) + { completion(error); } }; @@ -147,27 +160,33 @@ static BOOL isSelfCall(void) { // /~https://github.com/khanhduytran0/LiveContainer/blob/main/TweakLoader/DocumentPicker.m %hook UIDocumentPickerViewController -- (instancetype)initForOpeningContentTypes:(NSArray *)contentTypes asCopy:(BOOL)asCopy { +- (instancetype)initForOpeningContentTypes:(NSArray *)contentTypes asCopy:(BOOL)asCopy +{ BOOL shouldMultiselect = NO; - if ([contentTypes count] == 1 && contentTypes[0] == UTTypeFolder) { + if ([contentTypes count] == 1 && contentTypes[0] == UTTypeFolder) + { shouldMultiselect = YES; } NSArray *contentTypesNew = @[ UTTypeItem, UTTypeFolder ]; UIDocumentPickerViewController *ans = %orig(contentTypesNew, YES); - if (shouldMultiselect) { + if (shouldMultiselect) + { [ans setAllowsMultipleSelection:YES]; } return ans; } -- (instancetype)initWithDocumentTypes:(NSArray *)contentTypes inMode:(NSUInteger)mode { +- (instancetype)initWithDocumentTypes:(NSArray *)contentTypes inMode:(NSUInteger)mode +{ return [self initForOpeningContentTypes:contentTypes asCopy:(mode == 1 ? NO : YES)]; } -- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection { - if ([self allowsMultipleSelection]) { +- (void)setAllowsMultipleSelection:(BOOL)allowsMultipleSelection +{ + if ([self allowsMultipleSelection]) + { return; } %orig(YES); @@ -177,7 +196,8 @@ static BOOL isSelfCall(void) { %hook UIDocumentBrowserViewController -- (instancetype)initForOpeningContentTypes:(NSArray *)contentTypes { +- (instancetype)initForOpeningContentTypes:(NSArray *)contentTypes +{ NSArray *contentTypesNew = @[ UTTypeItem, UTTypeFolder ]; return %orig(contentTypesNew); } @@ -186,7 +206,8 @@ static BOOL isSelfCall(void) { %hook NSURL -- (BOOL)startAccessingSecurityScopedResource { +- (BOOL)startAccessingSecurityScopedResource +{ %orig; return YES; } @@ -195,7 +216,8 @@ static BOOL isSelfCall(void) { %hook ASAuthorizationController -- (void)performRequests { +- (void)performRequests +{ showBundleIDError(BundleIDErrorPasskey); } @@ -203,10 +225,12 @@ static BOOL isSelfCall(void) { %end -%ctor { +%ctor +{ BOOL isAppStoreApp = [[NSFileManager defaultManager] fileExistsAtPath:[[NSBundle mainBundle] appStoreReceiptURL].path]; - if (!isAppStoreApp) { + if (!isAppStoreApp) + { %init(Sideloading); } } diff --git a/Sources/Tweak.x b/Sources/Tweak.x index 8c2b212..436b6f7 100644 --- a/Sources/Tweak.x +++ b/Sources/Tweak.x @@ -1,26 +1,29 @@ +#import +#import + #import "Fonts.h" #import "LoaderConfig.h" #import "Logger.h" #import "Settings.h" #import "Themes.h" #import "Utils.h" -#import -#import static NSString *const kBlockedString = @"MCc0JywlJw=="; -static NSURL *source; -static NSString *bunnyPatchesBundlePath; -static NSURL *pyoncordDirectory; -static LoaderConfig *loaderConfig; +static NSURL *source; +static NSString *bunnyPatchesBundlePath; +static NSURL *pyoncordDirectory; +static LoaderConfig *loaderConfig; static NSTimeInterval shakeStartTime = 0; -static BOOL isShaking = NO; -id gBridge = nil; +static BOOL isShaking = NO; +id gBridge = nil; %hook RCTCxxBridge -- (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async { - if (![url.absoluteString containsString:@"main.jsbundle"]) { +- (void)executeApplicationScript:(NSData *)script url:(NSURL *)url async:(BOOL)async +{ + if (![url.absoluteString containsString:@"main.jsbundle"]) + { return %orig; } @@ -28,7 +31,8 @@ id gBridge = nil; BunnyLog(@"Stored bridge reference: %@", gBridge); NSBundle *bunnyPatchesBundle = [NSBundle bundleWithPath:bunnyPatchesBundlePath]; - if (!bunnyPatchesBundle) { + if (!bunnyPatchesBundle) + { BunnyLog(@"Failed to load BunnyPatches bundle from path: %@", bunnyPatchesBundlePath); showErrorAlert(@"Loader Error", @"Failed to initialize mod loader. Please reinstall the tweak.", nil); @@ -36,7 +40,8 @@ id gBridge = nil; } NSURL *patchPath = [bunnyPatchesBundle URLForResource:@"payload-base" withExtension:@"js"]; - if (!patchPath) { + if (!patchPath) + { BunnyLog(@"Failed to find payload-base.js in bundle"); showErrorAlert(@"Loader Error", @"Failed to initialize mod loader. Please reinstall the tweak.", nil); @@ -54,9 +59,11 @@ id gBridge = nil; dispatch_group_enter(group); NSURL *bundleUrl; - if (loaderConfig.customLoadUrlEnabled && loaderConfig.customLoadUrl) { + if (loaderConfig.customLoadUrlEnabled && loaderConfig.customLoadUrl) + { NSString *urlString = loaderConfig.customLoadUrl.absoluteString.lowercaseString; - if ([urlString containsString:decryptString(kBlockedString)]) { + if ([urlString containsString:decryptString(kBlockedString)]) + { dispatch_async(dispatch_get_main_queue(), ^{ UIViewController *rootVC = [UIApplication sharedApplication].windows.firstObject.rootViewController; @@ -67,10 +74,12 @@ id gBridge = nil; NSData *existingBundle = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"]]; - if (existingBundle) { + if (existingBundle) + { NSString *bundleContent = [[NSString alloc] initWithData:existingBundle encoding:NSUTF8StringEncoding]; - if ([bundleContent.lowercaseString containsString:decryptString(kBlockedString)]) { + if ([bundleContent.lowercaseString containsString:decryptString(kBlockedString)]) + { dispatch_async(dispatch_get_main_queue(), ^{ UIViewController *rootVC = [UIApplication sharedApplication].windows.firstObject.rootViewController; @@ -82,7 +91,9 @@ id gBridge = nil; bundleUrl = loaderConfig.customLoadUrl; BunnyLog(@"Using custom load URL: %@", bundleUrl.absoluteString); - } else { + } + else + { bundleUrl = [NSURL URLWithString:@"https://raw.githubusercontent.com/bunny-mod/builds/main/bunny.min.js"]; BunnyLog(@"Using default bundle URL: %@", bundleUrl.absoluteString); @@ -97,7 +108,8 @@ id gBridge = nil; stringWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] encoding:NSUTF8StringEncoding error:nil]; - if (bundleEtag && bundle) { + if (bundleEtag && bundle) + { [bundleRequest setValue:bundleEtag forHTTPHeaderField:@"If-None-Match"]; } @@ -106,16 +118,19 @@ id gBridge = nil; [[session dataTaskWithRequest:bundleRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { - if ([response isKindOfClass:[NSHTTPURLResponse class]]) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - if (httpResponse.statusCode == 200) { + if ([response isKindOfClass:[NSHTTPURLResponse class]]) + { + NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response; + if (httpResponse.statusCode == 200) + { bundle = data; [bundle writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"bundle.js"] atomically:YES]; NSString *etag = [httpResponse.allHeaderFields objectForKey:@"Etag"]; - if (etag) { + if (etag) + { [etag writeToURL:[pyoncordDirectory URLByAppendingPathComponent:@"etag.txt"] atomically:YES @@ -132,16 +147,20 @@ id gBridge = nil; NSData *themeData = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"current-theme.json"]]; - if (themeData) { - NSError *jsonError; + if (themeData) + { + NSError *jsonError; NSDictionary *themeDict = [NSJSONSerialization JSONObjectWithData:themeData options:0 error:&jsonError]; - if (!jsonError) { + if (!jsonError) + { BunnyLog(@"Loading theme data..."); - if (themeDict[@"data"]) { + if (themeDict[@"data"]) + { NSDictionary *data = themeDict[@"data"]; - if (data[@"semanticColors"] && data[@"rawColors"]) { + if (data[@"semanticColors"] && data[@"rawColors"]) + { BunnyLog(@"Initializing theme colors from theme data"); initializeThemeColors(data[@"semanticColors"], data[@"rawColors"]); } @@ -152,51 +171,65 @@ id gBridge = nil; [[NSString alloc] initWithData:themeData encoding:NSUTF8StringEncoding]]; %orig([jsCode dataUsingEncoding:NSUTF8StringEncoding], source, async); - } else { + } + else + { BunnyLog(@"Error parsing theme JSON: %@", jsonError); } - } else { + } + else + { BunnyLog(@"No theme data found at path: %@", [pyoncordDirectory URLByAppendingPathComponent:@"current-theme.json"]); } NSData *fontData = [NSData dataWithContentsOfURL:[pyoncordDirectory URLByAppendingPathComponent:@"fonts.json"]]; - if (fontData) { - NSError *jsonError; + if (fontData) + { + NSError *jsonError; NSDictionary *fontDict = [NSJSONSerialization JSONObjectWithData:fontData options:0 error:&jsonError]; - if (!jsonError && fontDict[@"main"]) { + if (!jsonError && fontDict[@"main"]) + { BunnyLog(@"Found font configuration, applying..."); patchFonts(fontDict[@"main"], fontDict[@"name"]); } } - if (bundle) { + if (bundle) + { BunnyLog(@"Executing JS bundle"); %orig(bundle, source, async); } NSURL *preloadsDirectory = [pyoncordDirectory URLByAppendingPathComponent:@"preloads"]; - if ([[NSFileManager defaultManager] fileExistsAtPath:preloadsDirectory.path]) { + if ([[NSFileManager defaultManager] fileExistsAtPath:preloadsDirectory.path]) + { NSError *error = nil; NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:preloadsDirectory includingPropertiesForKeys:nil options:0 error:&error]; - if (!error) { - for (NSURL *fileURL in contents) { - if ([[fileURL pathExtension] isEqualToString:@"js"]) { + if (!error) + { + for (NSURL *fileURL in contents) + { + if ([[fileURL pathExtension] isEqualToString:@"js"]) + { BunnyLog(@"Executing preload JS file %@", fileURL.absoluteString); NSData *data = [NSData dataWithContentsOfURL:fileURL]; - if (data) { + if (data) + { %orig(data, source, async); } } } - } else { + } + else + { BunnyLog(@"Error reading contents of preloads directory"); } } @@ -208,20 +241,25 @@ id gBridge = nil; %hook UIWindow -- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { - if (motion == UIEventSubtypeMotionShake) { +- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event +{ + if (motion == UIEventSubtypeMotionShake) + { isShaking = YES; shakeStartTime = [[NSDate date] timeIntervalSince1970]; } %orig; } -- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event { - if (motion == UIEventSubtypeMotionShake && isShaking) { +- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event +{ + if (motion == UIEventSubtypeMotionShake && isShaking) + { NSTimeInterval currentTime = [[NSDate date] timeIntervalSince1970]; NSTimeInterval shakeDuration = currentTime - shakeStartTime; - if (shakeDuration >= 0.5 && shakeDuration <= 2.0) { + if (shakeDuration >= 0.5 && shakeDuration <= 2.0) + { dispatch_async(dispatch_get_main_queue(), ^{ showSettingsSheet(); }); } isShaking = NO; @@ -231,8 +269,10 @@ id gBridge = nil; %end -%ctor { - @autoreleasepool { +%ctor +{ + @autoreleasepool + { source = [NSURL URLWithString:@"bunny"]; NSString *install_prefix = @"/var/jb"; @@ -259,9 +299,12 @@ id gBridge = nil; NSArray *bundleContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:bunnyPatchesBundlePath error:&error]; - if (error) { + if (error) + { BunnyLog(@"Error listing bundle contents: %@", error); - } else { + } + else + { BunnyLog(@"Bundle contents: %@", bundleContents); } diff --git a/app-repo.json b/app-repo.json index 64d9c80..8bf607b 100644 --- a/app-repo.json +++ b/app-repo.json @@ -12,12 +12,6 @@ "subtitle": "A client mod for Discord", "tintColor": "7289da", "versions": [ - { - "version": "266.0", - "date": "2025-02-11", - "size": 88451372, - "downloadURL": "/~https://github.com/bunny-mod/BunnyTweak/releases/download/v266.0/Bunny.ipa" - }, { "version": "265.0", "date": "2025-02-06",