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
pull/592/head
Morgan Pretty 3 years ago
parent 81f563229f
commit f9468219d9

@ -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 = "<group>"; };
FDC4381427B329CE00C60D73 /* NonceGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonceGenerator.swift; sourceTree = "<group>"; };
FDC4381627B32EC700C60D73 /* Personalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Personalization.swift; sourceTree = "<group>"; };
FDC4381927B34EBA00C60D73 /* LegacyCompactPollBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyCompactPollBody.swift; sourceTree = "<group>"; };
FDC4381B27B354AC00C60D73 /* LegacyPublicKeyBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyPublicKeyBody.swift; sourceTree = "<group>"; };
FDC4381F27B36ADC00C60D73 /* SOGSEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOGSEndpoint.swift; sourceTree = "<group>"; };
FDC4382527B37F6900C60D73 /* LegacyDeletedMessagesResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyDeletedMessagesResponse.swift; sourceTree = "<group>"; };
FDC4382727B37FD300C60D73 /* LegacyModeratorsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyModeratorsResponse.swift; sourceTree = "<group>"; };
FDC4382927B3802D00C60D73 /* LegacyRoomsResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyRoomsResponse.swift; sourceTree = "<group>"; };
FDC4382B27B380E300C60D73 /* LegacyMemberCountResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyMemberCountResponse.swift; sourceTree = "<group>"; };
FDC4382E27B383AF00C60D73 /* UnregisterResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnregisterResponse.swift; sourceTree = "<group>"; };
FDC4383027B3841C00C60D73 /* RegisterResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegisterResponse.swift; sourceTree = "<group>"; };
FDC4383727B3863200C60D73 /* VersionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = "<group>"; };
FDC4383927B4696200C60D73 /* LegacyAuthTokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyAuthTokenResponse.swift; sourceTree = "<group>"; };
FDC4383D27B4708600C60D73 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
FDC4383F27B4746D00C60D73 /* LegacyGetInfoResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyGetInfoResponse.swift; sourceTree = "<group>"; };
FDC4384327B47F4D00C60D73 /* LegacyOpenGroupMessageV2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyOpenGroupMessageV2.swift; sourceTree = "<group>"; };
FDC4384427B47F4D00C60D73 /* LegacyRoomInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyRoomInfo.swift; sourceTree = "<group>"; };
FDC4384527B47F4D00C60D73 /* LegacyCompactPollResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyCompactPollResponse.swift; sourceTree = "<group>"; };
FDC4384627B47F4D00C60D73 /* LegacyDeletion.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyDeletion.swift; sourceTree = "<group>"; };
FDC4384B27B47F7700C60D73 /* OpenGroup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroup.swift; sourceTree = "<group>"; };
FDC4384E27B4804F00C60D73 /* Header.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Header.swift; sourceTree = "<group>"; };
FDC4385027B4807400C60D73 /* QueryParam.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryParam.swift; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -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 */,

@ -97,11 +97,11 @@ extension Storage {
public func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> ()) {
Storage.read { transaction in
self.enumerateBlindedIdMapping(with: block, transaction: transaction)
self.enumerateBlindedIdMapping(using: transaction, with: block)
}
}
public func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> (), transaction: YapDatabaseReadTransaction) {
public func enumerateBlindedIdMapping(using transaction: YapDatabaseReadTransaction, with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> ()) {
transaction.enumerateRows(inCollection: Storage.blindedIdCacheCollection) { _, object, _, stop in
guard let mapping = object as? BlindedIdMapping else { return }

@ -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

@ -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<CodingKeys> = 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<CodingKeys> = encoder.container(keyedBy: CodingKeys.self)
try container.encode(ciphertext.base64EncodedString(), forKey: .ciphertext)
try container.encode(ephemeralPublicKey.base64EncodedString(), forKey: .ephemeralPublicKey)
}
}

@ -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]
}
}

@ -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]
}
}

@ -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]
}
}

@ -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)
}
}
}

@ -1,9 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
extension OpenGroupAPI {
struct LegacyGetInfoResponse: Codable {
let room: LegacyRoomInfo
}
}

@ -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
}
}

@ -1,9 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
extension OpenGroupAPI {
struct LegacyModeratorsResponse: Codable {
let moderators: [String]
}
}

@ -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<CodingKeys> = 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
)
}
}

@ -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
}
}

@ -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?
}
}

@ -1,9 +0,0 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
extension OpenGroupAPI {
struct LegacyRoomsResponse: Codable {
let rooms: [LegacyRoomInfo]
}
}

@ -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<String> {
let storage = SNMessagingKitConfiguration.shared.storage
if let authToken: String = storage.getAuthToken(for: room, on: server) {
return Promise.value(authToken)
}
if let authTokenPromise: Promise<String> = legacyAuthTokenPromises.wrappedValue["\(server).\(room)"] {
return authTokenPromise
}
let promise: Promise<String> = legacyRequestNewAuthToken(for: room, on: server)
.then(on: OpenGroupAPI.workQueue) { legacyClaimAuthToken($0, for: room, on: server) }
.then(on: OpenGroupAPI.workQueue) { authToken -> Promise<String> in
let (promise, seal) = Promise<String>.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<String> {
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<String> {
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<Void> {
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<LegacyCompactPollResponse> {
let storage: SessionMessagingKitStorageProtocol = SNMessagingKitConfiguration.shared.storage
let rooms: [String] = storage.getAllOpenGroups().values
.filter { $0.server == server }
.map { $0.room }
var getAuthTokenPromises: [String: Promise<String>] = [:]
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<String>](getAuthTokenPromises.values))
.then(on: OpenGroupAPI.workQueue) { _ -> Promise<LegacyCompactPollResponse> 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<LegacyCompactPollResponse> 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<LegacyRoomInfo> {
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<Data> {
// 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<Data> = 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<UInt64> {
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<UInt64> {
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<Data> {
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<LegacyOpenGroupMessageV2> {
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<Void> {
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<Void> {
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<Void> {
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<Void> {
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.")
}
}

@ -14,8 +14,12 @@ public final class OpenGroupManager: NSObject {
public static var defaultRoomsPromise: Promise<[OpenGroupAPI.Room]>?
private static var groupImagePromises: [String: Promise<Data>] = [:]
private static var moderators: [String: [String: Set<String>]] = [:] // Server URL to room ID to set of moderator IDs
private static var admins: [String: [String: Set<String>]] = [:] // 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<String>]]> = Atomic([:])
/// Server URL to room ID to set of admin IDs
private static var admins: Atomic<[String: [String: Set<String>]]> = 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<String> = (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<String> = 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()) {

@ -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
}
}
}

@ -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])

@ -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) }
}
}
}
}

@ -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<ObjCBool>) -> ())
func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> (), transaction: YapDatabaseReadTransaction)
func enumerateBlindedIdMapping(using transaction: YapDatabaseReadTransaction, with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> ())
// MARK: - Closed Groups

@ -39,39 +39,46 @@ public enum ContactUtilities {
.map { $0.sessionID }
}
public static func enumerateApprovedContactThreads(with block: @escaping (TSContactThread, Contact, UnsafeMutablePointer<ObjCBool>) -> ()) {
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<ObjCBool>) -> ()) {
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
}

@ -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<ObjCBool>) -> ()) {}
func enumerateBlindedIdMapping(with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> (), transaction: YapDatabaseReadTransaction) {
func enumerateBlindedIdMapping(using transaction: YapDatabaseReadTransaction, with block: @escaping (BlindedIdMapping, UnsafeMutablePointer<ObjCBool>) -> ()) {
}
// MARK: - Closed Groups

Loading…
Cancel
Save