// // Copyright (c) 2018 Open Whisper Systems. All rights reserved. // #import "DebugUIMisc.h" #import "OWSBackup.h" #import "OWSCountryMetadata.h" #import "OWSTableViewController.h" #import "RegistrationViewController.h" #import "Signal-Swift.h" #import "ThreadUtil.h" #import #import #import #import #import #import #import #import #import #import #import NS_ASSUME_NONNULL_BEGIN @interface TSAccountManager (DebugUI) - (void)resetForRegistration; @end #pragma mark - @interface OWSStorage (DebugUI) - (NSData *)databasePassword; @end #pragma mark - @implementation DebugUIMisc #pragma mark - Factory Methods - (NSString *)name { return @"Misc."; } - (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)thread { NSMutableArray *items = [NSMutableArray new]; [items addObject:[OWSTableItem itemWithTitle:@"Enable Manual Censorship Circumvention" actionBlock:^{ [DebugUIMisc setManualCensorshipCircumventionEnabled:YES]; }]]; [items addObject:[OWSTableItem itemWithTitle:@"Disable Manual Censorship Circumvention" actionBlock:^{ [DebugUIMisc setManualCensorshipCircumventionEnabled:NO]; }]]; [items addObject:[OWSTableItem itemWithTitle:@"Clear experience upgrades (works once per launch)" actionBlock:^{ [ExperienceUpgrade removeAllObjectsInCollection]; }]]; [items addObject:[OWSTableItem itemWithTitle:@"Clear hasDismissedOffers" actionBlock:^{ [DebugUIMisc clearHasDismissedOffers]; }]]; [items addObject:[OWSTableItem itemWithTitle:@"Re-register" actionBlock:^{ [OWSAlerts showConfirmationAlertWithTitle:@"Re-register?" message:@"If you proceed, you will not lose any of your " @"current messages, but your account will be " @"deactivated until you complete re-registration." proceedTitle:@"Proceed" proceedAction:^(UIAlertAction *_Nonnull action) { [self reregister]; }]; }]]; if (thread) { [items addObject:[OWSTableItem itemWithTitle:@"Send Encrypted Database" actionBlock:^{ [DebugUIMisc sendEncryptedDatabase:thread]; }]]; [items addObject:[OWSTableItem itemWithTitle:@"Send Unencrypted Database" actionBlock:^{ [DebugUIMisc sendUnencryptedDatabase:thread]; }]]; } [items addObject:[OWSTableItem itemWithTitle:@"Export Database" actionBlock:^{ [OWSBackup exportDatabase]; }]]; return [OWSTableSection sectionWithTitle:self.name items:items]; } - (void)reregister { DDLogInfo(@"%@ re-registering.", self.logTag); [[TSAccountManager sharedInstance] resetForRegistration]; [[Environment current].preferences unsetRecordedAPNSTokens]; RegistrationViewController *viewController = [RegistrationViewController new]; OWSNavigationController *navigationController = [[OWSNavigationController alloc] initWithRootViewController:viewController]; navigationController.navigationBarHidden = YES; [UIApplication sharedApplication].delegate.window.rootViewController = navigationController; } + (void)setManualCensorshipCircumventionEnabled:(BOOL)isEnabled { OWSCountryMetadata *countryMetadata = nil; NSString *countryCode = OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode; if (countryCode) { countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; } if (!countryMetadata) { countryCode = [PhoneNumber defaultCountryCode]; if (countryCode) { countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; } } if (!countryMetadata) { countryCode = @"US"; countryMetadata = [OWSCountryMetadata countryMetadataForCountryCode:countryCode]; } OWSAssert(countryMetadata); OWSSignalService.sharedInstance.manualCensorshipCircumventionCountryCode = countryCode; OWSSignalService.sharedInstance.manualCensorshipCircumventionDomain = countryMetadata.googleDomain; OWSSignalService.sharedInstance.isCensorshipCircumventionManuallyActivated = isEnabled; } + (void)clearHasDismissedOffers { [TSStorageManager.dbReadWriteConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { NSMutableArray *contactThreads = [NSMutableArray new]; [transaction enumerateKeysAndObjectsInCollection:[TSThread collection] usingBlock:^(NSString *_Nonnull key, id _Nonnull object, BOOL *_Nonnull stop) { TSThread *thread = object; if (thread.isGroupThread) { return; } TSContactThread *contactThread = object; [contactThreads addObject:contactThread]; }]; for (TSContactThread *contactThread in contactThreads) { if (contactThread.hasDismissedOffers) { contactThread.hasDismissedOffers = NO; [contactThread saveWithTransaction:transaction]; } } }]; } + (void)sendEncryptedDatabase:(TSThread *)thread { NSString *temporaryDirectory = NSTemporaryDirectory(); NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingString:@".sqlite"]; NSString *filePath = [temporaryDirectory stringByAppendingPathComponent:fileName]; __block BOOL success; [TSStorageManager.sharedManager.newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { NSError *error; success = [[NSFileManager defaultManager] copyItemAtPath:TSStorageManager.databaseFilePath toPath:filePath error:&error]; if (!success || error) { OWSFail(@"%@ Could not copy database file: %@.", self.logTag, error); success = NO; } }]; if (!success) { return; } OWSMessageSender *messageSender = [Environment current].messageSender; NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:fileName.pathExtension]; DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath]; [dataSource setSourceFilename:fileName]; SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; NSData *databasePassword = [TSStorageManager.sharedManager databasePassword]; attachment.captionText = [databasePassword hexadecimalString]; if (!attachment || [attachment hasError]) { OWSFail(@"%@ attachment[%@]: %@", self.logTag, [attachment sourceFilename], [attachment errorName]); return; } [ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender completion:nil]; } + (void)sendUnencryptedDatabase:(TSThread *)thread { NSString *temporaryDirectory = NSTemporaryDirectory(); NSString *fileName = [[NSUUID UUID].UUIDString stringByAppendingString:@".sqlite"]; NSString *filePath = [temporaryDirectory stringByAppendingPathComponent:fileName]; NSError *error = [TSStorageManager.sharedManager.newDatabaseConnection backupToPath:filePath]; if (error) { OWSFail(@"%@ Could not copy database file: %@.", self.logTag, error); return; } OWSMessageSender *messageSender = [Environment current].messageSender; NSString *utiType = [MIMETypeUtil utiTypeForFileExtension:fileName.pathExtension]; DataSource *_Nullable dataSource = [DataSourcePath dataSourceWithFilePath:filePath]; [dataSource setSourceFilename:fileName]; SignalAttachment *attachment = [SignalAttachment attachmentWithDataSource:dataSource dataUTI:utiType]; if (!attachment || [attachment hasError]) { OWSFail(@"%@ attachment[%@]: %@", self.logTag, [attachment sourceFilename], [attachment errorName]); return; } [ThreadUtil sendMessageWithAttachment:attachment inThread:thread messageSender:messageSender completion:nil]; } @end NS_ASSUME_NONNULL_END