diff --git a/Session/Signal/ConversationView/ConversationViewController.m b/Session/Signal/ConversationView/ConversationViewController.m index 3917855a8..ff1bc290e 100644 --- a/Session/Signal/ConversationView/ConversationViewController.m +++ b/Session/Signal/ConversationView/ConversationViewController.m @@ -3248,12 +3248,6 @@ typedef enum : NSUInteger { // }]; [self messageWasSent:message]; - - if ([self.thread isKindOfClass:TSContactThread.class]) { - [LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKSessionManagementProtocol sendSessionRequestIfNeededToPublicKey:self.thread.contactIdentifier transaction:transaction]; - }]; - } }); } diff --git a/Session/Signal/OWSConversationSettingsViewController.m b/Session/Signal/OWSConversationSettingsViewController.m index d4ae93edd..449485ae1 100644 --- a/Session/Signal/OWSConversationSettingsViewController.m +++ b/Session/Signal/OWSConversationSettingsViewController.m @@ -950,7 +950,7 @@ static CGRect oldframe; if (gThread.usesSharedSenderKeys) { NSString *groupPublicKey = [LKGroupUtilities getDecodedGroupID:gThread.groupModel.groupId]; [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [[LKClosedGroupsProtocol leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; + [[SNMessageSenderDelegate leaveGroupWithPublicKey:groupPublicKey transaction:transaction] retainUntilComplete]; }]; } @@ -1197,21 +1197,7 @@ static CGRect oldframe; - (void)resetSecureSession { - if (![self.thread isKindOfClass:TSContactThread.class]) { return; } - TSContactThread *thread = (TSContactThread *)self.thread; - __weak OWSConversationSettingsViewController *weakSelf = self; - NSString *message = @"This may help if you're having encryption problems in this conversation. Your messages will be kept."; - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Reset Secure Session?" message:message preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"TXT_CANCEL_TITLE", @"") style:UIAlertActionStyleDefault handler:nil]]; - [alert addAction:[UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - dispatch_async(dispatch_get_main_queue(), ^{ - [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [LKSessionManagementProtocol startSessionResetInThread:thread transaction:transaction]; - }]; - [weakSelf.navigationController popViewControllerAnimated:YES]; - }); - }]]; - [self presentViewController:alert animated:YES completion:nil]; + } #pragma mark - Notifications diff --git a/Session/View Controllers/EditClosedGroupVC.swift b/Session/View Controllers/EditClosedGroupVC.swift index 472cfe9e9..fc05185a8 100644 --- a/Session/View Controllers/EditClosedGroupVC.swift +++ b/Session/View Controllers/EditClosedGroupVC.swift @@ -209,7 +209,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega guard !name.isEmpty else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_missing_error", comment: "")) } - guard name.count < ClosedGroupsProtocol.maxNameSize else { + guard name.count < 64 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } isEditingGroupName = false @@ -253,7 +253,7 @@ final class EditClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelega } ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in Storage.writeSync { [weak self] transaction in - ClosedGroupsProtocol.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { + MessageSenderDelegate.update(groupPublicKey, with: members, name: name, transaction: transaction).done(on: DispatchQueue.main) { guard let self = self else { return } self.dismiss(animated: true, completion: nil) // Dismiss the loader popToConversationVC(self) diff --git a/Session/View Controllers/HomeVC.swift b/Session/View Controllers/HomeVC.swift index 4e6df7b5c..20f9f3d30 100644 --- a/Session/View Controllers/HomeVC.swift +++ b/Session/View Controllers/HomeVC.swift @@ -384,7 +384,7 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, UIScrol } else if let thread = thread as? TSGroupThread, thread.usesSharedSenderKeys == true { let groupID = thread.groupModel.groupId let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupID) - let _ = ClosedGroupsProtocol.leave(groupPublicKey, using: transaction).ensure { + let _ = MessageSenderDelegate.leave(groupPublicKey, using: transaction).ensure { Storage.writeSync { transaction in thread.removeAllThreadInteractions(with: transaction) thread.remove(with: transaction) diff --git a/Session/View Controllers/NewClosedGroupVC.swift b/Session/View Controllers/NewClosedGroupVC.swift index 027b85f06..d81ba17f7 100644 --- a/Session/View Controllers/NewClosedGroupVC.swift +++ b/Session/View Controllers/NewClosedGroupVC.swift @@ -157,20 +157,20 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat guard let name = nameTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines), name.count > 0 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_missing_error", comment: "")) } - guard name.count < ClosedGroupsProtocol.maxNameSize else { + guard name.count < 64 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } guard selectedContacts.count >= 1 else { return showError(title: "Please pick at least 1 group member") } - guard selectedContacts.count < ClosedGroupsProtocol.groupSizeLimit else { // Minus one because we're going to include self later + guard selectedContacts.count < 20 else { // Minus one because we're going to include self later return showError(title: NSLocalizedString("vc_create_closed_group_too_many_group_members_error", comment: "")) } let selectedContacts = self.selectedContacts ModalActivityIndicatorViewController.present(fromViewController: navigationController!, canCancel: false) { [weak self] _ in var promise: Promise! Storage.writeSync { transaction in - promise = ClosedGroupsProtocol.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) + promise = MessageSenderDelegate.createClosedGroup(name: name, members: selectedContacts, transaction: transaction) } let _ = promise.done(on: DispatchQueue.main) { thread in self?.presentingViewController?.dismiss(animated: true, completion: nil) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 480ed9c80..cfbf33f06 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -403,7 +403,6 @@ C33FDCAE255A582000E217F9 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; }; C33FDCB1255A582000E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */; }; C33FDCB3255A582000E217F9 /* TSContactThread.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF9255A580600E217F9 /* TSContactThread.m */; }; - C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */; }; C33FDCB7255A582000E217F9 /* LRUCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFD255A580600E217F9 /* LRUCache.swift */; }; C33FDCB8255A582000E217F9 /* OWSStorage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFE255A580600E217F9 /* OWSStorage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDCB9255A582000E217F9 /* DisplayNameUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */; }; @@ -485,7 +484,6 @@ C33FDD56255A582000E217F9 /* TSIncomingMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB9C255A581300E217F9 /* TSIncomingMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; - C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */; }; C33FDD5E255A582000E217F9 /* OWSDisappearingMessagesConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */; }; C33FDD60255A582000E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; C33FDD62255A582000E217F9 /* OWSLinkPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */; }; @@ -1511,7 +1509,6 @@ C33FDAF4255A580600E217F9 /* SSKEnvironment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SSKEnvironment.m; sourceTree = ""; }; C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+SignedPreKeyStore.m"; sourceTree = ""; }; C33FDAF9255A580600E217F9 /* TSContactThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSContactThread.m; sourceTree = ""; }; - C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionMetaProtocol.swift; sourceTree = ""; }; C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = ""; }; C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = ""; }; C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = ""; }; @@ -1605,7 +1602,6 @@ C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = ""; }; C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageHeaders.h; sourceTree = ""; }; C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = ""; }; - C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManagementProtocol.swift; sourceTree = ""; }; C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesConfiguration.m; sourceTree = ""; }; C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeySendingErrorMessage.h; sourceTree = ""; }; C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSLinkPreview.swift; sourceTree = ""; }; @@ -3272,8 +3268,6 @@ C33FDAFF255A580600E217F9 /* DisplayNameUtilities.swift */, C33FDBF4255A581B00E217F9 /* DisplayNameUtilities2.swift */, C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */, - C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */, - C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */, C33FDADF255A580400E217F9 /* PublicChatManager.swift */, C38EF3E5255B6DF4007E1867 /* ContactCellView.h */, C38EF3D6255B6DEF007E1867 /* ContactCellView.m */, @@ -5075,7 +5069,6 @@ C38EF218255B6D3B007E1867 /* Theme.m in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, B8D8F1382566120F0092EF10 /* Storage+ClosedGroups.swift in Sources */, - C33FDD5D255A582000E217F9 /* SessionManagementProtocol.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, C33FDD76255A582000E217F9 /* SSKKeychainStorage.swift in Sources */, C33FDDA6255A582000E217F9 /* OWSRecipientIdentity.m in Sources */, @@ -5097,7 +5090,6 @@ C33FDD13255A582000E217F9 /* OWSFailedAttachmentDownloadsJob.m in Sources */, C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */, C3CA3B13255CF18200F4C6D4 /* Destination+Conversion.swift in Sources */, - C33FDCB5255A582000E217F9 /* SessionMetaProtocol.swift in Sources */, C33FDD4D255A582000E217F9 /* PreKeyBundle+jsonDict.m in Sources */, C38EF24B255B6D67007E1867 /* UIView+OWS.m in Sources */, C33FDC51255A582000E217F9 /* TSIncomingMessage.m in Sources */, diff --git a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m b/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m index 07e8e7708..8163fa538 100644 --- a/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m +++ b/SignalUtilitiesKit/Messaging/Read Tracking/OWSOutgoingReceiptManager.m @@ -165,10 +165,12 @@ NSString *const kOutgoingReadReceiptManagerCollection = @"kOutgoingReadReceiptMa TSThread *thread = [TSContactThread getOrCreateThreadWithContactId:recipientId]; - if (![LKSessionMetaProtocol shouldSendReceiptInThread:thread]) { + if (thread.isGroupThread) { // Don't send receipts in group threads continue; } + // TODO TODO TODO + /* OWSReceiptsForSenderMessage *message; NSString *receiptName; diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift index bea7e37c4..bb72e8bac 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageReceiverDelegate.swift @@ -289,7 +289,6 @@ public final class MessageReceiverDelegate : SessionMessagingKit.MessageReceiver } // Respond to the request SNLog("Responding to sender key request from: \(message.sender!).") - SessionManagementProtocol.sendSessionRequestIfNeeded(to: message.sender!, using: transaction) let userRatchet = Storage.shared.getClosedGroupRatchet(for: groupPublicKey, senderPublicKey: userPublicKey) ?? SharedSenderKeys.generateRatchet(for: groupPublicKey, senderPublicKey: userPublicKey, using: transaction) let userSenderKey = ClosedGroupSenderKey(chainKey: Data(hex: userRatchet.chainKey), keyIndex: userRatchet.keyIndex, publicKey: Data(hex: userPublicKey)) diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift index 3452f3d68..92fc37e3c 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSenderDelegate.swift @@ -1,7 +1,9 @@ import PromiseKit -public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { +@objc(SNMessageSenderDelegate) +public final class MessageSenderDelegate : NSObject, SessionMessagingKit.MessageSenderDelegate, SharedSenderKeysDelegate { + // MARK: Error public enum Error : LocalizedError { case noThread case noPrivateKey @@ -16,8 +18,12 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele } } + // MARK: Initialization public static let shared = MessageSenderDelegate() + private override init() { } + + // MARK: Sending public func handleSuccessfulMessageSend(_ message: Message, using transaction: Any) { guard let tsMessage = TSOutgoingMessage.find(withTimestamp: message.sentTimestamp!) else { return } if let openGroupServerMessageID = message.openGroupServerMessageID { @@ -30,6 +36,7 @@ public final class MessageSenderDelegate : SessionMessagingKit.MessageSenderDele // TODO: Implement } + // MARK: Closed Groups public static func createClosedGroup(name: String, members: Set, transaction: YapDatabaseReadWriteTransaction) -> Promise { // Prepare var members = members diff --git a/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift b/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift index 18b5325fb..7e8e64bdb 100644 --- a/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift +++ b/SignalUtilitiesKit/Messaging/Typing Indicators/TypingIndicators.swift @@ -309,7 +309,7 @@ public class TypingIndicatorsImpl: NSObject, TypingIndicators { return } - if !SessionMetaProtocol.shouldSendTypingIndicator(in: thread) { return } + if thread.isGroupThread() { return } // Don't send typing indicators in group threads let typingIndicator = TypingIndicator() typingIndicator.kind = action diff --git a/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift b/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift deleted file mode 100644 index bb0df42fd..000000000 --- a/SignalUtilitiesKit/To Do/SessionManagementProtocol.swift +++ /dev/null @@ -1,225 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used -// • Express those cases in tests. - -@objc(LKSessionManagementProtocol) -public final class SessionManagementProtocol : NSObject { - - internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } - - // MARK: - General - - @objc(createPreKeys) - public static func createPreKeys() { - // We don't generate new pre keys here like Signal does. - // This is because we need the records to be linked to a contact since we don't have a central server. - // It's done automatically when we generate a pre key bundle to send to a contact (generatePreKeyBundleForContact:). - // You can use getOrCreatePreKeyForContact: to generate one if needed. - let signedPreKeyRecord = storage.generateRandomSignedRecord() - signedPreKeyRecord.markAsAcceptedByService() - storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - SNLog("Pre keys created successfully.") - } - - @objc(refreshSignedPreKey) - public static func refreshSignedPreKey() { - // We don't generate new pre keys here like Signal does. - // This is because we need the records to be linked to a contact since we don't have a central server. - // It's done automatically when we generate a pre key bundle to send to a contact (generatePreKeyBundleForContact:). - // You can use getOrCreatePreKeyForContact: to generate one if needed. - guard storage.currentSignedPrekeyId() == nil else { return } - let signedPreKeyRecord = storage.generateRandomSignedRecord() - signedPreKeyRecord.markAsAcceptedByService() - storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - TSPreKeyManager.clearPreKeyUpdateFailureCount() - TSPreKeyManager.clearSignedPreKeyRecords() - SNLog("Signed pre key refreshed successfully.") - } - - @objc(rotateSignedPreKey) - public static func rotateSignedPreKey() { - // This is identical to what Signal does, except that it doesn't upload the signed pre key - // to a server. - let signedPreKeyRecord = storage.generateRandomSignedRecord() - signedPreKeyRecord.markAsAcceptedByService() - storage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) - storage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) - TSPreKeyManager.clearPreKeyUpdateFailureCount() - TSPreKeyManager.clearSignedPreKeyRecords() - SNLog("Signed pre key rotated successfully.") - } - - // MARK: - Sending - - @objc(isSessionRequiredForMessage:recipientID:transaction:) - public static func isSessionRequired(for message: TSOutgoingMessage, recipientID: String, transaction: YapDatabaseReadWriteTransaction) -> Bool { - return false -// if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { -// return false -// } else { -// return !shouldUseFallbackEncryption(for: message, recipientID: recipientID, transaction: transaction) -// } - } - - @objc(shouldUseFallbackEncryptionForMessage:recipientID:transaction:) - public static func shouldUseFallbackEncryption(for message: TSOutgoingMessage, recipientID: String, transaction: YapDatabaseReadWriteTransaction) -> Bool { - return true -// if SharedSenderKeysImplementation.shared.isClosedGroup(recipientID) { return false } -// else if message is SessionRequestMessage { return true } -// else if message is EndSessionMessage { return true } -// else if let message = message as? DeviceLinkMessage, message.kind == .request { return true } -// else if message is OWSOutgoingNullMessage { return false } -// return !storage.containsSession(recipientID, deviceId: Int32(OWSDevicePrimaryDeviceId), protocolContext: transaction) - } - - private static func hasSentSessionRequestExpired(for publicKey: String) -> Bool { - return false -// let timestamp = Storage.getSessionRequestSentTimestamp(for: publicKey) -// let expiration = timestamp + TTLUtilities.getTTL(for: .sessionRequest) -// return NSDate.ows_millisecondTimeStamp() > expiration - } - - @objc(sendSessionRequestIfNeededToPublicKey:transaction:) - public static func sendSessionRequestIfNeeded(to publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { - // It's never necessary to establish a session with self - guard publicKey != getUserHexEncodedPublicKey() else { return } - // Check that we don't already have a session - let hasSession = storage.containsSession(publicKey, deviceId: Int32(1), protocolContext: transaction) - guard !hasSession else { return } - // Check that we didn't already send a session request - let hasSentSessionRequest = (Storage.shared.getSessionRequestSentTimestamp(for: publicKey) > 0) - let hasSentSessionRequestExpired = SessionManagementProtocol.hasSentSessionRequestExpired(for: publicKey) - if hasSentSessionRequestExpired { - Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: 0, using: transaction) - } - guard !hasSentSessionRequest || hasSentSessionRequestExpired else { return } - // Create the thread if needed - let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) - thread.save(with: transaction) - // Send the session request - SNLog("Sending session request to: \(publicKey).") - Storage.shared.setSessionRequestSentTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) - let sessionRequest = SessionRequest() - sessionRequest.preKeyBundle = storage.generatePreKeyBundle(forContact: publicKey) - MessageSender.send(sessionRequest, in: thread, using: transaction) - } - - @objc(sendNullMessageToPublicKey:transaction:) - public static func sendNullMessage(to publicKey: String, in transaction: YapDatabaseReadWriteTransaction) { - let thread = TSContactThread.getOrCreateThread(withContactId: publicKey, transaction: transaction) - thread.save(with: transaction) - let nullMessage = NullMessage() - MessageSender.send(nullMessage, in: thread, using: transaction) - } - - /// - Note: Deprecated. - /// - /// Only relevant for closed groups that don't use shared sender keys. - @objc(shouldIgnoreMissingPreKeyBundleExceptionForMessage:to:) - public static func shouldIgnoreMissingPreKeyBundleException(for message: TSOutgoingMessage, to hexEncodedPublicKey: String) -> Bool { - // When a closed group is created, members try to establish sessions with eachother in the background through - // session requests. Until ALL users those session requests were sent to have come online, stored the pre key - // bundles contained in the session requests and replied with background messages to finalize the session - // creation, a given user won't be able to successfully send a message to all members of a group. This check - // is so that until we can do better on this front the user at least won't see this as an error in the UI. - guard let groupThread = message.thread as? TSGroupThread else { return false } - return groupThread.groupModel.groupType == .closedGroup && !groupThread.usesSharedSenderKeys - } - - @objc(startSessionResetInThread:transaction:) - public static func startSessionReset(in thread: TSThread, using transaction: YapDatabaseReadWriteTransaction) { -// // Check preconditions -// guard let thread = thread as? TSContactThread else { -// return SNLog("Can't restore session for non contact thread.") -// } -// // Send end session messages to the devices requiring session restoration -// let devices = thread.sessionRestoreDevices // TODO: Rename this to something that reads better -// for device in devices { -// guard ECKeyPair.isValidHexEncodedPublicKey(candidate: device) else { continue } -// let thread = TSContactThread.getOrCreateThread(withContactId: device, transaction: transaction) -// thread.save(with: transaction) -// /* -// let endSessionMessage = EndSessionMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread) -// let messageSenderJobQueue = SSKEnvironment.shared.messageSenderJobQueue -// messageSenderJobQueue.add(message: endSessionMessage, transaction: transaction) -// */ -// } -// thread.removeAllSessionRestoreDevices(with: transaction) -// // Notify the user -// let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) -// infoMessage.save(with: transaction) -// // Update the session reset status -// thread.sessionResetStatus = .initiated -// thread.save(with: transaction) - } - - // MARK: - Receiving - - @objc(handleDecryptionError:forPublicKey:transaction:) - public static func handleDecryptionError(_ errorMessage: TSErrorMessage, for publicKey: String, using transaction: YapDatabaseReadWriteTransaction) { -// let type = errorMessage.errorType -// let masterPublicKey = storage.getMasterHexEncodedPublicKey(for: publicKey, in: transaction) ?? publicKey -// let thread = TSContactThread.getOrCreateThread(withContactId: masterPublicKey, transaction: transaction) -// let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) -// // Show the session reset prompt upon certain errors -// switch type { -// case .noSession, .invalidMessage, .invalidKeyException: -// if restorationTimeInMs > errorMessage.timestamp { -// // Automatically rebuild session after restoration -// sendSessionRequestIfNeeded(to: publicKey, using: transaction) -// } else { -// // Store the source device's public key in case it was a secondary device -// thread.addSessionRestoreDevice(publicKey, transaction: transaction) -// } -// default: break -// } - } - - private static func shouldProcessSessionRequest(from publicKey: String, at timestamp: UInt64) -> Bool { - let sentTimestamp = Storage.shared.getSessionRequestSentTimestamp(for: publicKey) - let processedTimestamp = Storage.shared.getSessionRequestProcessedTimestamp(for: publicKey) - let restorationTimestamp = UInt64(storage.getRestorationTime() * 1000) - return timestamp > sentTimestamp && timestamp > processedTimestamp && timestamp > restorationTimestamp - } - - @objc(handlePreKeyBundleMessageIfNeeded:wrappedIn:transaction:) - public static func handlePreKeyBundleMessageIfNeeded(_ protoContent: SNProtoContent, wrappedIn envelope: SNProtoEnvelope, using transaction: YapDatabaseReadWriteTransaction) { -// let publicKey = envelope.source! // Set during UD decryption -// guard let preKeyBundleMessage = protoContent.prekeyBundleMessage else { return } -// SNLog("Received a pre key bundle message from: \(publicKey).") -// guard let preKeyBundle = preKeyBundleMessage.getPreKeyBundle(with: transaction) else { -// return SNLog("Couldn't parse pre key bundle received from: \(publicKey).") -// } -// if !shouldProcessSessionRequest(from: publicKey, at: envelope.timestamp) { -// return SNLog("Ignoring session request from: \(publicKey).") -// } -// storage.setPreKeyBundle(preKeyBundle, forContact: publicKey, transaction: transaction) -// Storage.setSessionRequestProcessedTimestamp(for: publicKey, to: NSDate.ows_millisecondTimeStamp(), using: transaction) -// sendNullMessage(to: publicKey, in: transaction) - } - - @objc(handleEndSessionMessageReceivedInThread:using:) - public static func handleEndSessionMessageReceived(in thread: TSContactThread, using transaction: YapDatabaseReadWriteTransaction) { -// let publicKey = thread.contactIdentifier() -// SNLog("End session message received from: \(publicKey).") -// // Notify the user -// let infoMessage = TSInfoMessage(timestamp: NSDate.ows_millisecondTimeStamp(), in: thread, messageType: .typeLokiSessionResetInProgress) -// infoMessage.save(with: transaction) -// // Archive all sessions -// storage.archiveAllSessions(forContact: publicKey, protocolContext: transaction) -// // Update the session reset status -// thread.sessionResetStatus = .requestReceived -// thread.save(with: transaction) -// // Send a null message -// sendNullMessage(to: publicKey, in: transaction) - } -} diff --git a/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift b/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift deleted file mode 100644 index a47c8e5ee..000000000 --- a/SignalUtilitiesKit/To Do/SessionMetaProtocol.swift +++ /dev/null @@ -1,119 +0,0 @@ -import PromiseKit - -// A few notes about making changes in this file: -// -// • Don't use a database transaction if you can avoid it. -// • If you do need to use a database transaction, use a read transaction if possible. -// • For write transactions, consider making it the caller's responsibility to manage the database transaction (this helps avoid unnecessary transactions). -// • Think carefully about adding a function; there might already be one for what you need. -// • Document the expected cases in which a function will be used -// • Express those cases in tests. - -/// See [Receipts, Transcripts & Typing Indicators](https://github.com/loki-project/session-protocol-docs/wiki/Receipts,-Transcripts-&-Typing-Indicators) for more information. -@objc(LKSessionMetaProtocol) -public final class SessionMetaProtocol : NSObject { - - internal static var storage: OWSPrimaryStorage { OWSPrimaryStorage.shared() } - - // MARK: - Sending - - // MARK: Message Destination(s) - @objc public static func getDestinationsForOutgoingSyncMessage() -> NSMutableSet { - return NSMutableSet(set: [ getUserHexEncodedPublicKey() ]) // return NSMutableSet(set: MultiDeviceProtocol.getUserLinkedDevices()) - } - - @objc(getDestinationsForOutgoingGroupMessage:inThread:) - public static func getDestinations(for outgoingGroupMessage: TSOutgoingMessage, in thread: TSThread) -> NSMutableSet { - guard let thread = thread as? TSGroupThread else { preconditionFailure("Can't get destinations for group message in non-group thread.") } - var result: Set = [] - if thread.isOpenGroup { - if let openGroup = Storage.shared.getOpenGroup(for: thread.uniqueId!) { - result = [ openGroup.server ] // Aim the message at the open group server - } else { - // Should never occur - } - } else { - if let groupThread = thread as? TSGroupThread, groupThread.usesSharedSenderKeys { - let groupPublicKey = LKGroupUtilities.getDecodedGroupID(groupThread.groupModel.groupId) - result = [ groupPublicKey ] - } else { - result = Set(outgoingGroupMessage.sendingRecipientIds()) - .intersection(thread.groupModel.groupMemberIds) - .subtracting([ getUserHexEncodedPublicKey() ]) // .subtracting(MultiDeviceProtocol.getUserLinkedDevices()) - } - } - return NSMutableSet(set: result) - } - - // MARK: Note to Self - @objc(isThreadNoteToSelf:) - public static func isThreadNoteToSelf(_ thread: TSThread) -> Bool { - guard let thread = thread as? TSContactThread else { return false } - return thread.contactIdentifier() == getUserHexEncodedPublicKey() - /* - var isNoteToSelf = false - storage.dbReadConnection.read { transaction in - isNoteToSelf = LokiDatabaseUtilities.isUserLinkedDevice(thread.contactIdentifier(), transaction: transaction) - } - return isNoteToSelf - */ - } - - // MARK: Transcripts - @objc(shouldSendTranscriptForMessage:inThread:) - public static func shouldSendTranscript(for message: TSOutgoingMessage, in thread: TSThread) -> Bool { - guard message.shouldSyncTranscript() else { return false } - let isOpenGroupMessage = (thread as? TSGroupThread)?.isOpenGroup == true - let wouldSignalRequireTranscript = (AreRecipientUpdatesEnabled() || !message.hasSyncedTranscript) - guard wouldSignalRequireTranscript && !isOpenGroupMessage else { return false } - return false - /* - var usesMultiDevice = false - storage.dbReadConnection.read { transaction in - usesMultiDevice = !storage.getDeviceLinks(for: getUserHexEncodedPublicKey(), in: transaction).isEmpty - || UserDefaults.standard[.masterHexEncodedPublicKey] != nil - } - return usesMultiDevice - */ - } - - // MARK: Typing Indicators - /// Invoked only if typing indicators are enabled in the settings. Provides an opportunity - /// to avoid sending them if certain conditions are met. - @objc(shouldSendTypingIndicatorInThread:) - public static func shouldSendTypingIndicator(in thread: TSThread) -> Bool { - return !thread.isGroupThread() && thread.numberOfInteractions() > 0 - } - - // MARK: Receipts - @objc(shouldSendReceiptInThread:) - public static func shouldSendReceipt(in thread: TSThread) -> Bool { - return !thread.isGroupThread() - } - - // MARK: - Receiving - - @objc(isErrorMessageFromBeforeRestoration:) - public static func isErrorMessageFromBeforeRestoration(_ errorMessage: TSErrorMessage) -> Bool { - let restorationTimeInMs = UInt64(storage.getRestorationTime() * 1000) - return errorMessage.timestamp < restorationTimeInMs - } - - @objc(updateDisplayNameIfNeededForPublicKey:using:transaction:) - public static func updateDisplayNameIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage, in transaction: YapDatabaseReadWriteTransaction) { - guard let profile = dataMessage.profile, let displayName = profile.displayName, !displayName.isEmpty else { return } - let profileManager = SSKEnvironment.shared.profileManager - profileManager.updateProfileForContact(withID: publicKey, displayName: displayName, with: transaction) - } - - @objc(updateProfileKeyIfNeededForPublicKey:using:) - public static func updateProfileKeyIfNeeded(for publicKey: String, using dataMessage: SNProtoDataMessage) { - guard dataMessage.hasProfileKey, let profileKey = dataMessage.profileKey else { return } - guard profileKey.count == kAES256_KeyByteLength else { - return SNLog("Unexpected profile key size: \(profileKey.count).") - } - let profilePictureURL = dataMessage.profile?.profilePicture - let profileManager = SSKEnvironment.shared.profileManager - profileManager.setProfileKeyData(profileKey, forRecipientId: publicKey, avatarURL: profilePictureURL) - } -}