WIP
This commit is contained in:
parent
bbd3ecd54a
commit
aec182f36c
|
@ -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];
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<TSGroupThread>!
|
||||
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)
|
||||
|
|
|
@ -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 = "<group>"; };
|
||||
C33FDAF7255A580600E217F9 /* OWSPrimaryStorage+SignedPreKeyStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "OWSPrimaryStorage+SignedPreKeyStore.m"; sourceTree = "<group>"; };
|
||||
C33FDAF9255A580600E217F9 /* TSContactThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSContactThread.m; sourceTree = "<group>"; };
|
||||
C33FDAFB255A580600E217F9 /* SessionMetaProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionMetaProtocol.swift; sourceTree = "<group>"; };
|
||||
C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIMETypeUtil.h; sourceTree = "<group>"; };
|
||||
C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; };
|
||||
C33FDAFE255A580600E217F9 /* OWSStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSStorage.h; sourceTree = "<group>"; };
|
||||
|
@ -1605,7 +1602,6 @@
|
|||
C33FDB9E255A581400E217F9 /* TSAttachmentPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentPointer.m; sourceTree = "<group>"; };
|
||||
C33FDBA0255A581400E217F9 /* TSStorageHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageHeaders.h; sourceTree = "<group>"; };
|
||||
C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = "<group>"; };
|
||||
C33FDBA3255A581400E217F9 /* SessionManagementProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SessionManagementProtocol.swift; sourceTree = "<group>"; };
|
||||
C33FDBA4255A581400E217F9 /* OWSDisappearingMessagesConfiguration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingMessagesConfiguration.m; sourceTree = "<group>"; };
|
||||
C33FDBA6255A581400E217F9 /* TSInvalidIdentityKeySendingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeySendingErrorMessage.h; sourceTree = "<group>"; };
|
||||
C33FDBA8255A581500E217F9 /* OWSLinkPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSLinkPreview.swift; sourceTree = "<group>"; };
|
||||
|
@ -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 */,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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<String>, transaction: YapDatabaseReadWriteTransaction) -> Promise<TSGroupThread> {
|
||||
// Prepare
|
||||
var members = members
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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<String> = []
|
||||
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)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue