From 550e7ba63b5ce06100d320b57c2ec57ac6fae738 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Thu, 20 Sep 2018 11:19:12 -0600 Subject: [PATCH] Create disappearing message update info messages before messages they affect Since we're no longer sorting by timestamp we have to ensure we save the update info message before we save any affected message, e.g. in the case of implicit updates. --- .../src/Devices/OWSRecordTranscriptJob.m | 14 +++--- ...sappearingConfigurationUpdateInfoMessage.m | 2 +- .../src/Messages/OWSDisappearingMessagesJob.h | 27 ++--------- .../src/Messages/OWSDisappearingMessagesJob.m | 46 +++++++++---------- .../src/Messages/OWSMessageManager.m | 46 ++++++++++--------- 5 files changed, 56 insertions(+), 79 deletions(-) diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m index a09978c31..c3230e9c8 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m @@ -129,12 +129,13 @@ NS_ASSUME_NONNULL_BEGIN } } - if (transcript.isExpirationTimerUpdate) { - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage - contactsManager:self.contactsManager - transaction:transaction]; - + [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:outgoingMessage.expiresInSeconds + thread:transcript.thread + createdByRemoteRecipientId:nil + createdInExistingGroup:NO + transaction:transaction]; + if (transcript.isExpirationTimerUpdate) { // early return to avoid saving an empty incoming message. OWSAssertDebug(transcript.body.length == 0); OWSAssertDebug(outgoingMessage.attachmentIds.count == 0); @@ -149,9 +150,6 @@ NS_ASSUME_NONNULL_BEGIN [outgoingMessage saveWithTransaction:transaction]; [outgoingMessage updateWithWasSentFromLinkedDeviceWithTransaction:transaction]; - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage - contactsManager:self.contactsManager - transaction:transaction]; [[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage expirationStartedAt:transcript.expirationStartedAt transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/Interactions/OWSDisappearingConfigurationUpdateInfoMessage.m b/SignalServiceKit/src/Messages/Interactions/OWSDisappearingConfigurationUpdateInfoMessage.m index f57c4181c..d3a593511 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSDisappearingConfigurationUpdateInfoMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSDisappearingConfigurationUpdateInfoMessage.m @@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN return [NSString stringWithFormat:infoFormat, self.createdByRemoteName]; } } else { - // Changed by local request + // Changed by localNumber on this device or via synced transcript if (self.configurationIsEnabled && self.configurationDurationSeconds > 0) { NSString *infoFormat = NSLocalizedString(@"YOU_UPDATED_DISAPPEARING_MESSAGES_CONFIGURATION", @"Info message embedding a {{time amount}}, see the *_TIME_AMOUNT strings for context."); diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h index 20b4fc249..0eb504c33 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h @@ -21,42 +21,23 @@ NS_ASSUME_NONNULL_BEGIN expirationStartedAt:(uint64_t)expirationStartedAt transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction; -/** - * Synchronize our disappearing messages settings with that of the given message. Useful so we can - * become eventually consistent with remote senders. - * - * @param message - * Can be an expiring or non expiring message. We match the expiration timer of the message, including disabling - * expiring messages if the message is not an expiring message. - * - * @param contactsManager - * Provides the contact name responsible for any configuration changes in an info message. - */ -- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message - contactsManager:(id)contactsManager - transaction:(YapDatabaseReadWriteTransaction *)transaction; - /** * Synchronize our disappearing messages settings with that of the given message. Useful so we can * become eventually consistent with remote senders. * * @param duration * Can be 0, indicating a non-expiring message, or greater, indicating an expiring message. We match the expiration - * timer of the message, including disabling expiring messages if the message is not an expiring message. + * timer of the message, including disabling expiring messages if the message is not an expiring message. * - * @param timestampForSorting - * timestampForSorting of the message before which we want to appear. + * @param remoteRecipientId + * nil for outgoing messages, otherwise the recipientId of the sender * - * @param remoteContactName - * nil for outgoing messages, otherwise the name of the sender * @param createdInExistingGroup * YES when being added to a group which already has DM enabled, otherwise NO */ -// MJK FIXME - we can't rely on timestampForSorting - (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration thread:(TSThread *)thread - appearBeforeSenderTimestamp:(uint64_t)timestampForSorting - createdByRemoteContactName:(nullable NSString *)remoteContactName + createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId createdInExistingGroup:(BOOL)createdInExistingGroup transaction:(YapDatabaseReadWriteTransaction *)transaction; diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m index 6e43d008d..794ee87cf 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m @@ -13,6 +13,7 @@ #import "OWSDisappearingMessagesConfiguration.h" #import "OWSDisappearingMessagesFinder.h" #import "OWSPrimaryStorage.h" +#import "SSKEnvironment.h" #import "TSIncomingMessage.h" #import "TSMessage.h" #import "TSThread.h" @@ -110,6 +111,15 @@ void AssertIsOnDisappearingMessagesQueue() return queue; } +#pragma mark - Dependencies + +- (id)contactsManager +{ + return SSKEnvironment.shared.contactsManager; +} + +#pragma mark - + - (NSUInteger)deleteExpiredMessages { AssertIsOnDisappearingMessagesQueue(); @@ -193,40 +203,25 @@ void AssertIsOnDisappearingMessagesQueue() }]; } -- (void)becomeConsistentWithConfigurationForMessage:(TSMessage *)message - contactsManager:(id)contactsManager - transaction:(YapDatabaseReadWriteTransaction *)transaction -{ - TSThread *thread = [message threadWithTransaction:transaction]; - NSString *remoteContactName = nil; - if ([message isKindOfClass:[TSIncomingMessage class]]) { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)message; - remoteContactName = [contactsManager displayNameForPhoneIdentifier:incomingMessage.messageAuthorId]; - } - // MJK - we can't rely on timestampForSorting - [self becomeConsistentWithDisappearingDuration:message.expiresInSeconds - thread:thread - appearBeforeSenderTimestamp:message.timestampForSorting - createdByRemoteContactName:remoteContactName - createdInExistingGroup:NO - transaction:transaction]; -} +#pragma mark - Apply Remote Configuration -// MJK - we can't rely on timestampForSorting - (void)becomeConsistentWithDisappearingDuration:(uint32_t)duration thread:(TSThread *)thread - appearBeforeSenderTimestamp:(uint64_t)timestampForSorting - createdByRemoteContactName:(nullable NSString *)remoteContactName + createdByRemoteRecipientId:(nullable NSString *)remoteRecipientId createdInExistingGroup:(BOOL)createdInExistingGroup transaction:(YapDatabaseReadWriteTransaction *)transaction { OWSAssertDebug(thread); - OWSAssertDebug(timestampForSorting > 0); OWSAssertDebug(transaction); OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__]; + NSString *_Nullable remoteContactName = nil; + if (remoteRecipientId) { + remoteContactName = [self.contactsManager displayNameForPhoneIdentifier:remoteRecipientId]; + } + // Become eventually consistent in the case that the remote changed their settings at the same time. // Also in case remote doesn't support expiring messages OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration = @@ -248,10 +243,9 @@ void AssertIsOnDisappearingMessagesQueue() [disappearingMessagesConfiguration saveWithTransaction:transaction]; - // We want the info message to appear _before_ the message. - // MJK FIXME - we have to affect ordering by creation sequence, not sender timestamp + // MJK TODO - should be safe to remove this senderTimestamp OWSDisappearingConfigurationUpdateInfoMessage *infoMessage = - [[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithSenderTimestamp:timestampForSorting - 1 + [[OWSDisappearingConfigurationUpdateInfoMessage alloc] initWithSenderTimestamp:[NSDate ows_millisecondTimeStamp] thread:thread configuration:disappearingMessagesConfiguration createdByRemoteName:remoteContactName @@ -262,6 +256,8 @@ void AssertIsOnDisappearingMessagesQueue() backgroundTask = nil; } +#pragma mark - + - (void)startIfNecessary { dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 605e6e2f6..c58e9f8be 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -1146,8 +1146,6 @@ NS_ASSUME_NONNULL_BEGIN TSGroupThread *newGroupThread = [TSGroupThread getOrCreateThreadWithGroupId:groupId transaction:transaction]; - - uint64_t now = [NSDate ows_millisecondTimeStamp]; TSGroupModel *newGroupModel = [[TSGroupModel alloc] initWithTitle:dataMessage.group.name memberIds:newMemberIds.allObjects image:oldGroupThread.groupModel.groupImage @@ -1157,23 +1155,19 @@ NS_ASSUME_NONNULL_BEGIN newGroupThread.groupModel = newGroupModel; [newGroupThread saveWithTransaction:transaction]; - // MJK FIXME - seems like we're relying on senderTimestamp - TSInfoMessage *infoMessage = [[TSInfoMessage alloc] initWithSenderTimestamp:now - inThread:newGroupThread - messageType:TSInfoMessageTypeGroupUpdate - customMessage:updateGroupInfo]; - [infoMessage saveWithTransaction:transaction]; + [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer + thread:newGroupThread + createdByRemoteRecipientId:nil + createdInExistingGroup:NO + transaction:transaction]; - if (dataMessage.hasExpireTimer && dataMessage.expireTimer > 0) { - // MJK - we can't rely on senderTimestamp - [[OWSDisappearingMessagesJob sharedJob] - becomeConsistentWithDisappearingDuration:dataMessage.expireTimer - thread:newGroupThread - appearBeforeSenderTimestamp:now - createdByRemoteContactName:nil - createdInExistingGroup:YES - transaction:transaction]; - } + // MJK TODO - should be safe to remove senderTimestamp + TSInfoMessage *infoMessage = + [[TSInfoMessage alloc] initWithSenderTimestamp:[NSDate ows_millisecondTimeStamp] + inThread:newGroupThread + messageType:TSInfoMessageTypeGroupUpdate + customMessage:updateGroupInfo]; + [infoMessage saveWithTransaction:transaction]; return nil; } @@ -1210,6 +1204,12 @@ NS_ASSUME_NONNULL_BEGIN return nil; } + [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer + thread:oldGroupThread + createdByRemoteRecipientId:envelope.source + createdInExistingGroup:YES + transaction:transaction]; + TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage thread:oldGroupThread transaction:transaction]; @@ -1255,6 +1255,12 @@ NS_ASSUME_NONNULL_BEGIN TSContactThread *thread = [TSContactThread getOrCreateThreadWithContactId:envelope.source transaction:transaction]; + [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithDisappearingDuration:dataMessage.expireTimer + thread:thread + createdByRemoteRecipientId:envelope.source + createdInExistingGroup:NO + transaction:transaction]; + TSQuotedMessage *_Nullable quotedMessage = [TSQuotedMessage quotedMessageForDataMessage:dataMessage thread:thread transaction:transaction]; @@ -1369,10 +1375,6 @@ NS_ASSUME_NONNULL_BEGIN [OWSReadReceiptManager.sharedManager applyEarlyReadReceiptsForIncomingMessage:incomingMessage transaction:transaction]; - [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:incomingMessage - contactsManager:self.contactsManager - transaction:transaction]; - // Update thread preview in inbox [thread touchWithTransaction:transaction];