From f9468219d95d6327ded540a7953c16023895ebbd Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Fri, 4 Mar 2022 18:02:38 +1100 Subject: [PATCH] Code cleanup and database transaction tweaks Updated the OpenGroupManager to be a bit more thread safe Updated the OpenGroupManager "isModOrAdmin" check to better support the various keys of the current user Fixed some blinding code to use an existing transaction rather than create it's own ones Removed the Legacy API calls, handling and types --- Session.xcodeproj/project.pbxproj | 48 -- .../Database/Storage+Contacts.swift | 4 +- .../Messages/Signal/TSIncomingMessage.h | 2 +- .../Models/LegacyAuthTokenResponse.swift | 46 -- .../Models/LegacyCompactPollBody.swift | 27 - .../Models/LegacyCompactPollResponse.swift | 25 - .../LegacyDeletedMessagesResponse.swift | 13 - .../Open Groups/Models/LegacyDeletion.swift | 23 - .../Models/LegacyGetInfoResponse.swift | 9 - .../Models/LegacyMemberCountResponse.swift | 13 - .../Models/LegacyModeratorsResponse.swift | 9 - .../Models/LegacyOpenGroupMessageV2.swift | 71 -- .../Models/LegacyPublicKeyBody.swift | 13 - .../Open Groups/Models/LegacyRoomInfo.swift | 17 - .../Models/LegacyRoomsResponse.swift | 9 - .../Open Groups/OpenGroupAPI.swift | 637 ------------------ .../Open Groups/OpenGroupManager.swift | 104 ++- .../Open Groups/Types/SOGSEndpoint.swift | 84 --- .../MessageReceiver+Handling.swift | 2 +- .../Pollers/OpenGroupPoller.swift | 66 -- SessionMessagingKit/Storage.swift | 2 +- .../Utilities/ContactUtilities.swift | 35 +- .../_TestUtilities/TestStorage.swift | 2 +- 23 files changed, 95 insertions(+), 1166 deletions(-) delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyAuthTokenResponse.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyCompactPollBody.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyCompactPollResponse.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyDeletedMessagesResponse.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyDeletion.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyGetInfoResponse.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyMemberCountResponse.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyModeratorsResponse.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyOpenGroupMessageV2.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyPublicKeyBody.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyRoomInfo.swift delete mode 100644 SessionMessagingKit/Open Groups/Models/LegacyRoomsResponse.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index 11742491b..95257a5c4 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -807,23 +807,11 @@ FDC4380927B31D4E00C60D73 /* SOGSError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4380827B31D4E00C60D73 /* SOGSError.swift */; }; FDC4381527B329CE00C60D73 /* NonceGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381427B329CE00C60D73 /* NonceGenerator.swift */; }; FDC4381727B32EC700C60D73 /* Personalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381627B32EC700C60D73 /* Personalization.swift */; }; - FDC4381A27B34EBA00C60D73 /* LegacyCompactPollBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381927B34EBA00C60D73 /* LegacyCompactPollBody.swift */; }; - FDC4381C27B354AC00C60D73 /* LegacyPublicKeyBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381B27B354AC00C60D73 /* LegacyPublicKeyBody.swift */; }; FDC4382027B36ADC00C60D73 /* SOGSEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381F27B36ADC00C60D73 /* SOGSEndpoint.swift */; }; - FDC4382627B37F6900C60D73 /* LegacyDeletedMessagesResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382527B37F6900C60D73 /* LegacyDeletedMessagesResponse.swift */; }; - FDC4382827B37FD300C60D73 /* LegacyModeratorsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382727B37FD300C60D73 /* LegacyModeratorsResponse.swift */; }; - FDC4382A27B3802D00C60D73 /* LegacyRoomsResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382927B3802D00C60D73 /* LegacyRoomsResponse.swift */; }; - FDC4382C27B380E300C60D73 /* LegacyMemberCountResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382B27B380E300C60D73 /* LegacyMemberCountResponse.swift */; }; FDC4382F27B383AF00C60D73 /* UnregisterResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382E27B383AF00C60D73 /* UnregisterResponse.swift */; }; FDC4383127B3841C00C60D73 /* RegisterResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383027B3841C00C60D73 /* RegisterResponse.swift */; }; FDC4383827B3863200C60D73 /* VersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383727B3863200C60D73 /* VersionResponse.swift */; }; - FDC4383A27B4696200C60D73 /* LegacyAuthTokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383927B4696200C60D73 /* LegacyAuthTokenResponse.swift */; }; FDC4383E27B4708600C60D73 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383D27B4708600C60D73 /* Atomic.swift */; }; - FDC4384027B4746D00C60D73 /* LegacyGetInfoResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383F27B4746D00C60D73 /* LegacyGetInfoResponse.swift */; }; - FDC4384727B47F4D00C60D73 /* LegacyOpenGroupMessageV2.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384327B47F4D00C60D73 /* LegacyOpenGroupMessageV2.swift */; }; - FDC4384827B47F4D00C60D73 /* LegacyRoomInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384427B47F4D00C60D73 /* LegacyRoomInfo.swift */; }; - FDC4384927B47F4D00C60D73 /* LegacyCompactPollResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384527B47F4D00C60D73 /* LegacyCompactPollResponse.swift */; }; - FDC4384A27B47F4D00C60D73 /* LegacyDeletion.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384627B47F4D00C60D73 /* LegacyDeletion.swift */; }; FDC4384C27B47F7700C60D73 /* OpenGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384B27B47F7700C60D73 /* OpenGroup.swift */; }; FDC4384F27B4804F00C60D73 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4384E27B4804F00C60D73 /* Header.swift */; }; FDC4385127B4807400C60D73 /* QueryParam.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385027B4807400C60D73 /* QueryParam.swift */; }; @@ -1960,23 +1948,11 @@ FDC4380827B31D4E00C60D73 /* SOGSError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOGSError.swift; sourceTree = ""; }; FDC4381427B329CE00C60D73 /* NonceGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonceGenerator.swift; sourceTree = ""; }; FDC4381627B32EC700C60D73 /* Personalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Personalization.swift; sourceTree = ""; }; - FDC4381927B34EBA00C60D73 /* LegacyCompactPollBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyCompactPollBody.swift; sourceTree = ""; }; - FDC4381B27B354AC00C60D73 /* LegacyPublicKeyBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyPublicKeyBody.swift; sourceTree = ""; }; FDC4381F27B36ADC00C60D73 /* SOGSEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOGSEndpoint.swift; sourceTree = ""; }; - FDC4382527B37F6900C60D73 /* LegacyDeletedMessagesResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyDeletedMessagesResponse.swift; sourceTree = ""; }; - FDC4382727B37FD300C60D73 /* LegacyModeratorsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyModeratorsResponse.swift; sourceTree = ""; }; - FDC4382927B3802D00C60D73 /* LegacyRoomsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyRoomsResponse.swift; sourceTree = ""; }; - FDC4382B27B380E300C60D73 /* LegacyMemberCountResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyMemberCountResponse.swift; sourceTree = ""; }; FDC4382E27B383AF00C60D73 /* UnregisterResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnregisterResponse.swift; sourceTree = ""; }; FDC4383027B3841C00C60D73 /* RegisterResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterResponse.swift; sourceTree = ""; }; FDC4383727B3863200C60D73 /* VersionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = ""; }; - FDC4383927B4696200C60D73 /* LegacyAuthTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyAuthTokenResponse.swift; sourceTree = ""; }; FDC4383D27B4708600C60D73 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; - FDC4383F27B4746D00C60D73 /* LegacyGetInfoResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyGetInfoResponse.swift; sourceTree = ""; }; - FDC4384327B47F4D00C60D73 /* LegacyOpenGroupMessageV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyOpenGroupMessageV2.swift; sourceTree = ""; }; - FDC4384427B47F4D00C60D73 /* LegacyRoomInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyRoomInfo.swift; sourceTree = ""; }; - FDC4384527B47F4D00C60D73 /* LegacyCompactPollResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyCompactPollResponse.swift; sourceTree = ""; }; - FDC4384627B47F4D00C60D73 /* LegacyDeletion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyDeletion.swift; sourceTree = ""; }; FDC4384B27B47F7700C60D73 /* OpenGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroup.swift; sourceTree = ""; }; FDC4384E27B4804F00C60D73 /* Header.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Header.swift; sourceTree = ""; }; FDC4385027B4807400C60D73 /* QueryParam.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryParam.swift; sourceTree = ""; }; @@ -3948,18 +3924,6 @@ FDC438A927BB12BB00C60D73 /* UserModeratorRequest.swift */, FDC438AB27BB145200C60D73 /* UserDeleteMessagesRequest.swift */, FDC438AD27BB148700C60D73 /* UserDeleteMessagesResponse.swift */, - FDC4381B27B354AC00C60D73 /* LegacyPublicKeyBody.swift */, - FDC4383927B4696200C60D73 /* LegacyAuthTokenResponse.swift */, - FDC4381927B34EBA00C60D73 /* LegacyCompactPollBody.swift */, - FDC4384527B47F4D00C60D73 /* LegacyCompactPollResponse.swift */, - FDC4383F27B4746D00C60D73 /* LegacyGetInfoResponse.swift */, - FDC4382927B3802D00C60D73 /* LegacyRoomsResponse.swift */, - FDC4384427B47F4D00C60D73 /* LegacyRoomInfo.swift */, - FDC4382B27B380E300C60D73 /* LegacyMemberCountResponse.swift */, - FDC4382727B37FD300C60D73 /* LegacyModeratorsResponse.swift */, - FDC4382527B37F6900C60D73 /* LegacyDeletedMessagesResponse.swift */, - FDC4384627B47F4D00C60D73 /* LegacyDeletion.swift */, - FDC4384327B47F4D00C60D73 /* LegacyOpenGroupMessageV2.swift */, ); path = Models; sourceTree = ""; @@ -5256,7 +5220,6 @@ buildActionMask = 2147483647; files = ( B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */, - FDC4382A27B3802D00C60D73 /* LegacyRoomsResponse.swift in Sources */, C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */, C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */, C3A3A156256E1B91004D228D /* ProtoUtils.m in Sources */, @@ -5273,7 +5236,6 @@ FDC4385F27B4C4A200C60D73 /* PinnedMessage.swift in Sources */, C32A026325A801AA000ED5D4 /* NSData+messagePadding.m in Sources */, FD859EF227BF6BA200510D0C /* Data+Utilities.swift in Sources */, - FDC4384927B47F4D00C60D73 /* LegacyCompactPollResponse.swift in Sources */, C352A3932557883D00338F3E /* JobDelegate.swift in Sources */, C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */, FDC4386527B4DE7600C60D73 /* RoomPollInfo.swift in Sources */, @@ -5283,7 +5245,6 @@ C3D9E3BF25676AD70040E4F3 /* TSAttachmentStream.m in Sources */, C3C2A7562553A3AB00C340D1 /* VisibleMessage+Quote.swift in Sources */, B8B32021258B1A650020074B /* Contact.swift in Sources */, - FDC4384027B4746D00C60D73 /* LegacyGetInfoResponse.swift in Sources */, C32C5C89256DD0D2003C73A2 /* Storage+Jobs.swift in Sources */, C300A5FC2554B0A000555489 /* MessageReceiver.swift in Sources */, FDC438AC27BB145200C60D73 /* UserDeleteMessagesRequest.swift in Sources */, @@ -5298,7 +5259,6 @@ FDC4386727B4E10E00C60D73 /* Capabilities.swift in Sources */, C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */, C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */, - FDC4381A27B34EBA00C60D73 /* LegacyCompactPollBody.swift in Sources */, B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */, C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */, C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */, @@ -5323,13 +5283,10 @@ B8F5F60325EDE16F003BF8D4 /* DataExtractionNotification.swift in Sources */, C32C5D24256DD4C0003C73A2 /* MentionsManager.swift in Sources */, C3A71D1E25589AC30043A11F /* WebSocketProto.swift in Sources */, - FDC4384A27B47F4D00C60D73 /* LegacyDeletion.swift in Sources */, C3C2A7852553AAF300C340D1 /* SessionProtos.pb.swift in Sources */, B8566C63256F55930045A0B9 /* OWSLinkPreview+Conversion.swift in Sources */, - FDC4382827B37FD300C60D73 /* LegacyModeratorsResponse.swift in Sources */, C32C5B3F256DC1DF003C73A2 /* TSQuotedMessage+Conversion.swift in Sources */, B8EB20EE2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift in Sources */, - FDC4381C27B354AC00C60D73 /* LegacyPublicKeyBody.swift in Sources */, FDC4382F27B383AF00C60D73 /* UnregisterResponse.swift in Sources */, FDC4386327B4D94E00C60D73 /* SOGSMessage.swift in Sources */, C3C2A7712553A41E00C340D1 /* ControlMessage.swift in Sources */, @@ -5344,7 +5301,6 @@ C32C5D9C256DD6DC003C73A2 /* OWSOutgoingReceiptManager.m in Sources */, B8AE760B25ABFB5A001A84D2 /* GeneralUtilities.m in Sources */, C32C5C4F256DCC36003C73A2 /* Storage+OpenGroups.swift in Sources */, - FDC4384727B47F4D00C60D73 /* LegacyOpenGroupMessageV2.swift in Sources */, FDC4384F27B4804F00C60D73 /* Header.swift in Sources */, C3DA9C0725AE7396008F7C7E /* ConfigurationMessage.swift in Sources */, B8856CEE256F1054001CE70E /* OWSAudioPlayer.m in Sources */, @@ -5355,7 +5311,6 @@ FDC4381527B329CE00C60D73 /* NonceGenerator.swift in Sources */, C3BBE0762554CDA60050F1E3 /* Configuration.swift in Sources */, C35D76DB26606304009AA5FB /* ThreadUpdateBatcher.swift in Sources */, - FDC4382C27B380E300C60D73 /* LegacyMemberCountResponse.swift in Sources */, B8B32033258B235D0020074B /* Storage+Contacts.swift in Sources */, B8856D69256F141F001CE70E /* OWSWindowManager.m in Sources */, FD83B9AA27CF149D005E1583 /* ContactUtilities.swift in Sources */, @@ -5376,7 +5331,6 @@ C32C5BEF256DC8EE003C73A2 /* OWSDisappearingMessagesJob.m in Sources */, C34A977425A3E34A00852C71 /* ClosedGroupControlMessage.swift in Sources */, FDC4384C27B47F7700C60D73 /* OpenGroup.swift in Sources */, - FDC4382627B37F6900C60D73 /* LegacyDeletedMessagesResponse.swift in Sources */, B88FA7B826045D100049422F /* OpenGroupAPI.swift in Sources */, C32C5E97256DE0CB003C73A2 /* OWSPrimaryStorage.m in Sources */, FDC438C927BB706500C60D73 /* SendDirectMessageRequest.swift in Sources */, @@ -5385,7 +5339,6 @@ B8856E94256F1C37001CE70E /* OWSSounds.m in Sources */, C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */, C3A3A0EC256E1949004D228D /* OWSRecipientIdentity.m in Sources */, - FDC4383A27B4696200C60D73 /* LegacyAuthTokenResponse.swift in Sources */, B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */, C32C5AB2256DBE8F003C73A2 /* TSMessage.m in Sources */, C3A3A0FE256E1A3C004D228D /* TSDatabaseSecondaryIndexes.m in Sources */, @@ -5397,7 +5350,6 @@ B88A1AC725C90A4700E6D421 /* TypingIndicatorInteraction.swift in Sources */, C3D9E3C025676AD70040E4F3 /* TSAttachment.m in Sources */, FD83B9CE27D17A04005E1583 /* Request.swift in Sources */, - FDC4384827B47F4D00C60D73 /* LegacyRoomInfo.swift in Sources */, C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */, FDC438CB27BB7DB100C60D73 /* UpdateMessageRequest.swift in Sources */, C352A2FF25574B6300338F3E /* MessageSendJob.swift in Sources */, diff --git a/SessionMessagingKit/Database/Storage+Contacts.swift b/SessionMessagingKit/Database/Storage+Contacts.swift index 285285069..a6b1680f6 100644 --- a/SessionMessagingKit/Database/Storage+Contacts.swift +++ b/SessionMessagingKit/Database/Storage+Contacts.swift @@ -97,11 +97,11 @@ extension Storage { public func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> ()) { Storage.read { transaction in - self.enumerateBlindedIdMapping(with: block, transaction: transaction) + self.enumerateBlindedIdMapping(using: transaction, with: block) } } - public func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> (), transaction: YapDatabaseReadTransaction) { + public func enumerateBlindedIdMapping(using transaction: YapDatabaseReadTransaction, with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> ()) { transaction.enumerateRows(inCollection: Storage.blindedIdCacheCollection) { _, object, _, stop in guard let mapping = object as? BlindedIdMapping else { return } diff --git a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h index b4a0edb0e..c965ff51b 100644 --- a/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h +++ b/SessionMessagingKit/Messages/Signal/TSIncomingMessage.h @@ -85,7 +85,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) NSString *authorId; // convenience method for expiring a message which was just read -- (void)markAsReadNowWithSendReadReceipt:(BOOL)sendReadReceipt +- (void)markAsReadNowWithTrySendReadReceipt:(BOOL)trySendReadReceipt transaction:(YapDatabaseReadWriteTransaction *)transaction; - (void)setNotificationIdentifier:(NSString * _Nullable)notificationIdentifier diff --git a/SessionMessagingKit/Open Groups/Models/LegacyAuthTokenResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyAuthTokenResponse.swift deleted file mode 100644 index d15f21cc8..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyAuthTokenResponse.swift +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyAuthTokenResponse: Codable { - struct Challenge: Codable { - enum CodingKeys: String, CodingKey { - case ciphertext = "ciphertext" - case ephemeralPublicKey = "ephemeral_public_key" - } - - let ciphertext: Data - let ephemeralPublicKey: Data - } - - let challenge: Challenge - } -} - -// MARK: - Codable - -extension OpenGroupAPI.LegacyAuthTokenResponse.Challenge { - init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) - - let base64EncodedCiphertext: String = try container.decode(String.self, forKey: .ciphertext) - let base64EncodedEphemeralPublicKey: String = try container.decode(String.self, forKey: .ephemeralPublicKey) - - guard let ciphertext = Data(base64Encoded: base64EncodedCiphertext), let ephemeralPublicKey = Data(base64Encoded: base64EncodedEphemeralPublicKey) else { - throw HTTP.Error.parsingFailed - } - - self = OpenGroupAPI.LegacyAuthTokenResponse.Challenge( - ciphertext: ciphertext, - ephemeralPublicKey: ephemeralPublicKey - ) - } - - public func encode(to encoder: Encoder) throws { - var container: KeyedEncodingContainer = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(ciphertext.base64EncodedString(), forKey: .ciphertext) - try container.encode(ephemeralPublicKey.base64EncodedString(), forKey: .ephemeralPublicKey) - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyCompactPollBody.swift b/SessionMessagingKit/Open Groups/Models/LegacyCompactPollBody.swift deleted file mode 100644 index 70036c1e2..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyCompactPollBody.swift +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyCompactPollBody: Codable { - struct Room: Codable { - enum CodingKeys: String, CodingKey { - case id = "room_id" - case fromMessageServerId = "from_message_server_id" - case fromDeletionServerId = "from_deletion_server_id" - - // TODO: Remove this legacy value - case legacyAuthToken = "auth_token" - } - - let id: String - let fromMessageServerId: Int64? - let fromDeletionServerId: Int64? - - // TODO: This is a legacy value - let legacyAuthToken: String? - } - - let requests: [Room] - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyCompactPollResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyCompactPollResponse.swift deleted file mode 100644 index f699b3206..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyCompactPollResponse.swift +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - public struct LegacyCompactPollResponse: Codable { - public struct Result: Codable { - enum CodingKeys: String, CodingKey { - case room = "room_id" - case statusCode = "status_code" - case messages - case deletions - case moderators - } - - public let room: String - public let statusCode: UInt - public let messages: [LegacyOpenGroupMessageV2]? - public let deletions: [LegacyDeletion]? - public let moderators: [String]? - } - - public let results: [Result] - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyDeletedMessagesResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyDeletedMessagesResponse.swift deleted file mode 100644 index f063cc08c..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyDeletedMessagesResponse.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyDeletedMessagesResponse: Codable { - enum CodingKeys: String, CodingKey { - case deletions = "ids" - } - - let deletions: [LegacyDeletion] - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyDeletion.swift b/SessionMessagingKit/Open Groups/Models/LegacyDeletion.swift deleted file mode 100644 index 03fc1ae0a..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyDeletion.swift +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - public struct LegacyDeletion: Codable { - enum CodingKeys: String, CodingKey { - case id - case deletedMessageID = "deleted_message_id" - } - - let id: Int64 - let deletedMessageID: Int64 - - public static func from(_ json: JSON) -> LegacyDeletion? { - guard let id = json["id"] as? Int64, let deletedMessageID = json["deleted_message_id"] as? Int64 else { - return nil - } - - return LegacyDeletion(id: id, deletedMessageID: deletedMessageID) - } - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyGetInfoResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyGetInfoResponse.swift deleted file mode 100644 index b3e4317f3..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyGetInfoResponse.swift +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyGetInfoResponse: Codable { - let room: LegacyRoomInfo - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyMemberCountResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyMemberCountResponse.swift deleted file mode 100644 index 1f7c13cfb..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyMemberCountResponse.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyMemberCountResponse: Codable { - enum CodingKeys: String, CodingKey { - case memberCount = "member_count" - } - - let memberCount: UInt64 - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyModeratorsResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyModeratorsResponse.swift deleted file mode 100644 index 4846a5faf..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyModeratorsResponse.swift +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyModeratorsResponse: Codable { - let moderators: [String] - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyOpenGroupMessageV2.swift b/SessionMessagingKit/Open Groups/Models/LegacyOpenGroupMessageV2.swift deleted file mode 100644 index 17b0d5565..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyOpenGroupMessageV2.swift +++ /dev/null @@ -1,71 +0,0 @@ -import Foundation -import SessionUtilitiesKit - -public struct LegacyOpenGroupMessageV2: Codable { - enum CodingKeys: String, CodingKey { - case serverID = "server_id" - case sender = "public_key" - case sentTimestamp = "timestamp" - case base64EncodedData = "data" - case base64EncodedSignature = "signature" - } - - public let serverID: Int64? - public let sender: String? - public let sentTimestamp: UInt64 - /// The serialized protobuf in base64 encoding. - public let base64EncodedData: String - /// When sending a message, the sender signs the serialized protobuf with their private key so that - /// a receiving user can verify that the message wasn't tampered with. - public let base64EncodedSignature: String? - - public func sign(with publicKey: String) -> LegacyOpenGroupMessageV2? { - guard let userKeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair() else { return nil } - guard let data = Data(base64Encoded: base64EncodedData) else { return nil } - guard let signature = try? Ed25519.sign(data, with: userKeyPair) else { - SNLog("Failed to sign open group message.") - return nil - } - - return LegacyOpenGroupMessageV2( - serverID: serverID, - sender: sender, - sentTimestamp: sentTimestamp, - base64EncodedData: base64EncodedData, - base64EncodedSignature: signature.base64EncodedString() - ) - } -} - -// MARK: - Decoder - -extension LegacyOpenGroupMessageV2 { - public init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) - - let sender: String = try container.decode(String.self, forKey: .sender) - let base64EncodedData: String = try container.decode(String.self, forKey: .base64EncodedData) - let base64EncodedSignature: String = try container.decode(String.self, forKey: .base64EncodedSignature) - - // Validate the message signature - guard let data = Data(base64Encoded: base64EncodedData), let signature = Data(base64Encoded: base64EncodedSignature) else { - throw HTTP.Error.parsingFailed - } - - let publicKey = Data(hex: sender.removingIdPrefixIfNeeded()) - let isValid = (try? Ed25519.verifySignature(signature, publicKey: publicKey, data: data)) ?? false - - guard isValid else { - SNLog("Ignoring message with invalid signature.") - throw HTTP.Error.parsingFailed - } - - self = LegacyOpenGroupMessageV2( - serverID: try? container.decode(Int64.self, forKey: .serverID), - sender: sender, - sentTimestamp: try container.decode(UInt64.self, forKey: .sentTimestamp), - base64EncodedData: base64EncodedData, - base64EncodedSignature: base64EncodedSignature - ) - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyPublicKeyBody.swift b/SessionMessagingKit/Open Groups/Models/LegacyPublicKeyBody.swift deleted file mode 100644 index 572bdbdbf..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyPublicKeyBody.swift +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyPublicKeyBody: Codable { - enum CodingKeys: String, CodingKey { - case publicKey = "public_key" - } - - let publicKey: String - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyRoomInfo.swift b/SessionMessagingKit/Open Groups/Models/LegacyRoomInfo.swift deleted file mode 100644 index bccd9ea93..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyRoomInfo.swift +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - public struct LegacyRoomInfo: Codable { - enum CodingKeys: String, CodingKey { - case id - case name - case imageID = "image_id" - } - - public let id: String - public let name: String - public let imageID: String? - } -} diff --git a/SessionMessagingKit/Open Groups/Models/LegacyRoomsResponse.swift b/SessionMessagingKit/Open Groups/Models/LegacyRoomsResponse.swift deleted file mode 100644 index 162e629fc..000000000 --- a/SessionMessagingKit/Open Groups/Models/LegacyRoomsResponse.swift +++ /dev/null @@ -1,9 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation - -extension OpenGroupAPI { - struct LegacyRoomsResponse: Codable { - let rooms: [LegacyRoomInfo] - } -} diff --git a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift index 8ac37bc7f..7ac3f7e94 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupAPI.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupAPI.swift @@ -1036,7 +1036,6 @@ public final class OpenGroupAPI: NSObject { return Promise(error: Error.signingFailed) } - // TODO: 'removeAuthToken' as a migration??? (would previously do this when getting a `401`) return dependencies.api.sendOnionRequest(signedRequest, to: request.server, with: publicKey) } @@ -1045,640 +1044,4 @@ public final class OpenGroupAPI: NSObject { preconditionFailure("It's currently not allowed to send non onion routed requests.") } - - // MARK: - - // MARK: - - // MARK: - Legacy Requests (To be removed) - // TODO: Remove the legacy requests (should be unused once we release - just here for testing) - - public static var legacyDefaultRoomsPromise: Promise<[LegacyRoomInfo]>? - - // MARK: -- Legacy Auth - - @available(*, deprecated, message: "Use request signing instead") - private static func legacyGetAuthToken(for room: String, on server: String) -> Promise { - let storage = SNMessagingKitConfiguration.shared.storage - - if let authToken: String = storage.getAuthToken(for: room, on: server) { - return Promise.value(authToken) - } - - if let authTokenPromise: Promise = legacyAuthTokenPromises.wrappedValue["\(server).\(room)"] { - return authTokenPromise - } - - let promise: Promise = legacyRequestNewAuthToken(for: room, on: server) - .then(on: OpenGroupAPI.workQueue) { legacyClaimAuthToken($0, for: room, on: server) } - .then(on: OpenGroupAPI.workQueue) { authToken -> Promise in - let (promise, seal) = Promise.pending() - storage.write(with: { transaction in - storage.setAuthToken(for: room, on: server, to: authToken, using: transaction) - }, completion: { - seal.fulfill(authToken) - }) - return promise - } - - promise - .done(on: OpenGroupAPI.workQueue) { _ in - legacyAuthTokenPromises.wrappedValue["\(server).\(room)"] = nil - } - .catch(on: OpenGroupAPI.workQueue) { _ in - legacyAuthTokenPromises.wrappedValue["\(server).\(room)"] = nil - } - - legacyAuthTokenPromises.wrappedValue["\(server).\(room)"] = promise - return promise - } - - @available(*, deprecated, message: "Use request signing instead") - public static func legacyRequestNewAuthToken(for room: String, on server: String) -> Promise { - SNLog("Requesting auth token for server: \(server).") - guard let userKeyPair: ECKeyPair = SNMessagingKitConfiguration.shared.storage.getUserKeyPair() else { - return Promise(error: Error.generic) - } - - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyAuthTokenChallenge(legacyAuth: true), - queryParameters: [ - .publicKey: getUserHexEncodedPublicKey() - ], - isAuthRequired: false - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response = try data.decoded(as: LegacyAuthTokenResponse.self, customError: Error.parsingFailed) - let symmetricKey = try AESGCM.generateSymmetricKey(x25519PublicKey: response.challenge.ephemeralPublicKey, x25519PrivateKey: userKeyPair.privateKey) - - guard let tokenAsData = try? AESGCM.decrypt(response.challenge.ciphertext, with: symmetricKey) else { - throw Error.decryptionFailed - } - - return tokenAsData.toHexString() - } - } - - @available(*, deprecated, message: "Use request signing instead") - public static func legacyClaimAuthToken(_ authToken: String, for room: String, on server: String) -> Promise { - let requestBody: LegacyPublicKeyBody = LegacyPublicKeyBody(publicKey: getUserHexEncodedPublicKey()) - - guard let body: Data = try? JSONEncoder().encode(requestBody) else { - return Promise(error: HTTP.Error.invalidJSON) - } - - let request: Request = Request( - method: .post, - server: server, - room: room, - endpoint: .legacyAuthTokenClaim(legacyAuth: true), - headers: [ - // Set explicitly here because is isn't in the database yet at this point - .authorization: authToken - ], - body: body, - isAuthRequired: false - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in authToken } - } - - /// Should be called when leaving a group. - @available(*, deprecated, message: "Use request signing instead") - public static func legacyDeleteAuthToken(for room: String, on server: String) -> Promise { - let request: Request = Request( - method: .delete, - server: server, - room: room, - endpoint: .legacyAuthToken(legacyAuth: true) - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in - let storage = SNMessagingKitConfiguration.shared.storage - - storage.write { transaction in - storage.removeAuthToken(for: room, on: server, using: transaction) - } - } - } - - // MARK: -- Legacy Requests - - @available(*, deprecated, message: "Use poll or batch instead") - public static func legacyCompactPoll(_ server: String) -> Promise { - let storage: SessionMessagingKitStorageProtocol = SNMessagingKitConfiguration.shared.storage - let rooms: [String] = storage.getAllOpenGroups().values - .filter { $0.server == server } - .map { $0.room } - var getAuthTokenPromises: [String: Promise] = [:] - let useMessageLimit = (hasPerformedInitialPoll[server] != true && timeSinceLastOpen > OpenGroupAPI.Poller.maxInactivityPeriod) - - hasPerformedInitialPoll[server] = true - - if !legacyHasUpdatedLastOpenDate { - UserDefaults.standard[.lastOpen] = Date() - legacyHasUpdatedLastOpenDate = true - } - - for room in rooms { - getAuthTokenPromises[room] = legacyGetAuthToken(for: room, on: server) - } - - let requestBody: LegacyCompactPollBody = LegacyCompactPollBody( - requests: rooms - .map { roomId -> LegacyCompactPollBody.Room in - LegacyCompactPollBody.Room( - id: roomId, - fromMessageServerId: (useMessageLimit ? nil : - storage.getLastMessageServerID(for: roomId, on: server) - ), - fromDeletionServerId: (useMessageLimit ? nil : - storage.getLastDeletionServerID(for: roomId, on: server) - ), - legacyAuthToken: nil - ) - } - ) - - return when(fulfilled: [Promise](getAuthTokenPromises.values)) - .then(on: OpenGroupAPI.workQueue) { _ -> Promise in - let requestBodyWithAuthTokens: LegacyCompactPollBody = LegacyCompactPollBody( - requests: requestBody.requests.compactMap { oldRoom -> LegacyCompactPollBody.Room? in - guard let authToken: String = getAuthTokenPromises[oldRoom.id]?.value else { return nil } - - return LegacyCompactPollBody.Room( - id: oldRoom.id, - fromMessageServerId: oldRoom.fromMessageServerId, - fromDeletionServerId: oldRoom.fromDeletionServerId, - legacyAuthToken: authToken - ) - } - ) - - guard let body: Data = try? JSONEncoder().encode(requestBodyWithAuthTokens) else { - return Promise(error: HTTP.Error.invalidJSON) - } - - let request = Request( - method: .post, - server: server, - endpoint: .legacyCompactPoll(legacyAuth: true), - body: body, - isAuthRequired: false - ) - - return legacySend(request) - .then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyCompactPollResponse = try data.decoded(as: LegacyCompactPollResponse.self, customError: Error.parsingFailed) - - return when( - fulfilled: response.results - .compactMap { (result: LegacyCompactPollResponse.Result) -> Promise<[LegacyDeletion]>? in - // A 401 means that we didn't provide a (valid) auth token for a route that - // required one. We use this as an indication that the token we're using has - // expired. Note that a 403 has a different meaning; it means that we provided - // a valid token but it doesn't have a high enough permission level for the - // route in question. - guard result.statusCode != 401 else { - storage.writeSync { transaction in - storage.removeAuthToken(for: result.room, on: server, using: transaction) - } - - return nil - } - - return legacyProcess(messages: result.messages, for: result.room, on: server) - .then(on: OpenGroupAPI.workQueue) { _ -> Promise<[LegacyDeletion]> in - legacyProcess(deletions: result.deletions, for: result.room, on: server) - } - } - ).then(on: OpenGroupAPI.workQueue) { _ in Promise.value(response) } - } - } - } - - @available(*, deprecated, message: "Use getDefaultRoomsIfNeeded instead") - public static func legacyGetDefaultRoomsIfNeeded() { - Storage.shared.write( - with: { transaction in - Storage.shared.setOpenGroupPublicKey(for: defaultServer, to: defaultServerPublicKey, using: transaction) - }, - completion: { - let promise = attempt(maxRetryCount: 8, recoveringOn: DispatchQueue.main) { - OpenGroupAPI.legacyGetAllRooms(from: defaultServer) - } - _ = promise.done(on: OpenGroupAPI.workQueue) { items in - items.forEach { legacyGetGroupImage(for: $0.id, on: defaultServer).retainUntilComplete() } - } - promise.catch(on: OpenGroupAPI.workQueue) { _ in - OpenGroupAPI.legacyDefaultRoomsPromise = nil - } - legacyDefaultRoomsPromise = promise - } - ) - } - - @available(*, deprecated, message: "Use rooms(for:) instead") - public static func legacyGetAllRooms(from server: String) -> Promise<[LegacyRoomInfo]> { - let request: Request = Request( - server: server, - endpoint: .legacyRooms, - isAuthRequired: false - ) - - return legacySend(request) - .map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyRoomsResponse = try data.decoded(as: LegacyRoomsResponse.self, customError: Error.parsingFailed) - - return response.rooms - } - } - - @available(*, deprecated, message: "Use room(for:on:) instead") - public static func legacyGetRoomInfo(for room: String, on server: String) -> Promise { - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyRoomInfo(room), - isAuthRequired: false - ) - - return legacySend(request) - .map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyGetInfoResponse = try data.decoded(as: LegacyGetInfoResponse.self, customError: Error.parsingFailed) - - return response.room - } - } - - @available(*, deprecated, message: "Use roomImage(_:for:on:) instead") - public static func legacyGetGroupImage(for room: String, on server: String) -> Promise { - // Normally the image for a given group is stored with the group thread, so it's only - // fetched once. However, on the join open group screen we show images for groups the - // user * hasn't * joined yet. We don't want to re-fetch these images every time the - // user opens the app because that could slow the app down or be data-intensive. So - // instead we assume that these images don't change that often and just fetch them once - // a week. We also assume that they're all fetched at the same time as well, so that - // we only need to maintain one date in user defaults. On top of all of this we also - // don't double up on fetch requests by storing the existing request as a promise if - // there is one. - let lastOpenGroupImageUpdate: Date? = UserDefaults.standard[.lastOpenGroupImageUpdate] - let now: Date = Date() - let timeSinceLastUpdate: TimeInterval = (given(lastOpenGroupImageUpdate) { now.timeIntervalSince($0) } ?? .greatestFiniteMagnitude) - let updateInterval: TimeInterval = (7 * 24 * 60 * 60) - - if let data = Storage.shared.getOpenGroupImage(for: room, on: server), server == defaultServer, timeSinceLastUpdate < updateInterval { - return Promise.value(data) - } - - if let promise = legacyGroupImagePromises["\(server).\(room)"] { - return promise - } - - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyRoomImage(room), - isAuthRequired: false - ) - - let promise: Promise = legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyFileDownloadResponse = try data.decoded(as: LegacyFileDownloadResponse.self, customError: Error.parsingFailed) - - if server == defaultServer { - Storage.shared.write { transaction in - Storage.shared.setOpenGroupImage(to: response.data, for: room, on: server, using: transaction) - } - UserDefaults.standard[.lastOpenGroupImageUpdate] = now - } - - return response.data - } - legacyGroupImagePromises["\(server).\(room)"] = promise - - return promise - } - - @available(*, deprecated, message: "Use room(for:on:) instead") - public static func legacyGetMemberCount(for room: String, on server: String) -> Promise { - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyMemberCount(legacyAuth: true) - ) - - return legacySend(request) - .map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyMemberCountResponse = try data.decoded(as: LegacyMemberCountResponse.self, customError: Error.parsingFailed) - - let storage = SNMessagingKitConfiguration.shared.storage - storage.write { transaction in - storage.setUserCount(to: response.memberCount, forOpenGroupWithID: "\(server).\(room)", using: transaction) - } - - return response.memberCount - } - } - - // MARK: - Legacy File Storage - - @available(*, deprecated, message: "Use uploadFile(_:fileName:to:on:) instead") - public static func legacyUpload(_ file: Data, to room: String, on server: String) -> Promise { - let requestBody: FileUploadBody = FileUploadBody(file: file.base64EncodedString()) - - guard let body: Data = try? JSONEncoder().encode(requestBody) else { - return Promise(error: HTTP.Error.invalidJSON) - } - - let request = Request(method: .post, server: server, room: room, endpoint: .legacyFiles, body: body) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyFileUploadResponse = try data.decoded(as: LegacyFileUploadResponse.self, customError: Error.parsingFailed) - - return response.fileId - } - } - - @available(*, deprecated, message: "Use downloadFile(_:from:on:) instead") - public static func legacyDownload(_ file: UInt64, from room: String, on server: String) -> Promise { - let request = Request(server: server, room: room, endpoint: .legacyFile(file)) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyFileDownloadResponse = try data.decoded(as: LegacyFileDownloadResponse.self, customError: Error.parsingFailed) - - return response.data - } - } - - // MARK: - Legacy Message Sending & Receiving - - @available(*, deprecated, message: "Use send(_:to:on:whisperTo:whisperMods:with:) instead") - public static func legacySend(_ message: LegacyOpenGroupMessageV2, to room: String, on server: String, with publicKey: String) -> Promise { - guard let signedMessage = message.sign(with: publicKey) else { return Promise(error: Error.signingFailed) } - guard let body: Data = try? JSONEncoder().encode(signedMessage) else { - return Promise(error: Error.parsingFailed) - } - let request = Request(method: .post, server: server, room: room, endpoint: .legacyMessages, body: body) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let message: LegacyOpenGroupMessageV2 = try data.decoded(as: LegacyOpenGroupMessageV2.self, customError: Error.parsingFailed) - Storage.shared.write { transaction in - Storage.shared.addReceivedMessageTimestamp(message.sentTimestamp, using: transaction) - } - return message - } - } - - @available(*, deprecated, message: "Use recentMessages(in:on:) or messagesSince(seqNo:in:on:) instead") - public static func legacyGetMessages(for room: String, on server: String) -> Promise<[LegacyOpenGroupMessageV2]> { - let storage = SNMessagingKitConfiguration.shared.storage - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyMessages, - queryParameters: [ - .fromServerId: storage.getLastMessageServerID(for: room, on: server).map { String($0) } - ].compactMapValues { $0 } - ) - - return legacySend(request).then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise<[LegacyOpenGroupMessageV2]> in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let messages: [LegacyOpenGroupMessageV2] = try data.decoded(as: [LegacyOpenGroupMessageV2].self, customError: Error.parsingFailed) - - return legacyProcess(messages: messages, for: room, on: server) - } - } - - // MARK: - Legacy Message Deletion - - // TODO: No delete method????. - @available(*, deprecated, message: "Use v4 endpoint instead") - public static func legacyDeleteMessage(with serverID: Int64, from room: String, on server: String) -> Promise { - let request: Request = Request( - method: .delete, - server: server, - room: room, - endpoint: .legacyMessagesForServer(serverID) - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in } - } - - @available(*, deprecated, message: "Use v4 endpoint instead") - public static func legacyGetDeletedMessages(for room: String, on server: String) -> Promise<[LegacyDeletion]> { - let storage = SNMessagingKitConfiguration.shared.storage - - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyDeletedMessages, - queryParameters: [ - .fromServerId: storage.getLastDeletionServerID(for: room, on: server).map { String($0) } - ].compactMapValues { $0 } - ) - - return legacySend(request).then(on: OpenGroupAPI.workQueue) { _, maybeData -> Promise<[LegacyDeletion]> in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyDeletedMessagesResponse = try data.decoded(as: LegacyDeletedMessagesResponse.self, customError: Error.parsingFailed) - - return legacyProcess(deletions: response.deletions, for: room, on: server) - } - } - - // MARK: - Legacy Moderation - - @available(*, deprecated, message: "Use v4 endpoint instead") - public static func legacyGetModerators(for room: String, on server: String) -> Promise<[String]> { - let request: Request = Request( - server: server, - room: room, - endpoint: .legacyModerators - ) - - return legacySend(request) - .map(on: OpenGroupAPI.workQueue) { _, maybeData in - guard let data: Data = maybeData else { throw Error.parsingFailed } - let response: LegacyModeratorsResponse = try data.decoded(as: LegacyModeratorsResponse.self, customError: Error.parsingFailed) - - if var x = self.moderators[server] { - x[room] = Set(response.moderators) - self.moderators[server] = x - } - else { - self.moderators[server] = [room: Set(response.moderators)] - } - - return response.moderators - } - } - - @available(*, deprecated, message: "Use v4 endpoint instead") - public static func legacyBan(_ publicKey: String, from room: String, on server: String) -> Promise { - let requestBody: LegacyPublicKeyBody = LegacyPublicKeyBody(publicKey: getUserHexEncodedPublicKey()) - - guard let body: Data = try? JSONEncoder().encode(requestBody) else { - return Promise(error: HTTP.Error.invalidJSON) - } - - let request: Request = Request( - method: .post, - server: server, - room: room, - endpoint: .legacyBlockList, - body: body - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in } - } - - @available(*, deprecated, message: "Use v4 endpoint instead") - public static func legacyBanAndDeleteAllMessages(_ publicKey: String, from room: String, on server: String) -> Promise { - let requestBody: LegacyPublicKeyBody = LegacyPublicKeyBody(publicKey: getUserHexEncodedPublicKey()) - - guard let body: Data = try? JSONEncoder().encode(requestBody) else { - return Promise(error: HTTP.Error.invalidJSON) - } - - let request: Request = Request( - method: .post, - server: server, - room: room, - endpoint: .legacyBanAndDeleteAll, - body: body - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in } - } - - @available(*, deprecated, message: "Use v4 endpoint instead") - public static func legacyUnban(_ publicKey: String, from room: String, on server: String) -> Promise { - let request: Request = Request( - method: .delete, - server: server, - room: room, - endpoint: .legacyBlockListIndividual(publicKey) - ) - - return legacySend(request).map(on: OpenGroupAPI.workQueue) { _ in } - } - - // MARK: - Processing - // TODO: Move these methods to the OpenGroupManager? (seems odd for them to be in the API) - - @available(*, deprecated, message: "Use v4 endpoint instead") - private static func legacyProcess(messages: [LegacyOpenGroupMessageV2]?, for room: String, on server: String) -> Promise<[LegacyOpenGroupMessageV2]> { - guard let messages: [LegacyOpenGroupMessageV2] = messages, !messages.isEmpty else { return Promise.value([]) } - - let storage = SNMessagingKitConfiguration.shared.storage - let serverID: Int64 = (messages.compactMap { $0.serverID }.max() ?? 0) - let lastMessageServerID: Int64 = (storage.getLastMessageServerID(for: room, on: server) ?? 0) - - if serverID > lastMessageServerID { - let (promise, seal) = Promise<[LegacyOpenGroupMessageV2]>.pending() - - storage.write( - with: { transaction in - storage.setLastMessageServerID(for: room, on: server, to: serverID, using: transaction) - }, - completion: { - seal.fulfill(messages) - } - ) - - return promise - } - - return Promise.value(messages) - } - - @available(*, deprecated, message: "Use v4 endpoint instead") - private static func legacyProcess(deletions: [LegacyDeletion]?, for room: String, on server: String) -> Promise<[LegacyDeletion]> { - guard let deletions: [LegacyDeletion] = deletions else { return Promise.value([]) } - - let storage = SNMessagingKitConfiguration.shared.storage - let serverID: Int64 = (deletions.compactMap { $0.id }.max() ?? 0) - let lastDeletionServerID: Int64 = (storage.getLastDeletionServerID(for: room, on: server) ?? 0) - - if serverID > lastDeletionServerID { - let (promise, seal) = Promise<[LegacyDeletion]>.pending() - - storage.write( - with: { transaction in - storage.setLastDeletionServerID(for: room, on: server, to: serverID, using: transaction) - }, - completion: { - seal.fulfill(deletions) - } - ) - - return promise - } - - return Promise.value(deletions) - } - - // MARK: - Legacy Convenience - - @available(*, deprecated, message: "Use v4 endpoint instead") - private static func legacySend(_ request: Request, through api: OnionRequestAPIType.Type = OnionRequestAPI.self) -> Promise<(OnionRequestResponseInfoType, Data?)> { - guard let url: URL = request.url else { return Promise(error: Error.invalidURL) } - - var urlRequest: URLRequest = URLRequest(url: url) - urlRequest.httpMethod = request.method.rawValue - urlRequest.allHTTPHeaderFields = request.headers - .setting(.room, request.room) // TODO: Is this needed anymore? Add at the request level?. - .toHTTPHeaders() - urlRequest.httpBody = request.body - - if request.useOnionRouting { - guard let publicKey = SNMessagingKitConfiguration.shared.storage.getOpenGroupPublicKey(for: request.server) else { - return Promise(error: Error.noPublicKey) - } - - if request.isAuthRequired { - // Because legacy auth happens on a per-room basis, we need to have a room to - // make an authenticated request - guard let room = request.room else { - return api.sendOnionRequest(urlRequest, to: request.server, using: .v3, with: publicKey) - } - - return legacyGetAuthToken(for: room, on: request.server) - .then(on: OpenGroupAPI.workQueue) { authToken -> Promise<(OnionRequestResponseInfoType, Data?)> in - urlRequest.setValue(authToken, forHTTPHeaderField: Header.authorization.rawValue) - - let promise = api.sendOnionRequest(urlRequest, to: request.server, using: .v3, with: publicKey) - promise.catch(on: OpenGroupAPI.workQueue) { error in - // A 401 means that we didn't provide a (valid) auth token for a route - // that required one. We use this as an indication that the token we're - // using has expired. Note that a 403 has a different meaning; it means - // that we provided a valid token but it doesn't have a high enough - // permission level for the route in question. - if case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, _, _) = error, statusCode == 401 { - let storage = SNMessagingKitConfiguration.shared.storage - - storage.writeSync { transaction in - storage.removeAuthToken(for: room, on: request.server, using: transaction) - } - } - } - - return promise - } - } - - return api.sendOnionRequest(urlRequest, to: request.server, using: .v3, with: publicKey) - } - - preconditionFailure("It's currently not allowed to send non onion routed requests.") - } } diff --git a/SessionMessagingKit/Open Groups/OpenGroupManager.swift b/SessionMessagingKit/Open Groups/OpenGroupManager.swift index d23ae1edd..c128a6bc9 100644 --- a/SessionMessagingKit/Open Groups/OpenGroupManager.swift +++ b/SessionMessagingKit/Open Groups/OpenGroupManager.swift @@ -14,8 +14,12 @@ public final class OpenGroupManager: NSObject { public static var defaultRoomsPromise: Promise<[OpenGroupAPI.Room]>? private static var groupImagePromises: [String: Promise] = [:] - private static var moderators: [String: [String: Set]] = [:] // Server URL to room ID to set of moderator IDs - private static var admins: [String: [String: Set]] = [:] // Server URL to room ID to set of admin IDs + + /// Server URL to room ID to set of moderator IDs + private static var moderators: Atomic<[String: [String: Set]]> = Atomic([:]) + + /// Server URL to room ID to set of admin IDs + private static var admins: Atomic<[String: [String: Set]]> = Atomic([:]) // MARK: - Polling @@ -243,14 +247,16 @@ public final class OpenGroupManager: NSObject { // - Moderators if let moderators: [String] = (pollInfo.details?.moderators ?? maybeUpdatedModel?.groupModeratorIds) { - OpenGroupManager.moderators[server] = (OpenGroupManager.moderators[server] ?? [:]) - .setting(roomToken, Set(moderators)) + OpenGroupManager.moderators.mutate { + $0[server] = ($0[server] ?? [:]).setting(roomToken, Set(moderators)) + } } // - Admins if let admins: [String] = (pollInfo.details?.admins ?? maybeUpdatedModel?.groupAdminIds) { - OpenGroupManager.admins[server] = (OpenGroupManager.admins[server] ?? [:]) - .setting(roomToken, Set(admins)) + OpenGroupManager.admins.mutate { + $0[server] = ($0[server] ?? [:]).setting(roomToken, Set(admins)) + } } // - Room image (if there is one) @@ -357,7 +363,7 @@ public final class OpenGroupManager: NSObject { let sortedMessages: [OpenGroupAPI.DirectMessage] = messages .sorted { lhs, rhs in lhs.id < rhs.id } let latestMessageId: Int64 = (sortedMessages.last?.id ?? 0) - var mappingCache: [String: BlindedIdMapping] = [:] + var mappingCache: [String: BlindedIdMapping] = [:] // Only want this cache to exist for the current loop // Update the 'latestMessageId' value if fromOutbox { @@ -377,7 +383,7 @@ public final class OpenGroupManager: NSObject { // Note: The `posted` value is in seconds but all messages in the database use milliseconds for timestamps let envelope = SNProtoEnvelope.builder(type: .sessionMessage, timestamp: UInt64(floor(message.posted * 1000))) envelope.setContent(messageData) - envelope.setSource(message.sender) // TODO: Need to un-blind/intercept outbox messages? (their sender will be the blinded id) + envelope.setSource(message.sender) do { let data = try envelope.buildSerializedData() @@ -391,7 +397,6 @@ public final class OpenGroupManager: NSObject { using: transaction ) - // TODO: Need to test and validate this unblinding logic. // If the message was an outgoing message then attempt to unblind the recipient (this will help put // messages in the correct thread in case of message request approval race conditions as well as // during device sync'ing and restoration) @@ -399,11 +404,13 @@ public final class OpenGroupManager: NSObject { // Attempt to un-blind the 'message.recipient' let mapping: BlindedIdMapping - // Minor optimisation to avoid processing the same sender multiple times + // Minor optimisation to avoid processing the same sender multiple times in the same + // 'handleMessages' call (since the 'mapping' call is done within a transaction we + // will never have a mapping come through part-way through processing these messages) if let result: BlindedIdMapping = mappingCache[message.recipient] { mapping = result } - else if let result: BlindedIdMapping = ContactUtilities.mapping(for: message.recipient, serverPublicKey: serverPublicKey) { + else if let result: BlindedIdMapping = ContactUtilities.mapping(for: message.recipient, serverPublicKey: serverPublicKey, using: transaction) { mapping = result } else { @@ -426,6 +433,15 @@ public final class OpenGroupManager: NSObject { } try MessageReceiver.handle(receivedMessage, associatedWithProto: proto, openGroupID: nil, isBackgroundPoll: isBackgroundPoll, using: transaction) + + // If this message is from the outbox then we should add the open group details back to the + // thread just in case this is from a restore (otherwise the user won't be able to send a new + // message to the target inbox if they are still blinded) + if fromOutbox, let contactThread: TSContactThread = TSContactThread.fetch(uniqueId: TSContactThread.threadID(fromContactSessionID: message.recipient), transaction: transaction) { + contactThread.originalOpenGroupServer = server + contactThread.originalOpenGroupPublicKey = serverPublicKey + contactThread.save(with: transaction) + } } catch let error { SNLog("Couldn't receive inbox message due to error: \(error).") @@ -442,35 +458,51 @@ public final class OpenGroupManager: NSObject { } public static func isUserModeratorOrAdmin(_ publicKey: String, for room: String, on server: String, using dependencies: OpenGroupAPI.Dependencies = OpenGroupAPI.Dependencies()) -> Bool { - var targetKeys: [String] = [publicKey] - - // If we are checking for the current users public key then check for the blinded one as well - if publicKey == getUserHexEncodedPublicKey() { - guard let userEdKeyPair: Box.KeyPair = dependencies.storage.getUserED25519KeyPair() else { return false } - guard let serverPublicKey: String = dependencies.storage.getOpenGroupPublicKey(for: server) else { - return false - } - - // Add the unblinded key as an option - targetKeys.append(SessionId(.unblinded, publicKey: userEdKeyPair.publicKey).hexString) - - let server: OpenGroupAPI.Server? = dependencies.storage.getOpenGroupServer(name: server) - - // Check if the server supports blinded keys, if so then sign using the blinded key - if server?.capabilities.capabilities.contains(.blind) == true { + let modAndAdminKeys: Set = (OpenGroupManager.moderators.wrappedValue[server]?[room] ?? Set()) + .union(OpenGroupManager.admins.wrappedValue[server]?[room] ?? Set()) + + // If the publicKey is in the set then return immediately, otherwise only continue if it's the + // current user + guard !modAndAdminKeys.contains(publicKey) else { return true } + guard let sessionId: SessionId = SessionId(from: publicKey) else { return false } + + // Conveniently the logic for these different cases works in order so we can fallthrough each + // case with only minor efficiency losses + switch sessionId.prefix { + case .standard: + guard publicKey == getUserHexEncodedPublicKey() else { return false } + fallthrough + + case .unblinded: + guard let userEdKeyPair: Box.KeyPair = dependencies.storage.getUserED25519KeyPair() else { return false } + guard sessionId.prefix != .unblinded || publicKey == SessionId(.unblinded, publicKey: userEdKeyPair.publicKey).hexString else { + return false + } + fallthrough + + case .blinded: + guard let userEdKeyPair: Box.KeyPair = dependencies.storage.getUserED25519KeyPair() else { return false } + guard let serverPublicKey: String = dependencies.storage.getOpenGroupPublicKey(for: server) else { + return false + } guard let blindedKeyPair: Box.KeyPair = dependencies.sodium.blindedKeyPair(serverPublicKey: serverPublicKey, edKeyPair: userEdKeyPair, genericHash: dependencies.genericHash) else { return false } - - // Add the blinded key as an option - targetKeys.append(SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString) - } + guard sessionId.prefix != .blinded || publicKey == SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString else { + return false + } + + // If we got to here that means that the 'publicKey' value matches one of the current + // users 'standard', 'unblinded' or 'blinded' keys and as such we should check if any + // of them exist in the `modsAndAminKeys` Set + let possibleKeys: Set = Set([ + getUserHexEncodedPublicKey(), + SessionId(.unblinded, publicKey: userEdKeyPair.publicKey).hexString, + SessionId(.blinded, publicKey: blindedKeyPair.publicKey).hexString + ]) + + return !modAndAdminKeys.intersection(possibleKeys).isEmpty } - - return ( - (OpenGroupManager.moderators[server]?[room]?.contains(where: { key in targetKeys.contains(key) }) ?? false) || - (OpenGroupManager.admins[server]?[room]?.contains(where: { key in targetKeys.contains(key) }) ?? false) - ) } public static func getDefaultRoomsIfNeeded(using dependencies: OpenGroupAPI.Dependencies = OpenGroupAPI.Dependencies()) { diff --git a/SessionMessagingKit/Open Groups/Types/SOGSEndpoint.swift b/SessionMessagingKit/Open Groups/Types/SOGSEndpoint.swift index d664f682e..10c5088d3 100644 --- a/SessionMessagingKit/Open Groups/Types/SOGSEndpoint.swift +++ b/SessionMessagingKit/Open Groups/Types/SOGSEndpoint.swift @@ -53,31 +53,6 @@ extension OpenGroupAPI { case userModerator(String) case userDeleteMessages(String) - // Legacy endpoints (to be deprecated and removed) - - @available(*, deprecated, message: "Use v4 endpoint") case legacyFiles - @available(*, deprecated, message: "Use v4 endpoint") case legacyFile(UInt64) - - @available(*, deprecated, message: "Use v4 endpoint") case legacyMessages - @available(*, deprecated, message: "Use v4 endpoint") case legacyMessagesForServer(Int64) - @available(*, deprecated, message: "Use v4 endpoint") case legacyDeletedMessages - - @available(*, deprecated, message: "Use v4 endpoint") case legacyModerators - - @available(*, deprecated, message: "Use v4 endpoint") case legacyBlockList - @available(*, deprecated, message: "Use v4 endpoint") case legacyBlockListIndividual(String) - @available(*, deprecated, message: "Use v4 endpoint") case legacyBanAndDeleteAll - - @available(*, deprecated, message: "Use v4 endpoint") case legacyCompactPoll(legacyAuth: Bool) - @available(*, deprecated, message: "Use request signing") case legacyAuthToken(legacyAuth: Bool) - @available(*, deprecated, message: "Use request signing") case legacyAuthTokenChallenge(legacyAuth: Bool) - @available(*, deprecated, message: "Use request signing") case legacyAuthTokenClaim(legacyAuth: Bool) - - @available(*, deprecated, message: "Use v4 endpoint") case legacyRooms - @available(*, deprecated, message: "Use v4 endpoint") case legacyRoomInfo(String) - @available(*, deprecated, message: "Use v4 endpoint") case legacyRoomImage(String) - @available(*, deprecated, message: "Use v4 endpoint") case legacyMemberCount(legacyAuth: Bool) - var path: String { switch self { // Utility @@ -142,65 +117,6 @@ extension OpenGroupAPI { case .userPermission(let sessionId): return "user/\(sessionId)/permission" case .userModerator(let sessionId): return "user/\(sessionId)/moderator" case .userDeleteMessages(let sessionId): return "user/\(sessionId)/deleteMessages" - - // Legacy endpoints (to be deprecated and removed) - // TODO: Look for a nicer way to prepend 'legacy'? (OnionRequestAPI messes with this but the new auth needs it to be correct...) - - - case .legacyFiles: return "legacy/files" - case .legacyFile(let fileId): return "legacy/files/\(fileId)" - - case .legacyMessages: return "legacy/messages" - case .legacyMessagesForServer(let serverId): return "legacy/messages/\(serverId)" - case .legacyDeletedMessages: return "legacy/deleted_messages" - - case .legacyModerators: return "legacy/moderators" - - case .legacyBlockList: return "legacy/block_list" - case .legacyBlockListIndividual(let publicKey): return "legacy/block_list/\(publicKey)" - case .legacyBanAndDeleteAll: return "legacy/ban_and_delete_all" - - case .legacyCompactPoll(let useLegacyAuth): - return "\(useLegacyAuth ? "" : "legacy/")compact_poll" - - case .legacyAuthToken(let useLegacyAuth): - return "\(useLegacyAuth ? "" : "legacy/")auth_token" - - case .legacyAuthTokenChallenge(let useLegacyAuth): - return "\(useLegacyAuth ? "" : "legacy/")auth_token_challenge" - - case .legacyAuthTokenClaim(let useLegacyAuth): - return "\(useLegacyAuth ? "" : "legacy/")claim_auth_token" - - case .legacyRooms: return "legacy/rooms" - case .legacyRoomInfo(let roomName): return "legacy/rooms/\(roomName)" - case .legacyRoomImage(let roomName): return "legacy/rooms/\(roomName)/image" - - case .legacyMemberCount(let useLegacyAuth): - return "\(useLegacyAuth ? "" : "legacy/")member_count" - } - } - - var useLegacyAuth: Bool { - switch self { - // File upload/download should use legacy auth - case .legacyFiles, .legacyFile, .legacyMessages, - .legacyMessagesForServer, .legacyDeletedMessages, - .legacyModerators, .legacyBlockList, - .legacyBlockListIndividual, .legacyBanAndDeleteAll: - return true - - case .legacyCompactPoll(let useLegacyAuth), - .legacyAuthToken(let useLegacyAuth), - .legacyAuthTokenChallenge(let useLegacyAuth), - .legacyAuthTokenClaim(let useLegacyAuth), - .legacyMemberCount(let useLegacyAuth): - return useLegacyAuth - - case .legacyRooms, .legacyRoomInfo, .legacyRoomImage: - return true - - default: return false } } } diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 54a65d1a9..3e1c1b283 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -300,7 +300,7 @@ extension MessageReceiver { } if let messageToDelete = localMessage { if let incomingMessage = messageToDelete as? TSIncomingMessage { - incomingMessage.markAsReadNow(withSendReadReceipt: false, transaction: transaction) + incomingMessage.markAsReadNow(withTrySendReadReceipt: false, transaction: transaction) if let notificationIdentifier = incomingMessage.notificationIdentifier, !notificationIdentifier.isEmpty { UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [notificationIdentifier]) UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [notificationIdentifier]) diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift index 103491930..a742a9639 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPoller.swift @@ -66,19 +66,6 @@ extension OpenGroupAPI { self?.isPolling = false seal.fulfill(()) // The promise is just used to keep track of when we're done } - // OpenGroupAPI.compactPoll(server) - // OpenGroupAPI.legacyCompactPoll(server) - // .done(on: OpenGroupAPI.workQueue) { [weak self] response in - // guard let self = self else { return } - // self.isPolling = false - // response.results.forEach { self.handleCompactPollBody($0, isBackgroundPoll: isBackgroundPoll) } - // seal.fulfill(()) - // } - // .catch(on: OpenGroupAPI.workQueue) { error in - // SNLog("Open group polling failed due to error: \(error).") - // self.isPolling = false - // seal.fulfill(()) // The promise is just used to keep track of when we're done - // } return promise } @@ -160,58 +147,5 @@ extension OpenGroupAPI { } } } - - // MARK: - Legacy Handling - - private func handleCompactPollBody(_ body: OpenGroupAPI.LegacyCompactPollResponse.Result, isBackgroundPoll: Bool) { - let storage = SNMessagingKitConfiguration.shared.storage - // - Messages - // Sorting the messages by server ID before importing them fixes an issue where messages that quote older messages can't find those older messages - let openGroupID = "\(server).\(body.room)" - let messages = (body.messages ?? []).sorted { ($0.serverID ?? 0) < ($1.serverID ?? 0) } - - storage.write { transaction in - messages.forEach { message in - guard let data = Data(base64Encoded: message.base64EncodedData) else { - return SNLog("Ignoring open group message with invalid encoding.") - } - let envelope = SNProtoEnvelope.builder(type: .sessionMessage, timestamp: message.sentTimestamp) - envelope.setContent(data) - envelope.setSource(message.sender!) // Safe because messages with a nil sender are filtered out - do { - let data = try envelope.buildSerializedData() - let (message, proto) = try MessageReceiver.parse(data, openGroupMessageServerID: UInt64(message.serverID!), isRetry: false, using: transaction) - try MessageReceiver.handle(message, associatedWithProto: proto, openGroupID: openGroupID, isBackgroundPoll: isBackgroundPoll, using: transaction) - } catch { - SNLog("Couldn't receive open group message due to error: \(error).") - } - } - } - - // - Moderators - if var x = OpenGroupAPI.moderators[server] { - x[body.room] = Set(body.moderators ?? []) - OpenGroupAPI.moderators[server] = x - } - else { - OpenGroupAPI.moderators[server] = [ body.room : Set(body.moderators ?? []) ] - } - - // - Deletions - let deletedMessageServerIDs = Set((body.deletions ?? []).map { UInt64($0.deletedMessageID) }) - storage.write { transaction in - let transaction = transaction as! YapDatabaseReadWriteTransaction - guard let threadID = storage.getThreadID(for: openGroupID), - let thread = TSGroupThread.fetch(uniqueId: threadID, transaction: transaction) else { return } - var messagesToRemove: [TSMessage] = [] - - thread.enumerateInteractions(with: transaction) { interaction, stop in - guard let message = interaction as? TSMessage, deletedMessageServerIDs.contains(message.openGroupServerMessageID) else { return } - messagesToRemove.append(message) - } - - messagesToRemove.forEach { $0.remove(with: transaction) } - } - } } } diff --git a/SessionMessagingKit/Storage.swift b/SessionMessagingKit/Storage.swift index 92d3d12c9..3021827e5 100644 --- a/SessionMessagingKit/Storage.swift +++ b/SessionMessagingKit/Storage.swift @@ -28,7 +28,7 @@ public protocol SessionMessagingKitStorageProtocol { func cacheBlindedIdMapping(_ mapping: BlindedIdMapping) func cacheBlindedIdMapping(_ mapping: BlindedIdMapping, using transaction: YapDatabaseReadWriteTransaction) func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> ()) - func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> (), transaction: YapDatabaseReadTransaction) + func enumerateBlindedIdMapping(using transaction: YapDatabaseReadTransaction, with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> ()) // MARK: - Closed Groups diff --git a/SessionMessagingKit/Utilities/ContactUtilities.swift b/SessionMessagingKit/Utilities/ContactUtilities.swift index 25e4e3cda..12de6d358 100644 --- a/SessionMessagingKit/Utilities/ContactUtilities.swift +++ b/SessionMessagingKit/Utilities/ContactUtilities.swift @@ -39,39 +39,46 @@ public enum ContactUtilities { .map { $0.sessionID } } - public static func enumerateApprovedContactThreads(with block: @escaping (TSContactThread, Contact, UnsafeMutablePointer) -> ()) { - Storage.read { transaction in - TSContactThread.enumerateCollectionObjects(with: transaction) { object, stop in - guard let contactThread: TSContactThread = object as? TSContactThread else { return } - guard let contact: Contact = approvedContact(in: object, using: transaction) else { return } - - block(contactThread, contact, stop) - } + public static func enumerateApprovedContactThreads(using transaction: YapDatabaseReadTransaction, with block: @escaping (TSContactThread, Contact, UnsafeMutablePointer) -> ()) { + TSContactThread.enumerateCollectionObjects(with: transaction) { object, stop in + guard let contactThread: TSContactThread = object as? TSContactThread else { return } + guard let contact: Contact = approvedContact(in: object, using: transaction) else { return } + + block(contactThread, contact, stop) } } public static func mapping(for blindedId: String, serverPublicKey: String, using dependencies: OpenGroupAPI.Dependencies = OpenGroupAPI.Dependencies()) -> BlindedIdMapping? { - // TODO: Ensure the above case isn't going to be an issue due to legacy messages?. + var result: BlindedIdMapping? + + Storage.write { transaction in + result = ContactUtilities.mapping(for: blindedId, serverPublicKey: serverPublicKey, using: transaction, dependencies: dependencies) + } + + return result + } + + public static func mapping(for blindedId: String, serverPublicKey: String, using transaction: YapDatabaseReadWriteTransaction, dependencies: OpenGroupAPI.Dependencies = OpenGroupAPI.Dependencies()) -> BlindedIdMapping? { // Unfortunately the whole point of id-blinding is to make it hard to reverse-engineer a standard // sessionId, as a result in order to see if there is an unblinded contact for this blindedId we // can only really generate blinded ids for each contact and check if any match // // Due to this we have made a few optimisations to try and early-out as often as possible, first // we try to retrieve a direct cached mapping - var mappingResult: BlindedIdMapping? = dependencies.storage.getBlindedIdMapping(with: blindedId) + var mappingResult: BlindedIdMapping? = dependencies.storage.getBlindedIdMapping(with: blindedId, using: transaction) // No need to continue if we already have a result if let mapping: BlindedIdMapping = mappingResult { return mapping } // Then we try loop through all approved contact threads to see if one of those contacts can be blinded to match - ContactUtilities.enumerateApprovedContactThreads { contactThread, contact, stop in + ContactUtilities.enumerateApprovedContactThreads(using: transaction) { contactThread, contact, stop in guard dependencies.sodium.sessionId(contact.sessionID, matchesBlindedId: blindedId, serverPublicKey: serverPublicKey) else { return } // Cache the mapping let newMapping: BlindedIdMapping = BlindedIdMapping(blindedId: blindedId, sessionId: contact.sessionID, serverPublicKey: serverPublicKey) - dependencies.storage.cacheBlindedIdMapping(newMapping) + dependencies.storage.cacheBlindedIdMapping(newMapping, using: transaction) mappingResult = newMapping stop.pointee = true } @@ -81,7 +88,7 @@ public enum ContactUtilities { // Lastly loop through existing id mappings (in case the user is looking at a different SOGS but once had // a thread with this contact in a different SOGS and had cached the mapping) - dependencies.storage.enumerateBlindedIdMapping { mapping, stop in + dependencies.storage.enumerateBlindedIdMapping(using: transaction) { mapping, stop in guard mapping.serverPublicKey != serverPublicKey else { return } guard dependencies.sodium.sessionId(mapping.sessionId, matchesBlindedId: blindedId, serverPublicKey: serverPublicKey) else { return @@ -89,7 +96,7 @@ public enum ContactUtilities { // Cache the new mapping let newMapping: BlindedIdMapping = BlindedIdMapping(blindedId: blindedId, sessionId: mapping.sessionId, serverPublicKey: serverPublicKey) - dependencies.storage.cacheBlindedIdMapping(newMapping) + dependencies.storage.cacheBlindedIdMapping(newMapping, using: transaction) mappingResult = newMapping stop.pointee = true } diff --git a/SessionMessagingKitTests/_TestUtilities/TestStorage.swift b/SessionMessagingKitTests/_TestUtilities/TestStorage.swift index bae468cd0..3424a7749 100644 --- a/SessionMessagingKitTests/_TestUtilities/TestStorage.swift +++ b/SessionMessagingKitTests/_TestUtilities/TestStorage.swift @@ -62,7 +62,7 @@ class TestStorage: SessionMessagingKitStorageProtocol, Mockable { func cacheBlindedIdMapping(_ mapping: BlindedIdMapping) {} func cacheBlindedIdMapping(_ mapping: BlindedIdMapping, using transaction: YapDatabaseReadWriteTransaction) {} func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> ()) {} - func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> (), transaction: YapDatabaseReadTransaction) { + func enumerateBlindedIdMapping(using transaction: YapDatabaseReadTransaction, with block: @escaping (BlindedIdMapping, UnsafeMutablePointer) -> ()) { } // MARK: - Closed Groups