diff --git a/src/Messages/Interactions/OWSVerificationStateChangeMessage.h b/src/Messages/Interactions/OWSVerificationStateChangeMessage.h index 2951297a4..2f1a3f75a 100644 --- a/src/Messages/Interactions/OWSVerificationStateChangeMessage.h +++ b/src/Messages/Interactions/OWSVerificationStateChangeMessage.h @@ -11,8 +11,13 @@ NS_ASSUME_NONNULL_BEGIN @interface OWSVerificationStateChangeMessage : TSInfoMessage +@property (nonatomic, readonly) NSString *recipientId; +@property (nonatomic, readonly) OWSVerificationState verificationState; +@property (nonatomic, readonly) BOOL isLocalChange; + - (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread + recipientId:(NSString *)recipientId verificationState:(OWSVerificationState)verificationState isLocalChange:(BOOL)isLocalChange; diff --git a/src/Messages/Interactions/OWSVerificationStateChangeMessage.m b/src/Messages/Interactions/OWSVerificationStateChangeMessage.m index f8bdcb48d..ff46c791d 100644 --- a/src/Messages/Interactions/OWSVerificationStateChangeMessage.m +++ b/src/Messages/Interactions/OWSVerificationStateChangeMessage.m @@ -7,46 +7,29 @@ NS_ASSUME_NONNULL_BEGIN -@interface OWSVerificationStateChangeMessage () - -@property (nonatomic, readonly) OWSVerificationState verificationState; -@property (nonatomic, readonly) BOOL isLocalChange; - -@end - -#pragma mark - - @implementation OWSVerificationStateChangeMessage - (instancetype)initWithTimestamp:(uint64_t)timestamp thread:(TSThread *)thread + recipientId:(NSString *)recipientId verificationState:(OWSVerificationState)verificationState isLocalChange:(BOOL)isLocalChange { - self = [super initWithTimestamp:timestamp inThread:thread messageType:TSInfoMessageVerificationStateChange]; + OWSAssert(recipientId.length > 0) + + self + = [super initWithTimestamp:timestamp inThread:thread messageType:TSInfoMessageVerificationStateChange]; if (!self) { return self; } + _recipientId = recipientId; _verificationState = verificationState; _isLocalChange = isLocalChange; return self; } -- (NSString *)description -{ - switch (self.verificationState) { - case OWSVerificationStateDefault: - case OWSVerificationStateNoLongerVerified: - return NSLocalizedString(@"VERIFICATION_STATE_CHANGE_NOT_VERIFIED", - @"Info Message indicating that the verification state is not verified."); - case OWSVerificationStateVerified: - return NSLocalizedString(@"VERIFICATION_STATE_CHANGE_VERIFIED", - @"Info Message indicating that the verification state is verified."); - } -} - @end NS_ASSUME_NONNULL_END diff --git a/src/Messages/OWSIdentityManager.h b/src/Messages/OWSIdentityManager.h index 17f31ddd7..d5d8afc98 100644 --- a/src/Messages/OWSIdentityManager.h +++ b/src/Messages/OWSIdentityManager.h @@ -37,6 +37,8 @@ extern const NSUInteger kIdentityKeyLength; - (OWSVerificationState)verificationStateForRecipientId:(NSString *)recipientId; +- (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId; + /** * @param recipientId unique stable identifier for the recipient, e.g. e164 phone number * @returns nil if the recipient does not exist, or is trusted for sending diff --git a/src/Messages/OWSIdentityManager.m b/src/Messages/OWSIdentityManager.m index d94057d72..6dd8943fe 100644 --- a/src/Messages/OWSIdentityManager.m +++ b/src/Messages/OWSIdentityManager.m @@ -3,9 +3,11 @@ // #import "OWSIdentityManager.h" +#import "NSDate+millisecondTimeStamp.h" #import "NotificationsProtocol.h" #import "OWSMessageSender.h" #import "OWSRecipientIdentity.h" +#import "OWSVerificationStateChangeMessage.h" #import "OWSVerificationStateSyncMessage.h" #import "TSAccountManager.h" #import "TSContactThread.h" @@ -190,6 +192,14 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa // Cancel any pending verification state sync messages for this recipient. [self clearSyncMessageForRecipientId:recipientId]; + // TODO: This may be redundant with the "safety number changes" + // messages. + if (existingIdentity.verificationState != verificationState) { + [self saveChangeMessagesForRecipientId:recipientId + verificationState:verificationState + isLocalChange:YES]; + } + [self fireIdentityStateChangeNotification]; return YES; @@ -241,6 +251,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa // Cancel any pending verification state sync messages for this recipient. [self clearSyncMessageForRecipientId:recipientId]; } + + [self saveChangeMessagesForRecipientId:recipientId verificationState:verificationState isLocalChange:YES]; } [self fireIdentityStateChangeNotification]; @@ -263,6 +275,16 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa } } +- (nullable OWSRecipientIdentity *)recipientIdentityForRecipientId:(NSString *)recipientId +{ + OWSAssert(recipientId.length > 0); + + @synchronized(self) + { + return [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId]; + } +} + - (nullable OWSRecipientIdentity *)untrustedIdentityForSendingToRecipientId:(NSString *)recipientId { OWSAssert(recipientId.length > 0); @@ -385,18 +407,25 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa { OWSAssert(recipientId != nil); + NSMutableArray *messages = [NSMutableArray new]; + TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; OWSAssert(contactThread != nil); TSErrorMessage *errorMessage = [TSErrorMessage nonblockingIdentityChangeInThread:contactThread recipientId:recipientId]; - [errorMessage save]; - + [messages addObject:errorMessage]; [[TextSecureKitEnv sharedEnv].notificationsManager notifyUserForErrorMessage:errorMessage inThread:contactThread]; for (TSGroupThread *groupThread in [TSGroupThread groupThreadsWithRecipientId:recipientId]) { - [[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId] save]; + [messages addObject:[TSErrorMessage nonblockingIdentityChangeInThread:groupThread recipientId:recipientId]]; } + + [self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + for (TSMessage *message in messages) { + [message saveWithTransaction:transaction]; + } + }]; } - (void)enqueueSyncMessageForVerificationState:(OWSVerificationState)verificationState @@ -625,6 +654,9 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa OWSVerificationStateToString(verificationState)); [recipientIdentity updateWithVerificationState:verificationState]; + + // No need to call [saveChangeMessagesForRecipientId:..] since this is + // a new recipient. } else { // There's an existing recipient identity for this recipient. // We should update it. @@ -668,10 +700,44 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa } [recipientIdentity updateWithVerificationState:verificationState]; + + [self saveChangeMessagesForRecipientId:recipientId verificationState:verificationState isLocalChange:NO]; } } } +- (void)saveChangeMessagesForRecipientId:(NSString *)recipientId + verificationState:(OWSVerificationState)verificationState + isLocalChange:(BOOL)isLocalChange +{ + OWSAssert(recipientId.length > 0); + + NSMutableArray *messages = [NSMutableArray new]; + + TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; + OWSAssert(contactThread); + [messages addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] + thread:contactThread + recipientId:recipientId + verificationState:verificationState + isLocalChange:isLocalChange]]; + + for (TSGroupThread *groupThread in [TSGroupThread groupThreadsWithRecipientId:recipientId]) { + [messages + addObject:[[OWSVerificationStateChangeMessage alloc] initWithTimestamp:[NSDate ows_millisecondTimeStamp] + thread:groupThread + recipientId:recipientId + verificationState:verificationState + isLocalChange:isLocalChange]]; + } + + [self.storageManager.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + for (TSMessage *message in messages) { + [message saveWithTransaction:transaction]; + } + }]; +} + #pragma mark - Notifications - (void)applicationDidBecomeActive:(NSNotification *)notification