diff --git a/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.h b/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.h index efd28287f..4353dc19a 100644 --- a/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.h +++ b/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.h @@ -27,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN transaction:(YapDatabaseReadTransaction *)transaction; + (NSArray *)validDurationsSeconds; ++ (uint32_t)maxDurationSeconds; @end diff --git a/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.m b/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.m index eb5a8f162..5650fc72a 100644 --- a/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.m +++ b/SignalServiceKit/src/Contacts/OWSDisappearingMessagesConfiguration.m @@ -64,17 +64,29 @@ NS_ASSUME_NONNULL_BEGIN + (NSArray *)validDurationsSeconds { - return @[ @(5), - @(10), - @(30), - @(60), - @(300), - @(1800), - @(3600), - @(21600), - @(43200), - @(86400), - @(604800) ]; + return @[ + @(5 * kSecondInterval), + @(10 * kSecondInterval), + @(30 * kSecondInterval), + @(1 * kMinuteInterval), + @(5 * kMinuteInterval), + @(30 * kMinuteInterval), + @(1 * kHourInterval), + @(6 * kHourInterval), + @(12 * kHourInterval), + @(24 * kHourInterval), + @(1 * kWeekInterval) + ]; +} + ++ (uint32_t)maxDurationSeconds +{ + uint32_t max = [[self.validDurationsSeconds valueForKeyPath:@"@max.intValue"] unsignedIntValue]; + + // It's safe to update this assert if we add a larger duration + OWSAssert(max == 1 * kWeekInterval); + + return max; } - (NSUInteger)durationIndex diff --git a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m index 22f338c2d..bb9631489 100644 --- a/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m +++ b/SignalServiceKit/src/Devices/OWSRecordTranscriptJob.m @@ -151,9 +151,9 @@ NS_ASSUME_NONNULL_BEGIN [[OWSDisappearingMessagesJob sharedJob] becomeConsistentWithConfigurationForMessage:outgoingMessage contactsManager:self.contactsManager transaction:transaction]; - [[OWSDisappearingMessagesJob sharedJob] setExpirationForMessage:outgoingMessage - expirationStartedAt:transcript.expirationStartedAt - transaction:transaction]; + [[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:outgoingMessage + expirationStartedAt:transcript.expirationStartedAt + transaction:transaction]; [self.readReceiptManager applyEarlyReadReceiptsForOutgoingMessageFromLinkedDevice:outgoingMessage transaction:transaction]; diff --git a/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m index efd862450..431b4b40c 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSIncomingMessage.m @@ -151,11 +151,11 @@ NS_ASSUME_NONNULL_BEGIN { OWSAssert(transaction); - if (_read && readTimestamp <= self.expireStartedAt) { + if (_read && readTimestamp >= self.expireStartedAt) { return; } - - NSTimeInterval secondsAgoRead = ([NSDate ows_millisecondTimeStamp] - readTimestamp) / 1000; + + NSTimeInterval secondsAgoRead = ((NSTimeInterval)[NSDate ows_millisecondTimeStamp] - (NSTimeInterval)readTimestamp) / 1000; DDLogDebug(@"%@ marking uniqueId: %@ which has timestamp: %llu as read: %f seconds ago", self.logTag, self.uniqueId, @@ -164,6 +164,13 @@ NS_ASSUME_NONNULL_BEGIN _read = YES; [self saveWithTransaction:transaction]; [self touchThreadWithTransaction:transaction]; + + [transaction addCompletionQueue:nil + completionBlock:^{ + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:kIncomingMessageMarkedAsReadNotification + object:self]; + }]; [[OWSDisappearingMessagesJob sharedJob] startAnyExpirationForMessage:self expirationStartedAt:readTimestamp diff --git a/SignalServiceKit/src/Messages/Interactions/TSMessage.m b/SignalServiceKit/src/Messages/Interactions/TSMessage.m index 94a774e86..a14972967 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSMessage.m @@ -8,6 +8,7 @@ #import "NSDate+OWS.h" #import "NSString+SSK.h" #import "OWSContact.h" +#import "OWSDisappearingMessagesConfiguration.h" #import "TSAttachment.h" #import "TSAttachmentStream.h" #import "TSQuotedMessage.h" @@ -153,13 +154,31 @@ static const NSUInteger OWSMessageSchemaVersion = 4; - (void)setExpiresInSeconds:(uint32_t)expiresInSeconds { - _expiresInSeconds = expiresInSeconds; + uint32_t maxExpirationDuration = [OWSDisappearingMessagesConfiguration maxDurationSeconds]; + if (expiresInSeconds > maxExpirationDuration) { + OWSProdLogAndFail(@"%@ in %s using `maxExpirationDuration` instead of: %u", + self.logTag, + __PRETTY_FUNCTION__, + maxExpirationDuration); + } + + _expiresInSeconds = MIN(expiresInSeconds, maxExpirationDuration); [self updateExpiresAt]; } - (void)setExpireStartedAt:(uint64_t)expireStartedAt { - _expireStartedAt = expireStartedAt; + if (_expireStartedAt != 0 && _expireStartedAt < expireStartedAt) { + DDLogDebug(@"%@ in %s ignoring later startedAt time", self.logTag, __PRETTY_FUNCTION__); + return; + } + + uint64_t now = [NSDate ows_millisecondTimeStamp]; + if (expireStartedAt > now) { + DDLogWarn(@"%@ in %s using `now` instead of future time", self.logTag, __PRETTY_FUNCTION__); + } + + _expireStartedAt = MIN(now, expireStartedAt); [self updateExpiresAt]; } diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h index 1d611d8e8..d8c9b2fed 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.h @@ -21,10 +21,6 @@ NS_ASSUME_NONNULL_BEGIN expirationStartedAt:(uint64_t)expirationStartedAt transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction; -- (void)setExpirationForMessage:(TSMessage *)message - 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. diff --git a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m index cba7aced0..1c7461604 100644 --- a/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m +++ b/SignalServiceKit/src/Messages/OWSDisappearingMessagesJob.m @@ -170,17 +170,6 @@ void AssertIsOnDisappearingMessagesQueue() - (void)startAnyExpirationForMessage:(TSMessage *)message expirationStartedAt:(uint64_t)expirationStartedAt transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction -{ - if (!message.isExpiringMessage) { - return; - } - - [self setExpirationForMessage:message expirationStartedAt:expirationStartedAt transaction:transaction]; -} - -- (void)setExpirationForMessage:(TSMessage *)message - expirationStartedAt:(uint64_t)expirationStartedAt - transaction:(YapDatabaseReadWriteTransaction *_Nonnull)transaction { OWSAssert(transaction); @@ -401,7 +390,7 @@ void AssertIsOnDisappearingMessagesQueue() // We don't know when it was actually read, so assume it was read as soon as it was received. uint64_t readTimeBestGuess = message.timestampForSorting; - [self setExpirationForMessage:message expirationStartedAt:readTimeBestGuess transaction:transaction]; + [self startAnyExpirationForMessage:message expirationStartedAt:readTimeBestGuess transaction:transaction]; } transaction:transaction]; } diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m index 8c5b1c2cb..0a5c1bf42 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m @@ -438,13 +438,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE [message markAsReadAtTimestamp:readReceipt.readTimestamp sendReadReceipt:NO transaction:transaction]; [readReceipt removeWithTransaction:transaction]; - - [transaction addCompletionQueue:nil - completionBlock:^{ - [[NSNotificationCenter defaultCenter] - postNotificationNameAsync:kIncomingMessageMarkedAsReadNotification - object:message]; - }]; } - (void)processReadReceiptsFromLinkedDevice:(NSArray *)readReceiptProtos @@ -498,6 +491,11 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE OWSAssert(message); OWSAssert(transaction); + // Always re-mark the message as read to ensure any earlier read time is applied to disappearing messages. + [message markAsReadAtTimestamp:readTimestamp sendReadReceipt:NO transaction:transaction]; + + // Also mark any messages appearing earlier in the thread as read. + // // Use `timestampForSorting` which reflects local received order, rather than `timestamp` // which reflect sender time. [self markAsReadBeforeTimestamp:message.timestampForSorting @@ -547,10 +545,9 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE } OWSAssert(!possiblyRead.read); + OWSAssert(possiblyRead.expireStartedAt == 0); if (!possiblyRead.read) { [newlyReadList addObject:possiblyRead]; - } else if (readTimestamp < possiblyRead.expireStartedAt) { - [newlyReadList addObject:possiblyRead]; } }]; @@ -565,16 +562,6 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE } for (id readItem in newlyReadList) { [readItem markAsReadAtTimestamp:readTimestamp sendReadReceipt:wasLocal transaction:transaction]; - - if ([readItem isKindOfClass:[TSIncomingMessage class]]) { - TSIncomingMessage *incomingMessage = (TSIncomingMessage *)readItem; - [transaction addCompletionQueue:nil - completionBlock:^{ - [[NSNotificationCenter defaultCenter] - postNotificationNameAsync:kIncomingMessageMarkedAsReadNotification - object:incomingMessage]; - }]; - } } }