Signal-iOS/Signal/src/ViewControllers/DebugUI/DebugUISessionState.m
2021-07-21 23:01:12 -07:00

186 lines
9.2 KiB
Objective-C

//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
//
#import "DebugUISessionState.h"
#import "Signal-Swift.h"
#import <SignalMessaging/OWSTableViewController.h>
#import <SignalServiceKit/OWSIdentityManager.h>
#import <SignalServiceKit/SignalServiceKit-Swift.h>
#import <SignalServiceKit/TSContactThread.h>
#ifdef DEBUG
NS_ASSUME_NONNULL_BEGIN
@implementation DebugUISessionState
- (NSString *)name
{
return @"Session State";
}
#pragma mark -
- (nullable OWSTableSection *)sectionForThread:(nullable TSThread *)threadParameter
{
NSMutableArray<OWSTableItem *> *items = [NSMutableArray new];
if ([threadParameter isKindOfClass:[TSContactThread class]]) {
TSContactThread *thread = (TSContactThread *)threadParameter;
[items addObjectsFromArray:@[
[OWSTableItem itemWithTitle:@"Log All Recipient Identities"
actionBlock:^{
[OWSRecipientIdentity printAllIdentities];
}],
[OWSTableItem itemWithTitle:@"Log All Sessions"
actionBlock:^{
[self.databaseStorage readWithBlock:^(SDSAnyReadTransaction *transaction) {
[self.sessionStore printAllSessionsWithTransaction:transaction];
}];
}],
[OWSTableItem itemWithTitle:@"Toggle Key Change"
actionBlock:^{
OWSLogError(@"Flipping identity Key. Flip again to return.");
OWSIdentityManager *identityManager = [OWSIdentityManager shared];
SignalServiceAddress *address = thread.contactAddress;
NSData *currentKey = [identityManager identityKeyForAddress:address];
NSMutableData *flippedKey = [NSMutableData new];
const char *currentKeyBytes = currentKey.bytes;
for (NSUInteger i = 0; i < currentKey.length; i++) {
const char xorByte = currentKeyBytes[i] ^ 0xff;
[flippedKey appendBytes:&xorByte length:1];
}
OWSAssertDebug(flippedKey.length == currentKey.length);
[identityManager saveRemoteIdentity:flippedKey address:address];
}],
[OWSTableItem itemWithTitle:@"Delete all sessions"
actionBlock:^{
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
[self.sessionStore deleteAllSessionsForAddress:thread.contactAddress
transaction:transaction];
});
}],
[OWSTableItem itemWithTitle:@"Archive all sessions"
actionBlock:^{
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
[self.sessionStore archiveAllSessionsForAddress:thread.contactAddress
transaction:transaction];
});
}],
[OWSTableItem itemWithTitle:@"Send session reset"
actionBlock:^{
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
[self.sessionResetJobQueue addContactThread:thread transaction:transaction];
});
}],
]];
}
if ([threadParameter isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *groupThread = (TSGroupThread *)threadParameter;
[items addObject:[OWSTableItem itemWithTitle:@"Rotate sender key"
actionBlock:^{
DatabaseStorageWrite(
self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
[self.senderKeyStore resetSenderKeySessionFor:groupThread
transaction:transaction];
});
}]];
}
if (threadParameter) {
[items addObject:[OWSTableItem itemWithTitle:@"Update verification state"
actionBlock:^{ [self updateIdentityVerificationForThread:threadParameter]; }]];
}
[items addObjectsFromArray:@[
[OWSTableItem itemWithTitle:@"Clear Session and Identity Store"
actionBlock:^{ [self clearSessionAndIdentityStore]; }],
]];
[items addObject:[OWSTableItem itemWithTitle:@"Clear sender key store"
actionBlock:^{
DatabaseStorageWrite(
self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
[self.senderKeyStore resetSenderKeyStoreWithTransaction:transaction];
});
}]];
return [OWSTableSection sectionWithTitle:self.name items:items];
}
- (void)clearSessionAndIdentityStore
{
DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) {
[self.sessionStore resetSessionStore:transaction];
[[OWSIdentityManager shared] clearIdentityState:transaction];
});
}
- (void)updateIdentityVerificationForThread:(TSThread *)thread
{
if (thread.recipientAddresses.count == 0) {
OWSFailDebug(@"No recipients for thread %@", thread);
return;
}
if (thread.recipientAddresses.count > 1) {
ActionSheetController *recipientSelection = [[ActionSheetController alloc] initWithTitle:@"Select a recipient"
message:nil];
[recipientSelection addAction:OWSActionSheets.cancelAction];
__weak typeof(self) wSelf = self;
for (SignalServiceAddress *address in thread.recipientAddresses) {
NSString *name = [self.contactsManager displayNameForAddress:address];
[recipientSelection
addAction:[[ActionSheetAction alloc] initWithTitle:name
style:ActionSheetActionStyleDefault
handler:^(ActionSheetAction *action) {
[wSelf updateIdentityVerificationForAddress:address];
}]];
}
[OWSActionSheets showActionSheet:recipientSelection];
} else {
[self updateIdentityVerificationForAddress:thread.recipientAddresses.firstObject];
}
}
- (void)updateIdentityVerificationForAddress:(SignalServiceAddress *)address
{
OWSRecipientIdentity *identity = [OWSIdentityManager.shared recipientIdentityForAddress:address];
NSString *name = [self.contactsManager displayNameForAddress:address];
NSString *message = [NSString stringWithFormat:@"%@ is currently marked as %@",
name,
OWSVerificationStateToString(identity.verificationState)];
ActionSheetController *stateSelection = [[ActionSheetController alloc] initWithTitle:@"Select a verification state"
message:message];
[stateSelection addAction:OWSActionSheets.cancelAction];
for (NSNumber *stateNum in
@[ @(OWSVerificationStateVerified), @(OWSVerificationStateDefault), @(OWSVerificationStateNoLongerVerified) ]) {
OWSVerificationState state = [stateNum unsignedIntegerValue];
[stateSelection addAction:[[ActionSheetAction alloc] initWithTitle:OWSVerificationStateToString(state)
style:ActionSheetActionStyleDefault
handler:^(ActionSheetAction *action) {
[OWSIdentityManager.shared
setVerificationState:state
identityKey:identity.identityKey
address:address
isUserInitiatedChange:NO];
}]];
}
[OWSActionSheets showActionSheet:stateSelection];
}
@end
NS_ASSUME_NONNULL_END
#endif