diff --git a/Session/Calls/Call Management/SessionCall.swift b/Session/Calls/Call Management/SessionCall.swift index 1fc8620a5..a9ccbcdf0 100644 --- a/Session/Calls/Call Management/SessionCall.swift +++ b/Session/Calls/Call Management/SessionCall.swift @@ -206,7 +206,7 @@ public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate { let thread: SessionThread = try? SessionThread.fetchOne(db, id: sessionId) else { return } - let timestampMs: Int64 = Int64(floor(Date().timeIntervalSince1970 * 1000)) + let timestampMs: Int64 = SnodeAPI.currentOffsetTimestampMs() let message: CallMessage = CallMessage( uuid: self.uuid, kind: .preOffer, diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 83cbbb45a..7758c398e 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -409,7 +409,7 @@ extension ConversationVC: // flags appropriately let threadId: String = self.viewModel.threadData.threadId let oldThreadShouldBeVisible: Bool = (self.viewModel.threadData.threadShouldBeVisible == true) - let sentTimestampMs: Int64 = Int64(floor((Date().timeIntervalSince1970 * 1000))) + let sentTimestampMs: Int64 = SnodeAPI.currentOffsetTimestampMs() let linkPreviewDraft: LinkPreviewDraft? = snInputView.linkPreviewInfo?.draft let quoteModel: QuotedReplyModel? = snInputView.quoteDraftInfo?.model @@ -534,7 +534,7 @@ extension ConversationVC: // flags appropriately let threadId: String = self.viewModel.threadData.threadId let oldThreadShouldBeVisible: Bool = (self.viewModel.threadData.threadShouldBeVisible == true) - let sentTimestampMs: Int64 = Int64(floor((Date().timeIntervalSince1970 * 1000))) + let sentTimestampMs: Int64 = SnodeAPI.currentOffsetTimestampMs() // If this was a message request then approve it approveMessageRequestIfNeeded( @@ -640,7 +640,7 @@ extension ConversationVC: threadVariant: threadVariant, threadIsMessageRequest: threadIsMessageRequest, direction: .outgoing, - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ) if needsToStartTypingIndicator { @@ -1219,7 +1219,7 @@ extension ConversationVC: guard !threadIsMessageRequest else { return } // Perform local rate limiting (don't allow more than 20 reactions within 60 seconds) - let sentTimestamp: Int64 = Int64(floor(Date().timeIntervalSince1970 * 1000)) + let sentTimestamp: Int64 = SnodeAPI.currentOffsetTimestampMs() let recentReactionTimestamps: [Int64] = General.cache.wrappedValue.recentReactionTimestamps guard @@ -2044,7 +2044,7 @@ extension ConversationVC: // Create URL let directory: String = OWSTemporaryDirectory() - let fileName: String = "\(Int64(floor(Date().timeIntervalSince1970 * 1000))).m4a" + let fileName: String = "\(SnodeAPI.currentOffsetTimestampMs()).m4a" let url: URL = URL(fileURLWithPath: directory).appendingPathComponent(fileName) // Set up audio session @@ -2285,7 +2285,7 @@ extension ConversationVC { for: self.viewModel.threadData.threadId, threadVariant: self.viewModel.threadData.threadVariant, isNewThread: false, - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ) } diff --git a/Session/Conversations/Settings/OWSMessageTimerView.m b/Session/Conversations/Settings/OWSMessageTimerView.m index dc71b3b06..bfe57d7e3 100644 --- a/Session/Conversations/Settings/OWSMessageTimerView.m +++ b/Session/Conversations/Settings/OWSMessageTimerView.m @@ -8,6 +8,7 @@ #import #import #import +#import NS_ASSUME_NONNULL_BEGIN @@ -75,7 +76,7 @@ const CGFloat kDisappearingMessageIconSize = 12.f; return; } - uint64_t nowTimestamp = [NSDate ows_millisecondTimeStamp]; + uint64_t nowTimestamp = [SNSnodeAPI currentOffsetTimestampMs]; CGFloat secondsLeft = (self.expirationTimestamp > nowTimestamp ? (self.expirationTimestamp - nowTimestamp) / 1000.f : 0.f); CGFloat progress = 0.f; diff --git a/Session/Conversations/Settings/ThreadDisappearingMessagesViewModel.swift b/Session/Conversations/Settings/ThreadDisappearingMessagesViewModel.swift index aace471aa..886cc326a 100644 --- a/Session/Conversations/Settings/ThreadDisappearingMessagesViewModel.swift +++ b/Session/Conversations/Settings/ThreadDisappearingMessagesViewModel.swift @@ -168,7 +168,7 @@ class ThreadDisappearingMessagesViewModel: SessionTableViewModel () ) { // The 'backgroundTask' gets captured and cleared within the 'completion' block - let timestampNowMs: TimeInterval = ceil(Date().timeIntervalSince1970 * 1000) + let timestampNowMs: TimeInterval = TimeInterval(SnodeAPI.currentOffsetTimestampMs()) var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: #function) let updatedJob: Job? = Storage.shared.write { db in @@ -59,10 +60,14 @@ public extension DisappearingMessagesJob { guard let nextExpirationTimestampMs: Double = nextExpirationTimestampMs else { return nil } + /// The `expiresStartedAtMs` timestamp is now based on the `SnodeAPI.currentOffsetTimestampMs()` value + /// so we need to make sure offset the `nextRunTimestamp` accordingly to ensure it runs at the correct local time + let clockOffsetMs: Int64 = SnodeAPI.clockOffsetMs.wrappedValue + return try? Job .filter(Job.Columns.variant == Job.Variant.disappearingMessages) .fetchOne(db)? - .with(nextRunTimestamp: ceil(nextExpirationTimestampMs / 1000)) + .with(nextRunTimestamp: ceil((nextExpirationTimestampMs - Double(clockOffsetMs)) / 1000)) .saved(db) } diff --git a/SessionMessagingKit/Messages/Message.swift b/SessionMessagingKit/Messages/Message.swift index bac6dbb5e..1f239920c 100644 --- a/SessionMessagingKit/Messages/Message.swift +++ b/SessionMessagingKit/Messages/Message.swift @@ -259,7 +259,10 @@ public extension Message { return try processRawReceivedMessage( db, envelope: envelope, - serverExpirationTimestamp: (Date().timeIntervalSince1970 + ControlMessageProcessRecord.defaultExpirationSeconds), + serverExpirationTimestamp: ( + (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) + + ControlMessageProcessRecord.defaultExpirationSeconds + ), serverHash: serverHash, handleClosedGroupKeyUpdateMessages: true ) @@ -275,7 +278,10 @@ public extension Message { let processedMessage: ProcessedMessage? = try processRawReceivedMessage( db, envelope: envelope, - serverExpirationTimestamp: (Date().timeIntervalSince1970 + ControlMessageProcessRecord.defaultExpirationSeconds), + serverExpirationTimestamp: ( + (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) + + ControlMessageProcessRecord.defaultExpirationSeconds + ), serverHash: nil, handleClosedGroupKeyUpdateMessages: false ) @@ -407,7 +413,7 @@ public extension Message { let count: Int64 = rawReaction.you ? rawReaction.count - 1 : rawReaction.count - let timestampMs: Int64 = Int64(floor((Date().timeIntervalSince1970 * 1000))) + let timestampMs: Int64 = SnodeAPI.currentOffsetTimestampMs() let maxLength: Int = shouldAddSelfReaction ? 4 : 5 let desiredReactorIds: [String] = reactors .filter { $0 != blindedUserPublicKey && $0 != userPublicKey } // Remove current user for now, will add back if needed diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift index 8dc60c126..9f8f652db 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+Calls.swift @@ -4,6 +4,7 @@ import Foundation import GRDB import WebRTC import SessionUtilitiesKit +import SessionSnodeKit extension MessageReceiver { public static func handleCallMessage(_ db: Database, message: CallMessage) throws { @@ -189,7 +190,7 @@ extension MessageReceiver { body: String(data: messageInfoData, encoding: .utf8), timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ) .inserted(db) @@ -235,7 +236,7 @@ extension MessageReceiver { ) let timestampMs: Int64 = ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) guard let messageInfoData: Data = try? JSONEncoder().encode(messageInfo) else { return nil } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift index 5c5620a81..669e46de0 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift @@ -4,6 +4,7 @@ import Foundation import GRDB import Sodium import SessionUtilitiesKit +import SessionSnodeKit extension MessageReceiver { public static func handleClosedGroupControlMessage(_ db: Database, _ message: ClosedGroupControlMessage) throws { @@ -135,7 +136,7 @@ extension MessageReceiver { threadId: groupPublicKey, publicKey: Data(encryptionKeyPair.publicKey), secretKey: Data(encryptionKeyPair.secretKey), - receivedTimestamp: Date().timeIntervalSince1970 + receivedTimestamp: (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) ).insert(db) // Start polling @@ -196,7 +197,7 @@ extension MessageReceiver { threadId: groupPublicKey, publicKey: proto.publicKey.removingIdPrefixIfNeeded(), secretKey: proto.privateKey, - receivedTimestamp: Date().timeIntervalSince1970 + receivedTimestamp: (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) ).insert(db) } catch { @@ -231,7 +232,7 @@ extension MessageReceiver { .infoMessage(db, sender: sender), timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ).inserted(db) } @@ -307,7 +308,7 @@ extension MessageReceiver { .infoMessage(db, sender: sender), timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ).inserted(db) } @@ -383,7 +384,7 @@ extension MessageReceiver { .infoMessage(db, sender: sender), timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ).inserted(db) } @@ -461,7 +462,7 @@ extension MessageReceiver { .infoMessage(db, sender: sender), timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ).inserted(db) } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+DataExtractionNotification.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+DataExtractionNotification.swift index fd74915a9..a28346f6d 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+DataExtractionNotification.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+DataExtractionNotification.swift @@ -2,6 +2,7 @@ import Foundation import GRDB +import SessionSnodeKit extension MessageReceiver { internal static func handleDataExtractionNotification(_ db: Database, message: DataExtractionNotification) throws { @@ -24,7 +25,7 @@ extension MessageReceiver { }(), timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ).inserted(db) } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift index d16adbe95..06ee54eb3 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+MessageRequests.swift @@ -4,6 +4,7 @@ import Foundation import GRDB import SignalCoreKit import SessionUtilitiesKit +import SessionSnodeKit extension MessageReceiver { internal static func handleMessageRequestResponse( @@ -123,7 +124,7 @@ extension MessageReceiver { variant: .infoMessageRequestAccepted, timestampMs: ( message.sentTimestamp.map { Int64($0) } ?? - Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.currentOffsetTimestampMs() ) ).inserted(db) } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift index bc8d52a0b..0d219b5b2 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift @@ -6,6 +6,7 @@ import Sodium import Curve25519Kit import PromiseKit import SessionUtilitiesKit +import SessionSnodeKit extension MessageSender { public static var distributingKeyPairs: Atomic<[String: [ClosedGroupKeyPair]]> = Atomic([:]) @@ -24,7 +25,7 @@ extension MessageSender { let membersAsData = members.map { Data(hex: $0) } let admins = [ userPublicKey ] let adminsAsData = admins.map { Data(hex: $0) } - let formationTimestamp: TimeInterval = Date().timeIntervalSince1970 + let formationTimestamp: TimeInterval = (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) let thread: SessionThread = try SessionThread .fetchOrCreate(db, id: groupPublicKey, variant: .closedGroup) try ClosedGroup( @@ -91,7 +92,7 @@ extension MessageSender { threadId: groupPublicKey, publicKey: encryptionKeyPair.publicKey, secretKey: encryptionKeyPair.privateKey, - receivedTimestamp: Date().timeIntervalSince1970 + receivedTimestamp: (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) ).insert(db) // Notify the PN server @@ -110,7 +111,7 @@ extension MessageSender { threadId: thread.id, authorId: userPublicKey, variant: .infoClosedGroupCreated, - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) // Start polling @@ -142,7 +143,7 @@ extension MessageSender { threadId: closedGroup.threadId, publicKey: legacyNewKeyPair.publicKey, secretKey: legacyNewKeyPair.privateKey, - receivedTimestamp: Date().timeIntervalSince1970 + receivedTimestamp: (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) ) // Distribute it @@ -230,7 +231,7 @@ extension MessageSender { body: ClosedGroupControlMessage.Kind .nameChange(name: name) .infoMessage(db, sender: userPublicKey), - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved } @@ -330,7 +331,7 @@ extension MessageSender { body: ClosedGroupControlMessage.Kind .membersAdded(members: addedMembers.map { Data(hex: $0) }) .infoMessage(db, sender: userPublicKey), - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) guard let interactionId: Int64 = interaction.id else { throw StorageError.objectNotSaved } @@ -431,7 +432,7 @@ extension MessageSender { body: ClosedGroupControlMessage.Kind .membersRemoved(members: removedMembers.map { Data(hex: $0) }) .infoMessage(db, sender: userPublicKey), - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) guard let newInteractionId: Int64 = interaction.id else { throw StorageError.objectNotSaved } @@ -496,7 +497,7 @@ extension MessageSender { body: ClosedGroupControlMessage.Kind .memberLeft .infoMessage(db, sender: userPublicKey), - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)) + timestampMs: SnodeAPI.currentOffsetTimestampMs() ).inserted(db) guard let interactionId: Int64 = interaction.id else { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index f3b6f674c..0c9196ac3 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -5,6 +5,7 @@ import GRDB import Sodium import SignalCoreKit import SessionUtilitiesKit +import SessionSnodeKit public enum MessageReceiver { private static var lastEncryptionKeyPairRequest: [String: Date] = [:] @@ -144,7 +145,7 @@ public enum MessageReceiver { message.sender = sender message.recipient = userPublicKey message.sentTimestamp = envelope.timestamp - message.receivedTimestamp = UInt64((Date().timeIntervalSince1970) * 1000) + message.receivedTimestamp = UInt64(SnodeAPI.currentOffsetTimestampMs()) message.groupPublicKey = groupPublicKey message.openGroupServerMessageId = openGroupMessageServerId.map { UInt64($0) } diff --git a/SessionMessagingKit/Sending & Receiving/MessageSender.swift b/SessionMessagingKit/Sending & Receiving/MessageSender.swift index 547ab9521..ead951cbb 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageSender.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageSender.swift @@ -67,7 +67,7 @@ public final class MessageSender { let (promise, seal) = Promise.pending() let userPublicKey: String = getUserHexEncodedPublicKey(db) let isMainAppActive: Bool = (UserDefaults.sharedLokiProject?[.isMainAppActive]).defaulting(to: false) - let messageSendTimestamp: Int64 = Int64(floor(Date().timeIntervalSince1970 * 1000)) + let messageSendTimestamp: Int64 = SnodeAPI.currentOffsetTimestampMs() // Set the timestamp, sender and recipient message.sentTimestamp = ( @@ -202,7 +202,7 @@ public final class MessageSender { recipient: message.recipient!, data: base64EncodedData, ttl: message.ttl, - timestampMs: UInt64(messageSendTimestamp + SnodeAPI.clockOffset.wrappedValue) + timestampMs: UInt64(messageSendTimestamp) ) SnodeAPI @@ -322,7 +322,7 @@ public final class MessageSender { // Set the timestamp, sender and recipient if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set - message.sentTimestamp = UInt64(floor(Date().timeIntervalSince1970 * 1000)) + message.sentTimestamp = UInt64(SnodeAPI.currentOffsetTimestampMs()) } switch destination { @@ -472,7 +472,7 @@ public final class MessageSender { // Set the timestamp, sender and recipient if message.sentTimestamp == nil { // Visible messages will already have their sent timestamp set - message.sentTimestamp = UInt64(floor(Date().timeIntervalSince1970 * 1000)) + message.sentTimestamp = UInt64(SnodeAPI.currentOffsetTimestampMs()) } message.sender = userPublicKey @@ -617,7 +617,7 @@ public final class MessageSender { job: DisappearingMessagesJob.updateNextRunIfNeeded( db, interaction: interaction, - startedAtMs: (Date().timeIntervalSince1970 * 1000) + startedAtMs: TimeInterval(SnodeAPI.currentOffsetTimestampMs()) ) ) } @@ -636,7 +636,10 @@ public final class MessageSender { } }(), message: message, - serverExpirationTimestamp: (Date().timeIntervalSince1970 + ControlMessageProcessRecord.defaultExpirationSeconds) + serverExpirationTimestamp: ( + (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) + + ControlMessageProcessRecord.defaultExpirationSeconds + ) )?.insert(db) // Sync the message if: diff --git a/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift index 9e50e80b8..afebe2c10 100644 --- a/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift +++ b/SessionMessagingKit/Sending & Receiving/Typing Indicators/TypingIndicators.swift @@ -3,6 +3,7 @@ import Foundation import GRDB import SessionUtilitiesKit +import SessionSnodeKit public class TypingIndicators { // MARK: - Direction @@ -41,7 +42,7 @@ public class TypingIndicators { self.threadId = threadId self.direction = direction - self.timestampMs = (timestampMs ?? Int64(floor(Date().timeIntervalSince1970 * 1000))) + self.timestampMs = (timestampMs ?? SnodeAPI.currentOffsetTimestampMs()) } fileprivate func start(_ db: Database) { diff --git a/SessionShareExtension/ThreadPickerVC.swift b/SessionShareExtension/ThreadPickerVC.swift index 7db42407d..5fb7aaf2a 100644 --- a/SessionShareExtension/ThreadPickerVC.swift +++ b/SessionShareExtension/ThreadPickerVC.swift @@ -196,7 +196,7 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView authorId: getUserHexEncodedPublicKey(db), variant: .standardOutgoing, body: body, - timestampMs: Int64(floor(Date().timeIntervalSince1970 * 1000)), + timestampMs: SnodeAPI.currentOffsetTimestampMs(), hasMention: Interaction.isUserMentioned(db, threadId: threadId, body: body), expiresInSeconds: try? DisappearingMessagesConfiguration .select(.durationSeconds) diff --git a/SessionSnodeKit/Database/Models/SnodeReceivedMessageInfo.swift b/SessionSnodeKit/Database/Models/SnodeReceivedMessageInfo.swift index 7addb56e5..336a19de8 100644 --- a/SessionSnodeKit/Database/Models/SnodeReceivedMessageInfo.swift +++ b/SessionSnodeKit/Database/Models/SnodeReceivedMessageInfo.swift @@ -93,7 +93,7 @@ public extension SnodeReceivedMessageInfo { return try SnodeReceivedMessageInfo .select(Column.rowID) .filter(SnodeReceivedMessageInfo.Columns.key == key(for: snode, publicKey: publicKey, namespace: namespace)) - .filter(SnodeReceivedMessageInfo.Columns.expirationDateMs <= (Date().timeIntervalSince1970 * 1000)) + .filter(SnodeReceivedMessageInfo.Columns.expirationDateMs <= SnodeAPI.currentOffsetTimestampMs()) .asRequest(of: Int64.self) .fetchAll(db) } @@ -122,7 +122,7 @@ public extension SnodeReceivedMessageInfo { SnodeReceivedMessageInfo.Columns.wasDeletedOrInvalid == false ) .filter(SnodeReceivedMessageInfo.Columns.key == key(for: snode, publicKey: publicKey, namespace: namespace)) - .filter(SnodeReceivedMessageInfo.Columns.expirationDateMs > (Date().timeIntervalSince1970 * 1000)) + .filter(SnodeReceivedMessageInfo.Columns.expirationDateMs > SnodeAPI.currentOffsetTimestampMs()) .order(SnodeReceivedMessageInfo.Columns.id.desc) .fetchOne(db) diff --git a/SessionSnodeKit/OnionRequestAPI.swift b/SessionSnodeKit/OnionRequestAPI.swift index 2254c160e..eedb629aa 100644 --- a/SessionSnodeKit/OnionRequestAPI.swift +++ b/SessionSnodeKit/OnionRequestAPI.swift @@ -676,7 +676,7 @@ public enum OnionRequestAPI: OnionRequestAPIType { if let timestamp = body["t"] as? Int64 { let offset = timestamp - Int64(floor(Date().timeIntervalSince1970 * 1000)) - SnodeAPI.clockOffset.mutate { $0 = offset } + SnodeAPI.clockOffsetMs.mutate { $0 = offset } } guard 200...299 ~= statusCode else { diff --git a/SessionSnodeKit/SnodeAPI.swift b/SessionSnodeKit/SnodeAPI.swift index db0d2903a..eff7c6632 100644 --- a/SessionSnodeKit/SnodeAPI.swift +++ b/SessionSnodeKit/SnodeAPI.swift @@ -19,10 +19,16 @@ public final class SnodeAPI { internal static var snodePool: Atomic> = Atomic([]) /// The offset between the user's clock and the Service Node's clock. Used in cases where the - /// user's clock is incorrect. - /// - /// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions. - public static var clockOffset: Atomic = Atomic(0) + /// user's clock is incorrect + public static var clockOffsetMs: Atomic = Atomic(0) + + public static func currentOffsetTimestampMs() -> Int64 { + return ( + Int64(floor(Date().timeIntervalSince1970 * 1000)) + + SnodeAPI.clockOffsetMs.wrappedValue + ) + } + /// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions. public static var swarmCache: Atomic<[String: Set]> = Atomic([:]) @@ -546,7 +552,7 @@ public final class SnodeAPI { let lastHash = SnodeReceivedMessageInfo.fetchLastNotExpired(for: snode, namespace: namespace, associatedWith: publicKey)?.hash ?? "" // Construct signature - let timestamp = UInt64(Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.clockOffset.wrappedValue) + let timestamp = UInt64(SnodeAPI.currentOffsetTimestampMs()) let ed25519PublicKey = userED25519KeyPair.publicKey.toHexString() let namespaceVerificationString = (namespace == defaultNamespace ? "" : String(namespace)) @@ -647,7 +653,7 @@ public final class SnodeAPI { } // Construct signature - let timestamp = UInt64(Int64(floor(Date().timeIntervalSince1970 * 1000)) + SnodeAPI.clockOffset.wrappedValue) + let timestamp = UInt64(SnodeAPI.currentOffsetTimestampMs()) let ed25519PublicKey = userED25519KeyPair.publicKey.toHexString() guard @@ -1102,3 +1108,11 @@ public final class SnodeAPI { return nil } } + +@objc(SNSnodeAPI) +public final class SNSnodeAPI: NSObject { + @objc(currentOffsetTimestampMs) + public static func currentOffsetTimestampMs() -> UInt64 { + return UInt64(SnodeAPI.currentOffsetTimestampMs()) + } +}