Support for MITM/key change interface.
This commit is contained in:
parent
d90d27995c
commit
f67e0d13f0
|
@ -83,7 +83,7 @@ EXTERNAL SOURCES:
|
|||
|
||||
CHECKOUT OPTIONS:
|
||||
JSQMessagesViewController:
|
||||
:commit: bc976a04d906ab3e5316148ee66de172a6e370b2
|
||||
:commit: 8703ce020c86054ca32fbfdede0b4bded4428994
|
||||
:git: https://github.com/dtsbourg/JSQMessagesViewController
|
||||
SocketRocket:
|
||||
:commit: d0585af165
|
||||
|
|
2
Pods
2
Pods
|
@ -1 +1 @@
|
|||
Subproject commit 6641c0c61b183015950fb020a53a43a993bbb28f
|
||||
Subproject commit 9601c2be9292f740e40d530ec35ea7182d0a8441
|
|
@ -396,6 +396,7 @@
|
|||
B6C6AE561A305ED1006BAF8F /* textsecure.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6C6AE541A305ED1006BAF8F /* textsecure.cer */; };
|
||||
B6C93C4E199567AD00EDF894 /* DebugLogger.m in Sources */ = {isa = PBXBuildFile; fileRef = B6C93C4D199567AD00EDF894 /* DebugLogger.m */; };
|
||||
B6CBF53F1A254BD1000D4184 /* ContactDetailCell.m in Sources */ = {isa = PBXBuildFile; fileRef = B6CBF53E1A254BD1000D4184 /* ContactDetailCell.m */; };
|
||||
B6E314C91A38FAAF00A41AFB /* TSFingerprintGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E314C81A38FAAF00A41AFB /* TSFingerprintGenerator.m */; };
|
||||
B90418E6183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; };
|
||||
B90418E7183E9DD40038554A /* DateUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = B90418E5183E9DD40038554A /* DateUtil.m */; };
|
||||
B96A3100187DA1B600648F3E /* HelveticaNeueLTStd-Bd.otf in Resources */ = {isa = PBXBuildFile; fileRef = B96A30FE187DA1B600648F3E /* HelveticaNeueLTStd-Bd.otf */; };
|
||||
|
@ -1041,6 +1042,8 @@
|
|||
B6C93C4D199567AD00EDF894 /* DebugLogger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DebugLogger.m; sourceTree = "<group>"; };
|
||||
B6CBF53D1A254BD1000D4184 /* ContactDetailCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ContactDetailCell.h; path = "Signal/src/view controllers/ContactDetailCell.h"; sourceTree = SOURCE_ROOT; };
|
||||
B6CBF53E1A254BD1000D4184 /* ContactDetailCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ContactDetailCell.m; path = "Signal/src/view controllers/ContactDetailCell.m"; sourceTree = SOURCE_ROOT; };
|
||||
B6E314C71A38FAAF00A41AFB /* TSFingerprintGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSFingerprintGenerator.h; sourceTree = "<group>"; };
|
||||
B6E314C81A38FAAF00A41AFB /* TSFingerprintGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSFingerprintGenerator.m; sourceTree = "<group>"; };
|
||||
B90418E4183E9DD40038554A /* DateUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateUtil.h; sourceTree = "<group>"; };
|
||||
B90418E5183E9DD40038554A /* DateUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DateUtil.m; sourceTree = "<group>"; };
|
||||
B96A30FE187DA1B600648F3E /* HelveticaNeueLTStd-Bd.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "HelveticaNeueLTStd-Bd.otf"; sourceTree = "<group>"; };
|
||||
|
@ -2331,6 +2334,8 @@
|
|||
children = (
|
||||
B6B0963C1A1D25ED008BFAA6 /* SecurityUtils.h */,
|
||||
B6B0963D1A1D25ED008BFAA6 /* SecurityUtils.m */,
|
||||
B6E314C71A38FAAF00A41AFB /* TSFingerprintGenerator.h */,
|
||||
B6E314C81A38FAAF00A41AFB /* TSFingerprintGenerator.m */,
|
||||
);
|
||||
path = Security;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3194,6 +3199,7 @@
|
|||
E16E5BEF18AAC40200B7C403 /* EC25KeyAgreementProtocol.m in Sources */,
|
||||
B6B096901A1D25ED008BFAA6 /* Cryptography.m in Sources */,
|
||||
76EB064018170B33006006FC /* AnonymousTerminator.m in Sources */,
|
||||
B6E314C91A38FAAF00A41AFB /* TSFingerprintGenerator.m in Sources */,
|
||||
B6B096721A1D25ED008BFAA6 /* TSMessage.m in Sources */,
|
||||
76EB058818170B33006006FC /* PropertyListPreferences.m in Sources */,
|
||||
76EB05B218170B33006006FC /* DH3KKeyAgreementProtocol.m in Sources */,
|
||||
|
|
|
@ -19,21 +19,23 @@ typedef NS_ENUM(int32_t, TSErrorMessageType){
|
|||
TSErrorMessageMissingKeyId,
|
||||
TSErrorMessageInvalidMessage,
|
||||
TSErrorMessageDuplicateMessage,
|
||||
TSErrorMessageInvalidVersion
|
||||
TSErrorMessageInvalidVersion,
|
||||
};
|
||||
|
||||
+ (instancetype)corruptedMessageWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
+ (instancetype)invalidVersionWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
+ (instancetype)missingKeyIdWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
+ (instancetype)invalidKeyExceptionWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
+ (instancetype)untrustedKeyWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
+ (instancetype)missingSessionWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
|
||||
+ (instancetype)userNotRegisteredErrorMessageInThread:(TSThread*)thread;
|
||||
/**
|
||||
* Methods on TSErrorMessageWrongTrustedIdentityKey error types
|
||||
*/
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread failedMessageType:(TSErrorMessageType)errorMessageType;
|
||||
+ (instancetype)untrustedKeyWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
|
||||
- (NSData*)retryBody;
|
||||
- (BOOL)supportsRetry;
|
||||
- (void)acceptNewIdentityKey;
|
||||
- (NSString*)newIdentityKey;
|
||||
|
||||
@property (nonatomic, readonly) TSErrorMessageType errorType;
|
||||
|
||||
|
|
|
@ -8,9 +8,28 @@
|
|||
|
||||
#import "TSErrorMessage.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
#import "TSStorageManager+IdentityKeyStore.h"
|
||||
#import <AxolotlKit/PreKeyWhisperMessage.h>
|
||||
#import <AxolotlKit/NSData+keyVersionByte.h>
|
||||
#import "TSMessagesManager.h"
|
||||
#import "TSFingerprintGenerator.h"
|
||||
|
||||
@interface TSErrorMessage()
|
||||
@property NSData *pushSignal;
|
||||
@end
|
||||
|
||||
@implementation TSErrorMessage
|
||||
|
||||
- (instancetype)initForUnknownIdentityKeyWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread incomingPushSignal:(NSData*)signal{
|
||||
self = [self initWithTimestamp:timestamp inThread:thread failedMessageType:TSErrorMessageWrongTrustedIdentityKey];
|
||||
|
||||
if (self) {
|
||||
_pushSignal = signal;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread failedMessageType:(TSErrorMessageType)errorMessageType{
|
||||
self = [super initWithTimestamp:timestamp inThread:thread messageBody:nil attachements:nil];
|
||||
|
||||
|
@ -21,6 +40,11 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithSignal:(IncomingPushMessageSignal*)signal transaction:(YapDatabaseReadWriteTransaction*)transaction failedMessageType:(TSErrorMessageType)errorMessageType{
|
||||
TSContactThread *contactThread = [TSContactThread threadWithContactId:signal.source transaction:transaction];
|
||||
return [self initWithTimestamp:signal.timestamp inThread:contactThread failedMessageType:errorMessageType];
|
||||
}
|
||||
|
||||
- (NSString*)description{
|
||||
switch (_errorType) {
|
||||
case TSErrorMessageNoSession:
|
||||
|
@ -36,45 +60,65 @@
|
|||
case TSErrorMessageInvalidKeyException:
|
||||
return @"The recipient's key is not valid.";
|
||||
case TSErrorMessageWrongTrustedIdentityKey:
|
||||
return @"Your contact's identity key changed. Tap to verify and accept new key";
|
||||
return @"Identity key changed. Tap to verify new key.";
|
||||
default:
|
||||
return @"An unknown error occured";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+ (instancetype)userNotRegisteredErrorMessageInThread:(TSThread*)thread{
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread];
|
||||
+ (instancetype)corruptedMessageWithSignal:(IncomingPushMessageSignal *)signal withTransaction:(YapDatabaseReadWriteTransaction *)transaction{
|
||||
return [[self alloc] initWithSignal:signal transaction:transaction failedMessageType:TSErrorMessageInvalidMessage];
|
||||
}
|
||||
|
||||
+ (instancetype)invalidVersionWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
TSContactThread *contactThread = [TSContactThread threadWithContactId:preKeyMessage.source transaction:transaction];
|
||||
TSErrorMessage *errorMessage = [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:contactThread failedMessageType:TSErrorMessageInvalidVersion];
|
||||
return errorMessage;
|
||||
+ (instancetype)invalidVersionWithSignal:(IncomingPushMessageSignal*)signal withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
return [[self alloc] initWithSignal:signal transaction:transaction failedMessageType:TSErrorMessageInvalidVersion];
|
||||
}
|
||||
|
||||
+ (instancetype)missingKeyIdWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
TSContactThread *contactThread = [TSContactThread threadWithContactId:preKeyMessage.source transaction:transaction];
|
||||
TSErrorMessage *errorMessage = [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:contactThread failedMessageType:TSErrorMessageMissingKeyId];
|
||||
return errorMessage;
|
||||
+ (instancetype)missingKeyIdWithSignal:(IncomingPushMessageSignal*)signal withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
return [[self alloc] initWithSignal:signal transaction:transaction failedMessageType:TSErrorMessageMissingKeyId];
|
||||
}
|
||||
|
||||
+ (instancetype)invalidKeyExceptionWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
TSContactThread *contactThread = [TSContactThread threadWithContactId:preKeyMessage.source transaction:transaction];
|
||||
TSErrorMessage *errorMessage = [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:contactThread failedMessageType:TSErrorMessageInvalidKeyException];
|
||||
return errorMessage;
|
||||
+ (instancetype)invalidKeyExceptionWithSignal:(IncomingPushMessageSignal*)signal withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
return [[self alloc] initWithSignal:signal transaction:transaction failedMessageType:TSErrorMessageInvalidKeyException];
|
||||
}
|
||||
|
||||
+ (instancetype)untrustedKeyWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
TSContactThread *contactThread = [TSContactThread threadWithContactId:preKeyMessage.source transaction:transaction];
|
||||
TSErrorMessage *errorMessage = [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:contactThread failedMessageType:TSErrorMessageWrongTrustedIdentityKey];
|
||||
TSErrorMessage *errorMessage = [[self alloc] initForUnknownIdentityKeyWithTimestamp:preKeyMessage.timestamp inThread:contactThread incomingPushSignal:preKeyMessage.data];
|
||||
return errorMessage;
|
||||
}
|
||||
|
||||
+ (instancetype)missingSessionWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
TSContactThread *contactThread = [TSContactThread threadWithContactId:preKeyMessage.source transaction:transaction];
|
||||
TSErrorMessage *errorMessage = [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:contactThread failedMessageType:TSErrorMessageNoSession];
|
||||
return errorMessage;
|
||||
+ (instancetype)missingSessionWithSignal:(IncomingPushMessageSignal*)signal withTransaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
return [[self alloc] initWithSignal:signal transaction:transaction failedMessageType:TSErrorMessageNoSession];
|
||||
}
|
||||
|
||||
- (void)acceptNewIdentityKey{
|
||||
if (_errorType != TSErrorMessageWrongTrustedIdentityKey || !_pushSignal) {
|
||||
return;
|
||||
}
|
||||
|
||||
TSStorageManager *storage = [TSStorageManager sharedManager];
|
||||
IncomingPushMessageSignal *signal = [IncomingPushMessageSignal parseFromData:_pushSignal];
|
||||
PreKeyWhisperMessage *message = [[PreKeyWhisperMessage alloc] initWithData:signal.message];
|
||||
NSData *newKey = [message.identityKey removeKeyType];
|
||||
|
||||
[storage saveRemoteIdentity:newKey recipientId:signal.source];
|
||||
|
||||
[[TSMessagesManager sharedManager] handleMessageSignal:signal];
|
||||
//TODO: Decrypt any other messages encrypted with that new identity key automatically.
|
||||
}
|
||||
|
||||
- (NSString *)newIdentityKey{
|
||||
if (_errorType != TSErrorMessageWrongTrustedIdentityKey || !_pushSignal) {
|
||||
return @"";
|
||||
}
|
||||
|
||||
IncomingPushMessageSignal *signal = [IncomingPushMessageSignal parseFromData:_pushSignal];
|
||||
PreKeyWhisperMessage *message = [[PreKeyWhisperMessage alloc] initWithData:signal.message];
|
||||
NSData *identityKey = [message.identityKey removeKeyType];
|
||||
|
||||
return [TSFingerprintGenerator getFingerprintForDisplay:identityKey];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -12,9 +12,12 @@
|
|||
|
||||
typedef NS_ENUM(NSInteger, TSInfoMessageType){
|
||||
TSInfoMessageTypeSessionDidEnd,
|
||||
TSInfoMessageUserNotRegistered,
|
||||
TSInfoMessageTypeUnsupportedMessage
|
||||
};
|
||||
|
||||
+ (instancetype)userNotRegisteredMessageInThread:(TSThread*)thread transaction:(YapDatabaseReadWriteTransaction*)transaction;
|
||||
|
||||
@property TSInfoMessageType messageType;
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSContactThread *)contact messageType:(TSInfoMessageType)infoMessage;
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
//
|
||||
|
||||
#import "TSInfoMessage.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
|
||||
@implementation TSInfoMessage
|
||||
|
||||
- (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSContactThread *)contact messageType:(TSInfoMessageType)infoMessage{
|
||||
self = [super initWithTimestamp:timestamp inThread:contact messageBody:@"Placeholder for info message." attachements:nil];
|
||||
self = [super initWithTimestamp:timestamp inThread:contact messageBody:nil attachements:nil];
|
||||
|
||||
if (self) {
|
||||
_messageType = infoMessage;
|
||||
|
@ -20,12 +21,19 @@
|
|||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)userNotRegisteredMessageInThread:(TSContactThread*)thread transaction:(YapDatabaseReadWriteTransaction*)transaction{
|
||||
return [[self alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] inThread:thread messageType:TSInfoMessageUserNotRegistered];
|
||||
|
||||
}
|
||||
|
||||
- (NSString *)description{
|
||||
switch (_messageType) {
|
||||
case TSInfoMessageTypeSessionDidEnd:
|
||||
return @"Secure session ended.";
|
||||
case TSInfoMessageTypeUnsupportedMessage:
|
||||
return @"Media messages are currently not supported.";
|
||||
case TSInfoMessageUserNotRegistered:
|
||||
return @"The user is not registered.";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#import "TSRecipientPrekeyRequest.h"
|
||||
|
||||
#import "TSErrorMessage.h"
|
||||
#import "TSInfoMessage.h"
|
||||
|
||||
#import "TSContactThread.h"
|
||||
#import "TSGroupThread.h"
|
||||
|
@ -99,7 +100,7 @@ dispatch_queue_t sendingQueue() {
|
|||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[recipient removeWithTransaction:transaction];
|
||||
[message setMessageState:TSOutgoingMessageStateUnsent];
|
||||
[[TSErrorMessage userNotRegisteredErrorMessageInThread:thread] saveWithTransaction:transaction];
|
||||
[[TSInfoMessage userNotRegisteredMessageInThread:thread transaction:transaction] saveWithTransaction:transaction];
|
||||
}];
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#import "TSMessagesManager.h"
|
||||
|
||||
#import <AxolotlKit/AxolotlExceptions.h>
|
||||
#import <AxolotlKit/SessionCipher.h>
|
||||
|
||||
#import "Cryptography.h"
|
||||
|
@ -224,10 +225,12 @@
|
|||
TSThread *thread;
|
||||
if (groupId) {
|
||||
TSGroupThread *gThread = [TSGroupThread threadWithGroupId:groupId];
|
||||
[gThread saveWithTransaction:transaction];
|
||||
incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timeStamp inThread:gThread authorId:message.source messageBody:body attachements:nil];
|
||||
thread = gThread;
|
||||
} else{
|
||||
TSContactThread *cThread = [TSContactThread threadWithContactId:message.source transaction:transaction];
|
||||
[cThread saveWithTransaction:transaction];
|
||||
incomingMessage = [[TSIncomingMessage alloc] initWithTimestamp:timeStamp inThread:cThread messageBody:body attachements:nil];
|
||||
thread = cThread;
|
||||
}
|
||||
|
@ -238,9 +241,27 @@
|
|||
}
|
||||
|
||||
- (void)processException:(NSException*)exception pushSignal:(IncomingPushMessageSignal*)signal{
|
||||
DDLogError(@"Got exception: %@", exception.description);
|
||||
DDLogError(@"Got exception: %@ of type: %@", exception.description, exception.name);
|
||||
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
TSErrorMessage *errorMessage = [[TSErrorMessage alloc] initWithTimestamp:signal.timestamp inThread:[TSContactThread threadWithContactId:signal.source transaction:transaction] failedMessageType:TSErrorMessageNoSession];
|
||||
TSErrorMessage *errorMessage;
|
||||
|
||||
if ([exception.name isEqualToString:NoSessionException]) {
|
||||
errorMessage = [TSErrorMessage missingSessionWithSignal:signal withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyException]){
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithSignal:signal withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:InvalidKeyIdException]){
|
||||
errorMessage = [TSErrorMessage invalidKeyExceptionWithSignal:signal withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:DuplicateMessageException]){
|
||||
// Duplicate messages are dismissed
|
||||
return ;
|
||||
} else if ([exception.name isEqualToString:InvalidVersionException]){
|
||||
errorMessage = [TSErrorMessage invalidVersionWithSignal:signal withTransaction:transaction];
|
||||
} else if ([exception.name isEqualToString:UntrustedIdentityKeyException]){
|
||||
errorMessage = [TSErrorMessage untrustedKeyWithSignal:signal withTransaction:transaction];
|
||||
} else {
|
||||
errorMessage = [TSErrorMessage corruptedMessageWithSignal:signal withTransaction:transaction];
|
||||
}
|
||||
|
||||
[errorMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// TSFingerprintGenerator.h
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 10/12/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface TSFingerprintGenerator : NSObject
|
||||
|
||||
+ (NSString*)getFingerprintForDisplay:(NSData*)identityKey;
|
||||
|
||||
@end
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// TSFingerprintGenerator.m
|
||||
// Signal
|
||||
//
|
||||
// Created by Frederic Jacobs on 10/12/14.
|
||||
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSData+hexString.h"
|
||||
#import <AxolotlKit/NSData+keyVersionByte.h>
|
||||
|
||||
#import "TSFingerprintGenerator.h"
|
||||
|
||||
@implementation TSFingerprintGenerator
|
||||
|
||||
+ (NSString*)getFingerprintForDisplay:(NSData*)identityKey {
|
||||
// idea here is to insert a space every two characters. there is probably a cleverer/more native way to do this.
|
||||
|
||||
identityKey = [identityKey prependKeyType];
|
||||
NSString *fingerprint = [identityKey hexadecimalString];
|
||||
__block NSString* formattedFingerprint = @"";
|
||||
|
||||
|
||||
[fingerprint enumerateSubstringsInRange:NSMakeRange(0, [fingerprint length])
|
||||
options:NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock:
|
||||
^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if (substringRange.location % 2 != 0 && substringRange.location != [fingerprint length]-1) {
|
||||
substring = [substring stringByAppendingString:@" "];
|
||||
}
|
||||
formattedFingerprint = [formattedFingerprint stringByAppendingString:substring];
|
||||
}];
|
||||
return formattedFingerprint;
|
||||
}
|
||||
|
||||
|
||||
@end
|
|
@ -16,6 +16,8 @@
|
|||
#import "TSStorageManager.h"
|
||||
#import "TSStorageManager+IdentityKeyStore.h"
|
||||
|
||||
#import "TSFingerprintGenerator.h"
|
||||
|
||||
@interface FingerprintViewController ()
|
||||
@property TSContactThread *thread;
|
||||
@end
|
||||
|
@ -26,25 +28,6 @@
|
|||
self.thread = (TSContactThread*)thread;
|
||||
}
|
||||
|
||||
- (NSString*)getFingerprintForDisplay:(NSData*)identityKey {
|
||||
// idea here is to insert a space every two characters. there is probably a cleverer/more native way to do this.
|
||||
|
||||
identityKey = [identityKey prependKeyType];
|
||||
NSString *fingerprint = [identityKey hexadecimalString];
|
||||
__block NSString* formattedFingerprint = @"";
|
||||
|
||||
|
||||
[fingerprint enumerateSubstringsInRange:NSMakeRange(0, [fingerprint length])
|
||||
options:NSStringEnumerationByComposedCharacterSequences
|
||||
usingBlock:
|
||||
^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) {
|
||||
if (substringRange.location % 2 != 0 && substringRange.location != [fingerprint length]-1) {
|
||||
substring = [substring stringByAppendingString:@" "];
|
||||
}
|
||||
formattedFingerprint = [formattedFingerprint stringByAppendingString:substring];
|
||||
}];
|
||||
return formattedFingerprint;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
@ -59,10 +42,10 @@
|
|||
{
|
||||
self.contactFingerprintTitleLabel.text = self.thread.name;
|
||||
NSData *identityKey = [[TSStorageManager sharedManager] identityKeyForRecipientId:self.thread.contactIdentifier];
|
||||
self.contactFingerprintLabel.text = [self getFingerprintForDisplay:identityKey];
|
||||
self.contactFingerprintLabel.text = [TSFingerprintGenerator getFingerprintForDisplay:identityKey];
|
||||
|
||||
NSData *myPublicKey = [[TSStorageManager sharedManager] identityKeyPair].publicKey;
|
||||
self.userFingerprintLabel.text = [self getFingerprintForDisplay:myPublicKey];
|
||||
self.userFingerprintLabel.text = [TSFingerprintGenerator getFingerprintForDisplay:myPublicKey];
|
||||
|
||||
[UIView animateWithDuration:0.6 delay:0. options:UIViewAnimationOptionCurveEaseInOut animations:^{
|
||||
[self.view setAlpha:1];
|
||||
|
|
|
@ -31,9 +31,12 @@
|
|||
#import "TSStorageManager.h"
|
||||
#import "TSDatabaseView.h"
|
||||
#import <YapDatabase/YapDatabaseView.h>
|
||||
#import "TSInteraction.h"
|
||||
|
||||
|
||||
#import "TSMessageAdapter.h"
|
||||
#import "TSErrorMessage.h"
|
||||
#import "TSIncomingMessage.h"
|
||||
#import "TSInteraction.h"
|
||||
|
||||
#import "TSMessagesManager+sendMessages.h"
|
||||
#import "NSDate+millisecondTimeStamp.h"
|
||||
|
@ -451,11 +454,17 @@ typedef enum : NSUInteger {
|
|||
|
||||
- (void)collectionView:(JSQMessagesCollectionView *)collectionView didTapMessageBubbleAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
TSMessageAdapter * messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
|
||||
TSMessageAdapter *messageItem = [collectionView.dataSource collectionView:collectionView messageDataForItemAtIndexPath:indexPath];
|
||||
TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
|
||||
|
||||
BOOL isMessage = (messageItem.messageType == TSIncomingMessageAdapter) || (messageItem.messageType == TSOutgoingMessageAdapter);
|
||||
switch (messageItem.messageType) {
|
||||
case TSOutgoingMessageAdapter:
|
||||
if (messageItem.messageState == TSOutgoingMessageStateUnsent) {
|
||||
[self handleUnsentMessageTap:(TSOutgoingMessage*)interaction];
|
||||
}
|
||||
case TSIncomingMessageAdapter:{
|
||||
|
||||
BOOL isMediaMessage = isMessage ? [messageItem isMediaMessage] : NO;
|
||||
BOOL isMediaMessage = [messageItem isMediaMessage];
|
||||
|
||||
if (isMediaMessage) {
|
||||
id<JSQMessageMediaData> messageMedia = [messageItem media];
|
||||
|
@ -470,38 +479,63 @@ typedef enum : NSUInteger {
|
|||
}
|
||||
}
|
||||
|
||||
BOOL isUnsent = messageItem.messageState == TSOutgoingMessageStateAttemptingOut && [messageItem.senderId isEqualToString:self.senderId];
|
||||
break;}
|
||||
case TSErrorMessageAdapter:
|
||||
[self handleErrorMessageTap:(TSErrorMessage*)interaction];
|
||||
break;
|
||||
case TSInfoMessageAdapter:
|
||||
break;
|
||||
|
||||
if (isMessage && isUnsent)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Bubble User Actions
|
||||
|
||||
- (void)handleUnsentMessageTap:(TSOutgoingMessage*)message{
|
||||
[DJWActionSheet showInView:self.tabBarController.view withTitle:nil cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:@[@"Send again"] tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
|
||||
if (tappedButtonIndex == actionSheet.cancelButtonIndex) {
|
||||
NSLog(@"User Cancelled");
|
||||
} else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) {
|
||||
|
||||
[self.uiDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
||||
TSOutgoingMessage * message = (TSOutgoingMessage*)messageItem;
|
||||
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
||||
[message removeWithTransaction:transaction];
|
||||
[self finishSendingMessage];
|
||||
}];
|
||||
|
||||
}else {
|
||||
switch (tappedButtonIndex) {
|
||||
case 0:
|
||||
{
|
||||
TSOutgoingMessage * message = (TSOutgoingMessage*)messageItem;
|
||||
[[TSMessagesManager sharedManager] sendMessage:message inThread:self.thread];
|
||||
[self finishSendingMessage];
|
||||
break;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)handleErrorMessageTap:(TSErrorMessage*)message{
|
||||
if (message.errorType == TSErrorMessageWrongTrustedIdentityKey) {
|
||||
NSString *newKeyFingerprint = [message newIdentityKey];
|
||||
NSString *messageString = [NSString stringWithFormat:@"Do you want to accept %@'s new identity key: %@", _thread.name, newKeyFingerprint];
|
||||
NSArray *actions = @[@"Accept new identity key", @"Copy new identity key to pasteboard"];
|
||||
|
||||
[DJWActionSheet showInView:self.tabBarController.view withTitle:messageString cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete" otherButtonTitles:actions tapBlock:^(DJWActionSheet *actionSheet, NSInteger tappedButtonIndex) {
|
||||
if (tappedButtonIndex == actionSheet.cancelButtonIndex) {
|
||||
NSLog(@"User Cancelled");
|
||||
} else if (tappedButtonIndex == actionSheet.destructiveButtonIndex) {
|
||||
[self.editingDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction){
|
||||
[message removeWithTransaction:transaction];
|
||||
}];
|
||||
} else {
|
||||
switch (tappedButtonIndex) {
|
||||
case 0:
|
||||
[message acceptNewIdentityKey];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
[[UIPasteboard generalPasteboard] setString:newKeyFingerprint];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - Navigation
|
||||
|
@ -514,7 +548,6 @@ typedef enum : NSUInteger {
|
|||
|
||||
} else if ([segue.identifier isEqualToString:@"fingerprintSegue"]){
|
||||
FingerprintViewController *vc = [segue destinationViewController];
|
||||
TSContactThread *thread = (TSContactThread*) self.thread;
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
[vc configWithThread:self.thread];
|
||||
}];
|
||||
|
@ -697,8 +730,7 @@ typedef enum : NSUInteger {
|
|||
return numberOfMessages;
|
||||
}
|
||||
|
||||
- (TSMessageAdapter*)messageAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
- (TSInteraction*)interactionAtIndexPath:(NSIndexPath*)indexPath {
|
||||
__block TSInteraction *message = nil;
|
||||
[self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
|
||||
YapDatabaseViewTransaction *viewTransaction = [transaction ext:TSMessageDatabaseViewExtensionName];
|
||||
|
@ -714,7 +746,13 @@ typedef enum : NSUInteger {
|
|||
message = [viewTransaction objectAtRow:row inSection:section withMappings:self.messageMappings];
|
||||
NSParameterAssert(message != nil);
|
||||
}];
|
||||
return [TSMessageAdapter messageViewDataWithInteraction:message inThread:self.thread];
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
- (TSMessageAdapter*)messageAtIndexPath:(NSIndexPath *)indexPath {
|
||||
TSInteraction *interaction = [self interactionAtIndexPath:indexPath];
|
||||
return [TSMessageAdapter messageViewDataWithInteraction:interaction inThread:self.thread];
|
||||
}
|
||||
|
||||
#pragma mark Accessory View
|
||||
|
|
Loading…
Reference in New Issue