mirror of
https://github.com/NohamR/Tweaks.git
synced 2026-10-10 18:29:48 +00:00
Clean up and export metadata
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
TARGET = iphone:latest:15.0
|
TARGET = iphone:latest:15.0
|
||||||
ARCHS = arm64 arm64e
|
ARCHS = arm64
|
||||||
INSTALL_TARGET_PROCESSES = fr.lecanardenchaine.app
|
INSTALL_TARGET_PROCESSES = fr.lecanardenchaine.app
|
||||||
|
|
||||||
include $(THEOS)/makefiles/common.mk
|
include $(THEOS)/makefiles/common.mk
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
// log stream --predicate 'process == "LeCanardEnchaine" AND eventMessage contains "CanardDumper" ' --level default --style compact
|
||||||
|
|
||||||
#import <substrate.h>
|
#import <substrate.h>
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
@@ -6,57 +8,131 @@
|
|||||||
|
|
||||||
static NSString *const kCanardLogTag = @"[CanardDumper]";
|
static NSString *const kCanardLogTag = @"[CanardDumper]";
|
||||||
static NSString *const kCanardDumpDirectoryName = @"CanardDumps";
|
static NSString *const kCanardDumpDirectoryName = @"CanardDumps";
|
||||||
|
static NSString *const kCanardReaderFirstOpenKey = @"READER_FIRST_OPEN";
|
||||||
|
static NSString *const kCanardFirebaseSessionsSettingsKey = @"firebase-sessions-settings";
|
||||||
|
static NSString *const kCanardCatalogManagerDefaultsDomain = @"com.immanens.datamanager.CatalogManager.default";
|
||||||
|
|
||||||
|
static NSString *const kCanardFirebaseCollectAnrsKey = @"collect_anrs";
|
||||||
|
static NSString *const kCanardFirebaseCollectBuildIdsKey = @"collect_build_ids";
|
||||||
|
static NSString *const kCanardFirebaseCollectLoggedExceptionsKey = @"collect_logged_exceptions";
|
||||||
|
static NSString *const kCanardFirebaseCollectReportsKey = @"collect_reports";
|
||||||
|
static NSString *const kCanardFirebaseSessionsEnabledKey = @"sessions_enabled";
|
||||||
|
static NSString *const kCanardCatalogLocalKey = @"local";
|
||||||
|
|
||||||
#pragma mark - State
|
#pragma mark - State
|
||||||
|
|
||||||
static NSString *CanardArchivePassword;
|
static NSString *CanardArchivePassword;
|
||||||
static int CanardLastSavedReadSize = -1;
|
static NSString *CanardCurrentArchivePath;
|
||||||
|
static NSString *CanardCurrentArchiveFileName;
|
||||||
|
static NSDictionary *CanardCurrentArchiveEntry;
|
||||||
|
static NSString *CanardLastSavedToken;
|
||||||
|
|
||||||
#pragma mark - UI Helpers
|
static NSDictionary *CanardForcedFirebaseSessionsSettings(NSDictionary *currentSettings) {
|
||||||
|
NSMutableDictionary *settings = currentSettings ? [currentSettings mutableCopy] : [NSMutableDictionary dictionary];
|
||||||
|
|
||||||
static UIViewController *CanardTopViewController(UIViewController *viewController) {
|
settings[kCanardFirebaseCollectAnrsKey] = @NO;
|
||||||
if (!viewController) return nil;
|
settings[kCanardFirebaseCollectBuildIdsKey] = @NO;
|
||||||
|
settings[kCanardFirebaseCollectLoggedExceptionsKey] = @NO;
|
||||||
|
settings[kCanardFirebaseCollectReportsKey] = @NO;
|
||||||
|
settings[kCanardFirebaseSessionsEnabledKey] = @NO;
|
||||||
|
|
||||||
if (viewController.presentedViewController) {
|
return settings;
|
||||||
return CanardTopViewController(viewController.presentedViewController);
|
|
||||||
}
|
|
||||||
if ([viewController isKindOfClass:[UINavigationController class]]) {
|
|
||||||
return CanardTopViewController([(UINavigationController *)viewController visibleViewController]);
|
|
||||||
}
|
|
||||||
if ([viewController isKindOfClass:[UITabBarController class]]) {
|
|
||||||
return CanardTopViewController([(UITabBarController *)viewController selectedViewController]);
|
|
||||||
}
|
|
||||||
return viewController;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CanardPresentShareSheet(NSString *filePath) {
|
static void CanardApplyForcedDefaults(void) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
UIWindow *keyWindow = nil;
|
[defaults setBool:NO forKey:kCanardReaderFirstOpenKey];
|
||||||
for (UIWindow *window in [UIApplication sharedApplication].windows) {
|
|
||||||
if (window.isKeyWindow) {
|
|
||||||
keyWindow = window;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UIViewController *topVC = CanardTopViewController(keyWindow.rootViewController);
|
NSDictionary *existing = [defaults dictionaryForKey:kCanardFirebaseSessionsSettingsKey];
|
||||||
if (!topVC) {
|
NSDictionary *forced = CanardForcedFirebaseSessionsSettings(existing);
|
||||||
NSLog(@"%@ Unable to present share sheet", kCanardLogTag);
|
[defaults setObject:forced forKey:kCanardFirebaseSessionsSettingsKey];
|
||||||
return;
|
[defaults synchronize];
|
||||||
}
|
|
||||||
|
|
||||||
NSURL *fileURL = [NSURL fileURLWithPath:filePath];
|
NSLog(@"%@ Forced defaults applied for %@ and %@", kCanardLogTag, kCanardReaderFirstOpenKey, kCanardFirebaseSessionsSettingsKey);
|
||||||
UIActivityViewController *shareController = [[UIActivityViewController alloc] initWithActivityItems:@[fileURL] applicationActivities:nil];
|
|
||||||
shareController.popoverPresentationController.sourceView = topVC.view;
|
|
||||||
shareController.popoverPresentationController.sourceRect = CGRectMake(
|
|
||||||
CGRectGetMidX(topVC.view.bounds),
|
|
||||||
CGRectGetMidY(topVC.view.bounds),
|
|
||||||
0, 0
|
|
||||||
);
|
|
||||||
[topVC presentViewController:shareController animated:YES completion:nil];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NSArray *CanardCatalogLocalEntries(void) {
|
||||||
|
NSDictionary *domainValues = [[NSUserDefaults standardUserDefaults]
|
||||||
|
persistentDomainForName:kCanardCatalogManagerDefaultsDomain];
|
||||||
|
id local = domainValues[kCanardCatalogLocalKey];
|
||||||
|
if ([local isKindOfClass:[NSArray class]]) {
|
||||||
|
return (NSArray *)local;
|
||||||
|
}
|
||||||
|
return @[];
|
||||||
|
}
|
||||||
|
|
||||||
|
static NSDictionary *CanardCatalogEntryForFileName(NSString *fileName) {
|
||||||
|
if (fileName.length == 0) return nil;
|
||||||
|
|
||||||
|
for (id item in CanardCatalogLocalEntries()) {
|
||||||
|
if (![item isKindOfClass:[NSDictionary class]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *entry = (NSDictionary *)item;
|
||||||
|
NSString *entryFileName = entry[@"fileName"];
|
||||||
|
if ([entryFileName isKindOfClass:[NSString class]] && [entryFileName isEqualToString:fileName]) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CanardUpdateCurrentArchiveContext(NSString *archivePath) {
|
||||||
|
CanardCurrentArchivePath = [archivePath copy];
|
||||||
|
CanardCurrentArchiveFileName = [[archivePath lastPathComponent] copy];
|
||||||
|
CanardCurrentArchiveEntry = CanardCatalogEntryForFileName(CanardCurrentArchiveFileName);
|
||||||
|
CanardLastSavedToken = nil;
|
||||||
|
|
||||||
|
NSLog(@"%@ Archive context file=%@ entryFound=%@", kCanardLogTag, CanardCurrentArchiveFileName, CanardCurrentArchiveEntry ? @"YES" : @"NO");
|
||||||
|
}
|
||||||
|
|
||||||
|
// #pragma mark - UI Helpers
|
||||||
|
|
||||||
|
// static UIViewController *CanardTopViewController(UIViewController *viewController) {
|
||||||
|
// if (!viewController) return nil;
|
||||||
|
|
||||||
|
// if (viewController.presentedViewController) {
|
||||||
|
// return CanardTopViewController(viewController.presentedViewController);
|
||||||
|
// }
|
||||||
|
// if ([viewController isKindOfClass:[UINavigationController class]]) {
|
||||||
|
// return CanardTopViewController([(UINavigationController *)viewController visibleViewController]);
|
||||||
|
// }
|
||||||
|
// if ([viewController isKindOfClass:[UITabBarController class]]) {
|
||||||
|
// return CanardTopViewController([(UITabBarController *)viewController selectedViewController]);
|
||||||
|
// }
|
||||||
|
// return viewController;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// static void CanardPresentShareSheet(NSString *filePath) {
|
||||||
|
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
// UIWindow *keyWindow = nil;
|
||||||
|
// for (UIWindow *window in [UIApplication sharedApplication].windows) {
|
||||||
|
// if (window.isKeyWindow) {
|
||||||
|
// keyWindow = window;
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// UIViewController *topVC = CanardTopViewController(keyWindow.rootViewController);
|
||||||
|
// if (!topVC) {
|
||||||
|
// NSLog(@"%@ Unable to present share sheet", kCanardLogTag);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// NSURL *fileURL = [NSURL fileURLWithPath:filePath];
|
||||||
|
// UIActivityViewController *shareController = [[UIActivityViewController alloc] initWithActivityItems:@[fileURL] applicationActivities:nil];
|
||||||
|
// shareController.popoverPresentationController.sourceView = topVC.view;
|
||||||
|
// shareController.popoverPresentationController.sourceRect = CGRectMake(
|
||||||
|
// CGRectGetMidX(topVC.view.bounds),
|
||||||
|
// CGRectGetMidY(topVC.view.bounds),
|
||||||
|
// 0, 0
|
||||||
|
// );
|
||||||
|
// [topVC presentViewController:shareController animated:YES completion:nil];
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
#pragma mark - File Helpers
|
#pragma mark - File Helpers
|
||||||
|
|
||||||
static NSString *CanardSanitizedFilename(NSString *password) {
|
static NSString *CanardSanitizedFilename(NSString *password) {
|
||||||
@@ -80,27 +156,60 @@ static bool CanardSaveData(NSData *data, NSString *password) {
|
|||||||
[fm createDirectoryAtPath:dumpDir withIntermediateDirectories:YES attributes:nil error:nil];
|
[fm createDirectoryAtPath:dumpDir withIntermediateDirectories:YES attributes:nil error:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *fileName = [NSString stringWithFormat:@"file_%@.pdf", CanardSanitizedFilename(password)];
|
NSString *docStem = [[CanardCurrentArchiveFileName stringByDeletingPathExtension] copy];
|
||||||
NSString *filePath = [dumpDir stringByAppendingPathComponent:fileName];
|
if (docStem.length == 0) {
|
||||||
|
docStem = @"unknown_doc";
|
||||||
if ([data writeToFile:filePath atomically:YES]) {
|
|
||||||
NSLog(@"%@ Saved to %@ (%lu bytes)", kCanardLogTag, filePath, (unsigned long)data.length);
|
|
||||||
CanardPresentShareSheet(filePath);
|
|
||||||
return YES;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NSLog(@"%@ Failed to save to %@", kCanardLogTag, filePath);
|
NSString *safeDocStem = CanardSanitizedFilename(docStem);
|
||||||
|
NSString *safePassword = CanardSanitizedFilename(password);
|
||||||
|
NSString *baseName = [NSString stringWithFormat:@"%@_%@", safeDocStem, safePassword];
|
||||||
|
|
||||||
|
NSString *pdfPath = [dumpDir stringByAppendingPathComponent:[baseName stringByAppendingString:@".pdf"]];
|
||||||
|
NSString *jsonPath = [dumpDir stringByAppendingPathComponent:[baseName stringByAppendingString:@".json"]];
|
||||||
|
|
||||||
|
if (![data writeToFile:pdfPath atomically:YES]) {
|
||||||
|
NSLog(@"%@ Failed to save to %@", kCanardLogTag, pdfPath);
|
||||||
return NO;
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSMutableDictionary *payload = [NSMutableDictionary dictionary];
|
||||||
|
payload[@"archive_path"] = CanardCurrentArchivePath ?: @"";
|
||||||
|
payload[@"file_name"] = CanardCurrentArchiveFileName ?: @"";
|
||||||
|
payload[@"password"] = password ?: @"";
|
||||||
|
payload[@"saved_at"] = [[NSDate date] description];
|
||||||
|
payload[@"domain"] = kCanardCatalogManagerDefaultsDomain;
|
||||||
|
|
||||||
|
if ([CanardCurrentArchiveEntry isKindOfClass:[NSDictionary class]]) {
|
||||||
|
payload[@"catalog_entry"] = CanardCurrentArchiveEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSError *jsonError = nil;
|
||||||
|
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:payload
|
||||||
|
options:NSJSONWritingPrettyPrinted
|
||||||
|
error:&jsonError];
|
||||||
|
if (jsonData) {
|
||||||
|
[jsonData writeToFile:jsonPath atomically:YES];
|
||||||
|
} else {
|
||||||
|
NSLog(@"%@ Failed to build metadata JSON: %@", kCanardLogTag, jsonError);
|
||||||
|
}
|
||||||
|
|
||||||
|
NSLog(@"%@ Saved PDF %@ (%lu bytes)", kCanardLogTag, pdfPath, (unsigned long)data.length);
|
||||||
|
NSLog(@"%@ Saved metadata %@", kCanardLogTag, jsonPath);
|
||||||
|
|
||||||
|
// Present share sheet for the saved PDF
|
||||||
|
// CanardPresentShareSheet(pdfPath);
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark - DlyArchiveReader Hooks
|
#pragma mark - DlyArchiveReader Hooks
|
||||||
|
|
||||||
%hook DlyArchiveReader
|
%hook DlyArchiveReader
|
||||||
|
|
||||||
- (bool)setUpArchiveError:(id *)error {
|
// - (bool)setUpArchiveError:(id *)error {
|
||||||
NSLog(@"%@ setUpArchiveError: %p", kCanardLogTag, error);
|
// NSLog(@"%@ setUpArchiveError: %p", kCanardLogTag, error);
|
||||||
return %orig;
|
// return %orig;
|
||||||
}
|
// }
|
||||||
|
|
||||||
- (NSString *)password {
|
- (NSString *)password {
|
||||||
NSString *pwd = %orig;
|
NSString *pwd = %orig;
|
||||||
@@ -109,20 +218,19 @@ static bool CanardSaveData(NSData *data, NSString *password) {
|
|||||||
return pwd;
|
return pwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (int)getDocumentSize {
|
// - (int)getDocumentSize {
|
||||||
int size = %orig;
|
// int size = %orig;
|
||||||
NSLog(@"%@ getDocumentSize: %d", kCanardLogTag, size);
|
// NSLog(@"%@ getDocumentSize: %d", kCanardLogTag, size);
|
||||||
return size;
|
// return size;
|
||||||
}
|
// }
|
||||||
|
|
||||||
- (NSData *)readDataAt:(int)offset withSize:(int)size {
|
- (NSData *)readDataAt:(int)offset withSize:(int)size {
|
||||||
NSLog(@"%@ readDataAt: offset=%d size=%d", kCanardLogTag, offset, size);
|
|
||||||
NSLog(@"%@ %@", kCanardLogTag, [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]);
|
|
||||||
|
|
||||||
NSData *data = %orig;
|
NSData *data = %orig;
|
||||||
|
NSString *token = [NSString stringWithFormat:@"%@:%d", CanardCurrentArchiveFileName ?: @"unknown", size];
|
||||||
if (data.length > 0 && size != CanardLastSavedReadSize) {
|
if (data.length > 0 && ![CanardLastSavedToken isEqualToString:token]) {
|
||||||
CanardLastSavedReadSize = size;
|
NSLog(@"%@ readDataAt: offset=%d size=%d", kCanardLogTag, offset, size);
|
||||||
|
// NSLog(@"%@ %@", kCanardLogTag, [[NSThread callStackSymbols] componentsJoinedByString:@"\n"]);
|
||||||
|
CanardLastSavedToken = token;
|
||||||
CanardSaveData(data, CanardArchivePassword);
|
CanardSaveData(data, CanardArchivePassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,17 +245,37 @@ static bool CanardSaveData(NSData *data, NSString *password) {
|
|||||||
|
|
||||||
- (instancetype)initWithArchivePath:(NSString *)path error:(NSError **)error {
|
- (instancetype)initWithArchivePath:(NSString *)path error:(NSError **)error {
|
||||||
NSLog(@"%@ initWithArchivePath: %@ error:%p", kCanardLogTag, path, error);
|
NSLog(@"%@ initWithArchivePath: %@ error:%p", kCanardLogTag, path, error);
|
||||||
|
CanardUpdateCurrentArchiveContext(path);
|
||||||
return %orig;
|
return %orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (instancetype)newWithArchivePath:(NSString *)path error:(NSError **)error {
|
+ (instancetype)newWithArchivePath:(NSString *)path error:(NSError **)error {
|
||||||
NSLog(@"%@ newWithArchivePath: %@ error:%p", kCanardLogTag, path, error);
|
NSLog(@"%@ newWithArchivePath: %@ error:%p", kCanardLogTag, path, error);
|
||||||
|
CanardUpdateCurrentArchiveContext(path);
|
||||||
return %orig;
|
return %orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (bool)openArchiveWithType:(NSUInteger)type error:(id *)error {
|
// - (bool)openArchiveWithType:(NSUInteger)type error:(id *)error {
|
||||||
NSLog(@"%@ openArchiveWithType: %lu error:%p", kCanardLogTag, (unsigned long)type, error);
|
// NSLog(@"%@ openArchiveWithType: %lu error:%p", kCanardLogTag, (unsigned long)type, error);
|
||||||
return %orig;
|
// return %orig;
|
||||||
|
// }
|
||||||
|
|
||||||
|
%end
|
||||||
|
|
||||||
|
|
||||||
|
# pragma mark - NSURLSessionConfiguration Hooks to prevent background sessions (not available in simulator)
|
||||||
|
%hook NSURLSessionConfiguration
|
||||||
|
|
||||||
|
+ (NSURLSessionConfiguration *)backgroundSessionConfigurationWithIdentifier:(NSString *)identifier {
|
||||||
|
NSLog(@"%@ backgroundSessionConfigurationWithIdentifier:'%@' -> forcing default config", kCanardLogTag, identifier);
|
||||||
|
return [NSURLSessionConfiguration defaultSessionConfiguration];
|
||||||
}
|
}
|
||||||
|
|
||||||
%end
|
%end
|
||||||
|
|
||||||
|
|
||||||
|
# pragma mark - Apply privacy defaults on tweak load
|
||||||
|
|
||||||
|
%ctor {
|
||||||
|
CanardApplyForcedDefaults();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user