From 409337b5126d3840a5335359420d02c194d44809 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Wed, 26 Aug 2020 11:11:55 +1000 Subject: [PATCH 01/12] use server time to order open group messages --- .../src/Loki/API/Open Groups/PublicChatAPI.swift | 10 ++++++---- .../src/Loki/API/Open Groups/PublicChatMessage.swift | 12 ++++++++---- .../src/Loki/API/Open Groups/PublicChatPoller.swift | 2 +- SignalServiceKit/src/Messages/OWSMessageSender.m | 2 +- 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift index 09574bbe9..4f5e25b54 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift @@ -122,10 +122,12 @@ public final class PublicChatAPI : DotNetAPI { return rawMessages.flatMap { message in let isDeleted = (message["is_deleted"] as? Int == 1) guard !isDeleted else { return nil } + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ" guard let annotations = message["annotations"] as? [JSON], let annotation = annotations.first(where: { $0["type"] as? String == publicChatMessageType }), let value = annotation["value"] as? JSON, let serverID = message["id"] as? UInt64, let hexEncodedSignatureData = value["sig"] as? String, let signatureVersion = value["sigver"] as? UInt64, let body = message["text"] as? String, let user = message["user"] as? JSON, let hexEncodedPublicKey = user["username"] as? String, - let timestamp = value["timestamp"] as? UInt64 else { + let timestamp = value["timestamp"] as? UInt64, let dateAsString = message["created_at"] as? String, let date = dateFormatter.date(from: dateAsString) else { print("[Loki] Couldn't parse message for public chat channel with ID: \(channel) on server: \(server) from: \(message).") return nil } @@ -168,7 +170,7 @@ public final class PublicChatAPI : DotNetAPI { width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle) } let result = PublicChatMessage(serverID: serverID, senderPublicKey: hexEncodedPublicKey, displayName: displayName, profilePicture: profilePicture, - body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature) + body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTime: date) guard result.hasValidSignature() else { print("[Loki] Ignoring public chat message with invalid signature.") return nil @@ -182,7 +184,7 @@ public final class PublicChatAPI : DotNetAPI { return nil } return result - }.sorted { $0.timestamp < $1.timestamp } + }.sorted { $0.serverTime!.compare($1.serverTime!) == ComparisonResult.orderedAscending } } } }.handlingInvalidAuthTokenIfNeeded(for: server) @@ -217,7 +219,7 @@ public final class PublicChatAPI : DotNetAPI { throw DotNetAPIError.parsingFailed } let timestamp = UInt64(date.timeIntervalSince1970) * 1000 - return PublicChatMessage(serverID: serverID, senderPublicKey: getUserHexEncodedPublicKey(), displayName: displayName, profilePicture: signedMessage.profilePicture, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature) + return PublicChatMessage(serverID: serverID, senderPublicKey: getUserHexEncodedPublicKey(), displayName: displayName, profilePicture: signedMessage.profilePicture, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature, serverTime: date) } } }.handlingInvalidAuthTokenIfNeeded(for: server) diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift index 6445ebf03..ab05a0e34 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift @@ -14,6 +14,9 @@ public final class PublicChatMessage : NSObject { public var attachments: [Attachment] = [] public let signature: Signature? + // MARK: Server Time (use for sorting) + public let serverTime: Date? + @objc(serverID) public var objc_serverID: UInt64 { return serverID ?? 0 } @@ -72,7 +75,7 @@ public final class PublicChatMessage : NSObject { } // MARK: Initialization - public init(serverID: UInt64?, senderPublicKey: String, displayName: String, profilePicture: ProfilePicture?, body: String, type: String, timestamp: UInt64, quote: Quote?, attachments: [Attachment], signature: Signature?) { + public init(serverID: UInt64?, senderPublicKey: String, displayName: String, profilePicture: ProfilePicture?, body: String, type: String, timestamp: UInt64, quote: Quote?, attachments: [Attachment], signature: Signature?, serverTime: Date? = nil) { self.serverID = serverID self.senderPublicKey = senderPublicKey self.displayName = displayName @@ -83,10 +86,11 @@ public final class PublicChatMessage : NSObject { self.quote = quote self.attachments = attachments self.signature = signature + self.serverTime = serverTime super.init() } - @objc public convenience init(senderPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64) { + @objc public convenience init(senderPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64, serverTime: Date? = nil) { let quote: Quote? if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteePublicKey, let quotedMessageBody = quotedMessageBody { let quotedMessageServerID = (quotedMessageServerID != 0) ? quotedMessageServerID : nil @@ -100,7 +104,7 @@ public final class PublicChatMessage : NSObject { } else { signature = nil } - self.init(serverID: nil, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: nil, body: body, type: type, timestamp: timestamp, quote: quote, attachments: [], signature: signature) + self.init(serverID: nil, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: nil, body: body, type: type, timestamp: timestamp, quote: quote, attachments: [], signature: signature, serverTime: serverTime) } // MARK: Crypto @@ -115,7 +119,7 @@ public final class PublicChatMessage : NSObject { return nil } let signature = Signature(data: signatureData, version: signatureVersion) - return PublicChatMessage(serverID: serverID, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: profilePicture, body: body, type: type, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature) + return PublicChatMessage(serverID: serverID, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: profilePicture, body: body, type: type, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTime: serverTime) } internal func hasValidSignature() -> Bool { diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift index 3e4efc7e1..7e63ca214 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift @@ -75,7 +75,7 @@ public final class PublicChatPoller : NSObject { } */ // Sorting the messages by timestamp before importing them fixes an issue where messages that quote older messages can't find those older messages - messages.sorted { $0.timestamp < $1.timestamp }.forEach { message in + messages.sorted { $0.serverTime!.compare($1.serverTime!) == ComparisonResult.orderedAscending }.forEach { message in var wasSentByCurrentUser = false OWSPrimaryStorage.shared().dbReadConnection.read { transaction in wasSentByCurrentUser = LokiDatabaseUtilities.isUserLinkedDevice(message.senderPublicKey, transaction: transaction) diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index a5e64e1cb..4374f69fa 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1043,7 +1043,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body LKPublicChatMessage *groupMessage = [[LKPublicChatMessage alloc] initWithSenderPublicKey:userPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType - timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0]; + timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0 serverTime:nil]; OWSLinkPreview *linkPreview = message.linkPreview; if (linkPreview != nil) { TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId]; From 10f1b4be8c91ef46b69b80e44cabe028f6c79d91 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Wed, 26 Aug 2020 12:54:28 +1000 Subject: [PATCH 02/12] allow creation of group of size with only one member and us --- Signal/src/Loki/View Controllers/NewClosedGroupVC.swift | 4 ++-- Signal/translations/en.lproj/Localizable.strings | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift index a46c235d8..a2401b935 100644 --- a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -171,7 +171,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat guard name.count < 64 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } - guard selectedContacts.count >= 2 else { + guard selectedContacts.count >= 1 else { return showError(title: NSLocalizedString("vc_create_closed_group_not_enough_group_members_error", comment: "")) } guard selectedContacts.count < 50 else { // Minus one because we're going to include self later @@ -211,7 +211,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat guard name.count < 64 else { return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } - guard selectedContacts.count >= 2 else { + guard selectedContacts.count >= 1 else { return showError(title: NSLocalizedString("vc_create_closed_group_not_enough_group_members_error", comment: "")) } guard selectedContacts.count < 10 else { // Minus one because we're going to include self later diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index eb3256526..223da87e8 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -2647,7 +2647,7 @@ "vc_create_closed_group_empty_state_button_title" = "Start a Session"; "vc_create_closed_group_group_name_missing_error" = "Please enter a group name"; "vc_create_closed_group_group_name_too_long_error" = "Please enter a shorter group name"; -"vc_create_closed_group_not_enough_group_members_error" = "Please pick at least 2 group members"; +"vc_create_closed_group_not_enough_group_members_error" = "Please pick at least 1 group member"; "vc_create_closed_group_too_many_group_members_error" = "A closed group cannot have more than 10 members"; "vc_create_closed_group_invalid_session_id_error" = "One of the members of your group has an invalid Session ID"; From 80c460553051ed96f8579ab9d08fb01bc5bb6e3c Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Wed, 26 Aug 2020 13:07:12 +1000 Subject: [PATCH 03/12] sort with sortId for open groups in TSInteraction --- .../src/Messages/Interactions/TSInteraction.m | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m index 83af87902..07009a22c 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m @@ -5,6 +5,7 @@ #import "TSInteraction.h" #import "TSDatabaseSecondaryIndexes.h" #import "TSThread.h" +#import "TSGroupThread.h" #import #import @@ -191,6 +192,18 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) // Loki: Sort the messages by the sender's timestamp (Signal uses sortId) uint64_t sortId1 = self.timestamp; uint64_t sortId2 = other.timestamp; + + // Loki: In open groups, we use the server time to sort the messages + // SortId represents the order that a message is processed + // Since we have sorted the messages in the poller using server time + // SortId can represent the order by server time. + if (self.thread.isGroupThread) { + TSGroupThread *thread = (TSGroupThread *)self.thread; + if (thread.isPublicChat) { + sortId1 = self.sortId; + sortId2 = other.sortId; + } + } if (sortId1 > sortId2) { return NSOrderedDescending; From d6604c10ffa6293c3ae80be9ea59c478b32c4b2e Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Wed, 26 Aug 2020 14:11:42 +1000 Subject: [PATCH 04/12] use timestamp instead of date --- .../src/Loki/API/Open Groups/PublicChatAPI.swift | 7 ++++--- .../Loki/API/Open Groups/PublicChatMessage.swift | 14 +++++++------- .../Loki/API/Open Groups/PublicChatPoller.swift | 2 +- SignalServiceKit/src/Messages/OWSMessageSender.m | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift index 4f5e25b54..268175ba1 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift @@ -131,6 +131,7 @@ public final class PublicChatAPI : DotNetAPI { print("[Loki] Couldn't parse message for public chat channel with ID: \(channel) on server: \(server) from: \(message).") return nil } + let servertTimestamp = UInt64(date.timeIntervalSince1970) * 1000 var profilePicture: PublicChatMessage.ProfilePicture? = nil let displayName = user["name"] as? String ?? NSLocalizedString("Anonymous", comment: "") if let userAnnotations = user["annotations"] as? [JSON], let profilePictureAnnotation = userAnnotations.first(where: { $0["type"] as? String == profilePictureType }), @@ -170,7 +171,7 @@ public final class PublicChatAPI : DotNetAPI { width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle) } let result = PublicChatMessage(serverID: serverID, senderPublicKey: hexEncodedPublicKey, displayName: displayName, profilePicture: profilePicture, - body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTime: date) + body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTimestamp: servertTimestamp) guard result.hasValidSignature() else { print("[Loki] Ignoring public chat message with invalid signature.") return nil @@ -184,7 +185,7 @@ public final class PublicChatAPI : DotNetAPI { return nil } return result - }.sorted { $0.serverTime!.compare($1.serverTime!) == ComparisonResult.orderedAscending } + }.sorted { $0.serverTimestamp < $1.serverTimestamp} } } }.handlingInvalidAuthTokenIfNeeded(for: server) @@ -219,7 +220,7 @@ public final class PublicChatAPI : DotNetAPI { throw DotNetAPIError.parsingFailed } let timestamp = UInt64(date.timeIntervalSince1970) * 1000 - return PublicChatMessage(serverID: serverID, senderPublicKey: getUserHexEncodedPublicKey(), displayName: displayName, profilePicture: signedMessage.profilePicture, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature, serverTime: date) + return PublicChatMessage(serverID: serverID, senderPublicKey: getUserHexEncodedPublicKey(), displayName: displayName, profilePicture: signedMessage.profilePicture, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature, serverTimestamp: timestamp) } } }.handlingInvalidAuthTokenIfNeeded(for: server) diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift index ab05a0e34..780f1fa52 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift @@ -14,8 +14,8 @@ public final class PublicChatMessage : NSObject { public var attachments: [Attachment] = [] public let signature: Signature? - // MARK: Server Time (use for sorting) - public let serverTime: Date? + // MARK: Server Timestamp (use for sorting) + public let serverTimestamp: UInt64 @objc(serverID) public var objc_serverID: UInt64 { return serverID ?? 0 } @@ -75,7 +75,7 @@ public final class PublicChatMessage : NSObject { } // MARK: Initialization - public init(serverID: UInt64?, senderPublicKey: String, displayName: String, profilePicture: ProfilePicture?, body: String, type: String, timestamp: UInt64, quote: Quote?, attachments: [Attachment], signature: Signature?, serverTime: Date? = nil) { + public init(serverID: UInt64?, senderPublicKey: String, displayName: String, profilePicture: ProfilePicture?, body: String, type: String, timestamp: UInt64, quote: Quote?, attachments: [Attachment], signature: Signature?, serverTimestamp: UInt64) { self.serverID = serverID self.senderPublicKey = senderPublicKey self.displayName = displayName @@ -86,11 +86,11 @@ public final class PublicChatMessage : NSObject { self.quote = quote self.attachments = attachments self.signature = signature - self.serverTime = serverTime + self.serverTimestamp = serverTimestamp super.init() } - @objc public convenience init(senderPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64, serverTime: Date? = nil) { + @objc public convenience init(senderPublicKey: String, displayName: String, body: String, type: String, timestamp: UInt64, quotedMessageTimestamp: UInt64, quoteePublicKey: String?, quotedMessageBody: String?, quotedMessageServerID: UInt64, signatureData: Data?, signatureVersion: UInt64, serverTimestamp: UInt64) { let quote: Quote? if quotedMessageTimestamp != 0, let quoteeHexEncodedPublicKey = quoteePublicKey, let quotedMessageBody = quotedMessageBody { let quotedMessageServerID = (quotedMessageServerID != 0) ? quotedMessageServerID : nil @@ -104,7 +104,7 @@ public final class PublicChatMessage : NSObject { } else { signature = nil } - self.init(serverID: nil, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: nil, body: body, type: type, timestamp: timestamp, quote: quote, attachments: [], signature: signature, serverTime: serverTime) + self.init(serverID: nil, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: nil, body: body, type: type, timestamp: timestamp, quote: quote, attachments: [], signature: signature, serverTimestamp: serverTimestamp) } // MARK: Crypto @@ -119,7 +119,7 @@ public final class PublicChatMessage : NSObject { return nil } let signature = Signature(data: signatureData, version: signatureVersion) - return PublicChatMessage(serverID: serverID, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: profilePicture, body: body, type: type, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTime: serverTime) + return PublicChatMessage(serverID: serverID, senderPublicKey: senderPublicKey, displayName: displayName, profilePicture: profilePicture, body: body, type: type, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTimestamp: serverTimestamp) } internal func hasValidSignature() -> Bool { diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift index 7e63ca214..5779c3e1d 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatPoller.swift @@ -75,7 +75,7 @@ public final class PublicChatPoller : NSObject { } */ // Sorting the messages by timestamp before importing them fixes an issue where messages that quote older messages can't find those older messages - messages.sorted { $0.serverTime!.compare($1.serverTime!) == ComparisonResult.orderedAscending }.forEach { message in + messages.sorted { $0.serverTimestamp < $1.serverTimestamp }.forEach { message in var wasSentByCurrentUser = false OWSPrimaryStorage.shared().dbReadConnection.read { transaction in wasSentByCurrentUser = LokiDatabaseUtilities.isUserLinkedDevice(message.senderPublicKey, transaction: transaction) diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 4374f69fa..f87c8ab6b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1043,7 +1043,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body LKPublicChatMessage *groupMessage = [[LKPublicChatMessage alloc] initWithSenderPublicKey:userPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType - timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0 serverTime:nil]; + timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0 serverTimestamp:0]; OWSLinkPreview *linkPreview = message.linkPreview; if (linkPreview != nil) { TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId]; From f2b67cc78ad0b110dcde1c393d478041fdb43c51 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 27 Aug 2020 09:17:57 +1000 Subject: [PATCH 05/12] Update translations --- Signal/src/Loki/View Controllers/NewClosedGroupVC.swift | 4 ++-- Signal/translations/de.lproj/Localizable.strings | 1 - Signal/translations/en.lproj/Localizable.strings | 1 - Signal/translations/es.lproj/Localizable.strings | 1 - Signal/translations/fa.lproj/Localizable.strings | 1 - Signal/translations/fr.lproj/Localizable.strings | 1 - Signal/translations/it.lproj/Localizable.strings | 1 - Signal/translations/pt_BR.lproj/Localizable.strings | 1 - Signal/translations/ru.lproj/Localizable.strings | 3 +-- Signal/translations/zh_CN.lproj/Localizable.strings | 1 - 10 files changed, 3 insertions(+), 12 deletions(-) diff --git a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift index a2401b935..3e31f2eff 100644 --- a/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift +++ b/Signal/src/Loki/View Controllers/NewClosedGroupVC.swift @@ -172,7 +172,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } guard selectedContacts.count >= 1 else { - return showError(title: NSLocalizedString("vc_create_closed_group_not_enough_group_members_error", comment: "")) + return showError(title: "Please pick at least 1 group member") } guard selectedContacts.count < 50 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: "")) @@ -212,7 +212,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat return showError(title: NSLocalizedString("vc_create_closed_group_group_name_too_long_error", comment: "")) } guard selectedContacts.count >= 1 else { - return showError(title: NSLocalizedString("vc_create_closed_group_not_enough_group_members_error", comment: "")) + return showError(title: "Please pick at least 1 group member") } guard selectedContacts.count < 10 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: "")) diff --git a/Signal/translations/de.lproj/Localizable.strings b/Signal/translations/de.lproj/Localizable.strings index fa81833e7..ba9644ce4 100644 --- a/Signal/translations/de.lproj/Localizable.strings +++ b/Signal/translations/de.lproj/Localizable.strings @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "Session starten"; "vc_create_closed_group_group_name_missing_error" = "Bitte geben Sie einen Gruppennamen ein."; "vc_create_closed_group_group_name_too_long_error" = "Bitte geben Sie einen kürzeren Gruppennamen ein."; -"vc_create_closed_group_not_enough_group_members_error" = "Bitte wählen Sie mindestens zwei Gruppenmitglieder aus."; "vc_create_closed_group_too_many_group_members_error" = "Eine geschlossene Gruppe kann maximal zehn Mitglieder haben."; "vc_create_closed_group_invalid_session_id_error" = "Ein Mitglied Ihrer Gruppe hat eine ungültige Session ID."; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 223da87e8..ed691906c 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -2647,7 +2647,6 @@ "vc_create_closed_group_empty_state_button_title" = "Start a Session"; "vc_create_closed_group_group_name_missing_error" = "Please enter a group name"; "vc_create_closed_group_group_name_too_long_error" = "Please enter a shorter group name"; -"vc_create_closed_group_not_enough_group_members_error" = "Please pick at least 1 group member"; "vc_create_closed_group_too_many_group_members_error" = "A closed group cannot have more than 10 members"; "vc_create_closed_group_invalid_session_id_error" = "One of the members of your group has an invalid Session ID"; diff --git a/Signal/translations/es.lproj/Localizable.strings b/Signal/translations/es.lproj/Localizable.strings index 35c13d975..a66178d52 100644 --- a/Signal/translations/es.lproj/Localizable.strings +++ b/Signal/translations/es.lproj/Localizable.strings @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "Empezar una Session"; "vc_create_closed_group_group_name_missing_error" = "Por favor, ingresa un nombre de grupo"; "vc_create_closed_group_group_name_too_long_error" = "Por favor, ingresa un nombre de grupo más corto"; -"vc_create_closed_group_not_enough_group_members_error" = "Por favor, elige al menos 2 miembros del grupo"; "vc_create_closed_group_too_many_group_members_error" = "Un grupo cerrado no puede tener más de 10 miembros"; "vc_create_closed_group_invalid_session_id_error" = "Uno de los miembros de tu grupo tiene un ID de Session no válido"; diff --git a/Signal/translations/fa.lproj/Localizable.strings b/Signal/translations/fa.lproj/Localizable.strings index 26bc996ef..404b7854a 100644 --- a/Signal/translations/fa.lproj/Localizable.strings +++ b/Signal/translations/fa.lproj/Localizable.strings @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "شروع Session"; "vc_create_closed_group_group_name_missing_error" = "لطفا یک نام گروه وارد کنید"; "vc_create_closed_group_group_name_too_long_error" = "لطفا نام گروه کوتاه‌تری وارد کنید"; -"vc_create_closed_group_not_enough_group_members_error" = "لطفا حداقل ۲ عضو برای گروه انتخاب کنید"; "vc_create_closed_group_too_many_group_members_error" = "یک گروه خصوصی نمی‌تواند بیش از ۱۰ عضو داشته باشد"; "vc_create_closed_group_invalid_session_id_error" = "یکی از اعضای گروه شما دارای شناسه نامعتبر است"; diff --git a/Signal/translations/fr.lproj/Localizable.strings b/Signal/translations/fr.lproj/Localizable.strings index 00431fbea..10bbdb8de 100644 --- a/Signal/translations/fr.lproj/Localizable.strings +++ b/Signal/translations/fr.lproj/Localizable.strings @@ -2648,7 +2648,6 @@ "vc_create_closed_group_empty_state_button_title" = "Démarrer une session"; "vc_create_closed_group_group_name_missing_error" = "Veuillez saisir un nom de groupe"; "vc_create_closed_group_group_name_too_long_error" = "Veuillez saisir un nom de groupe plus court"; -"vc_create_closed_group_not_enough_group_members_error" = "Veuillez sélectionner au moins 2 membres"; "vc_create_closed_group_too_many_group_members_error" = "Un groupe privé ne peut pas avoir plus de 10 membres"; "vc_create_closed_group_invalid_session_id_error" = "Un des membres de votre groupe a un Session ID non valide"; diff --git a/Signal/translations/it.lproj/Localizable.strings b/Signal/translations/it.lproj/Localizable.strings index 8058fc506..faa832e34 100644 --- a/Signal/translations/it.lproj/Localizable.strings +++ b/Signal/translations/it.lproj/Localizable.strings @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "Inizia una sessione"; "vc_create_closed_group_group_name_missing_error" = "Inserisci un nome per il gruppo"; "vc_create_closed_group_group_name_too_long_error" = "Inserisci un nome gruppo più breve"; -"vc_create_closed_group_not_enough_group_members_error" = "Scegli almeno 2 membri del gruppo"; "vc_create_closed_group_too_many_group_members_error" = "Un gruppo chiuso non può avere più di 10 membri"; "vc_create_closed_group_invalid_session_id_error" = "Uno dei membri del tuo gruppo ha una Sessione ID non valido"; diff --git a/Signal/translations/pt_BR.lproj/Localizable.strings b/Signal/translations/pt_BR.lproj/Localizable.strings index ddea683b9..dcb2f0d25 100644 --- a/Signal/translations/pt_BR.lproj/Localizable.strings +++ b/Signal/translations/pt_BR.lproj/Localizable.strings @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "Iniciar uma sessão"; "vc_create_closed_group_group_name_missing_error" = "Digite um nome de grupo"; "vc_create_closed_group_group_name_too_long_error" = "Digite um nome de grupo mais curto"; -"vc_create_closed_group_not_enough_group_members_error" = "Escolha pelo menos 2 membros do grupo"; "vc_create_closed_group_too_many_group_members_error" = "Um grupo fechado não pode ter mais de 10 membros"; "vc_create_closed_group_invalid_session_id_error" = "Um dos membros do seu grupo tem um ID Session inválido"; diff --git a/Signal/translations/ru.lproj/Localizable.strings b/Signal/translations/ru.lproj/Localizable.strings index f67f85599..96c0b9bd0 100644 --- a/Signal/translations/ru.lproj/Localizable.strings +++ b/Signal/translations/ru.lproj/Localizable.strings @@ -2570,7 +2570,7 @@ "view_fake_chat_bubble_5" = "Друзья не позволят друзьям использовать ненадежные мессенджеры. Пользуйтесь на здоровье."; "vc_register_title" = "Познакомьтесь со своим Session ID"; -"vc_register_explanation" = "Ваш Session ID - это уникальный адрес, который могут использовать другие люди для связи с вами при помощи Session. Поскольку ваш Session ID никак не связан с вашей настоящей личностью, он по определению является полностью анонимным и конфиденциальным."; +"vc_register_explanation" = "Ваш Session ID - это уникальный адрес, который другие пользователи могут использовать для связи с вами при помощи Session. Поскольку ваш Session ID никак не связан с вашей настоящей личностью, он по определению является полностью анонимным и конфиденциальным."; "vc_register_public_key_copied_message" = "Скопировано в буфер обмена"; "vc_restore_title" = "Восстановите свой аккаунт"; @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "Начать Сессию"; "vc_create_closed_group_group_name_missing_error" = "Пожалуйста, введите название группы"; "vc_create_closed_group_group_name_too_long_error" = "Пожалуйста, введите более короткое имя группы"; -"vc_create_closed_group_not_enough_group_members_error" = "Пожалуйста, выберите как минимум 2 участников группы"; "vc_create_closed_group_too_many_group_members_error" = "В закрытой группе не может быть больше 10 участников"; "vc_create_closed_group_invalid_session_id_error" = "Один из участников вашей группы имеет недопустимый Session ID"; diff --git a/Signal/translations/zh_CN.lproj/Localizable.strings b/Signal/translations/zh_CN.lproj/Localizable.strings index 0d8df3995..4b373be5b 100644 --- a/Signal/translations/zh_CN.lproj/Localizable.strings +++ b/Signal/translations/zh_CN.lproj/Localizable.strings @@ -2638,7 +2638,6 @@ "vc_create_closed_group_empty_state_button_title" = "开始对话"; "vc_create_closed_group_group_name_missing_error" = "请输入群组名称"; "vc_create_closed_group_group_name_too_long_error" = "请输入较短的群组名称"; -"vc_create_closed_group_not_enough_group_members_error" = "请选择至少2位群组成员"; "vc_create_closed_group_too_many_group_members_error" = "私密群组成员不得超过10个"; "vc_create_closed_group_invalid_session_id_error" = "您群组中的一位成员的Session ID无效"; From 833b8aa18a15ef2fa9ef7b8c69a09e65a2f3295a Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 27 Aug 2020 10:46:47 +1000 Subject: [PATCH 06/12] Minor refactoring --- .../src/Loki/API/Open Groups/PublicChatAPI.swift | 4 ++-- .../src/Loki/API/Open Groups/PublicChatMessage.swift | 3 +-- .../src/Messages/Interactions/TSInteraction.m | 11 +++++------ SignalServiceKit/src/Messages/OWSMessageSender.m | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift index 268175ba1..e18cd245a 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatAPI.swift @@ -131,7 +131,7 @@ public final class PublicChatAPI : DotNetAPI { print("[Loki] Couldn't parse message for public chat channel with ID: \(channel) on server: \(server) from: \(message).") return nil } - let servertTimestamp = UInt64(date.timeIntervalSince1970) * 1000 + let serverTimestamp = UInt64(date.timeIntervalSince1970) * 1000 var profilePicture: PublicChatMessage.ProfilePicture? = nil let displayName = user["name"] as? String ?? NSLocalizedString("Anonymous", comment: "") if let userAnnotations = user["annotations"] as? [JSON], let profilePictureAnnotation = userAnnotations.first(where: { $0["type"] as? String == profilePictureType }), @@ -171,7 +171,7 @@ public final class PublicChatAPI : DotNetAPI { width: width, height: height, caption: caption, url: url, linkPreviewURL: linkPreviewURL, linkPreviewTitle: linkPreviewTitle) } let result = PublicChatMessage(serverID: serverID, senderPublicKey: hexEncodedPublicKey, displayName: displayName, profilePicture: profilePicture, - body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTimestamp: servertTimestamp) + body: body, type: publicChatMessageType, timestamp: timestamp, quote: quote, attachments: attachments, signature: signature, serverTimestamp: serverTimestamp) guard result.hasValidSignature() else { print("[Loki] Ignoring public chat message with invalid signature.") return nil diff --git a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift index 780f1fa52..9c15c618f 100644 --- a/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift +++ b/SignalServiceKit/src/Loki/API/Open Groups/PublicChatMessage.swift @@ -13,8 +13,7 @@ public final class PublicChatMessage : NSObject { public let quote: Quote? public var attachments: [Attachment] = [] public let signature: Signature? - - // MARK: Server Timestamp (use for sorting) + /// - Note: Used for sorting. public let serverTimestamp: UInt64 @objc(serverID) diff --git a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m index 07009a22c..45ea82714 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSInteraction.m +++ b/SignalServiceKit/src/Messages/Interactions/TSInteraction.m @@ -189,14 +189,13 @@ NSString *NSStringFromOWSInteractionType(OWSInteractionType value) { OWSAssertDebug(other); - // Loki: Sort the messages by the sender's timestamp (Signal uses sortId) + // Sort the messages by the sender's timestamp (Signal uses sortId) uint64_t sortId1 = self.timestamp; uint64_t sortId2 = other.timestamp; - - // Loki: In open groups, we use the server time to sort the messages - // SortId represents the order that a message is processed - // Since we have sorted the messages in the poller using server time - // SortId can represent the order by server time. + + // In open groups messages should be sorted by their server timestamp. `sortId` represents the order in which messages + // were processed. Since in the open group poller we sort messages by their server timestamp, sorting by `sortId` is + // effectively the same as sorting by server timestamp. if (self.thread.isGroupThread) { TSGroupThread *thread = (TSGroupThread *)self.thread; if (thread.isPublicChat) { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index f87c8ab6b..2d980a534 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1043,7 +1043,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; } NSString *body = (message.body != nil && message.body.length > 0) ? message.body : [NSString stringWithFormat:@"%@", @(message.timestamp)]; // Workaround for the fact that the back-end doesn't accept messages without a body LKPublicChatMessage *groupMessage = [[LKPublicChatMessage alloc] initWithSenderPublicKey:userPublicKey displayName:displayName body:body type:LKPublicChatAPI.publicChatMessageType - timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0 serverTimestamp:0]; + timestamp:message.timestamp quotedMessageTimestamp:quoteID quoteePublicKey:quoteePublicKey quotedMessageBody:quote.body quotedMessageServerID:quotedMessageServerID signatureData:nil signatureVersion:0 serverTimestamp:0]; OWSLinkPreview *linkPreview = message.linkPreview; if (linkPreview != nil) { TSAttachmentStream *attachment = [TSAttachmentStream fetchObjectWithUniqueID:linkPreview.imageAttachmentId]; From 344b5e0fcef8457c3a3965961473d758424806f2 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 27 Aug 2020 14:39:59 +1000 Subject: [PATCH 07/12] Increase file size OR multiplier --- SignalServiceKit/src/Loki/API/FileServerAPI.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/FileServerAPI.swift b/SignalServiceKit/src/Loki/API/FileServerAPI.swift index 2b95c8814..fc2f69535 100644 --- a/SignalServiceKit/src/Loki/API/FileServerAPI.swift +++ b/SignalServiceKit/src/Loki/API/FileServerAPI.swift @@ -12,10 +12,10 @@ public final class FileServerAPI : DotNetAPI { public static let maxFileSize = 10_000_000 // 10 MB /// The file server has a file size limit of `maxFileSize`, which the Service Nodes try to enforce as well. However, the limit applied by the Service Nodes /// is on the **HTTP request** and not the file size. Because of onion request encryption, a file that's about 4 MB will result in a request that's about 18 MB. - /// On average the multiplier appears to be about 4.4, so when checking whether the file will exceed the file size limit when uploading a file we just divide + /// On average the multiplier appears to be about 6, so when checking whether the file will exceed the file size limit when uploading a file we just divide /// the size of the file by this number. The alternative would be to actually check the size of the HTTP request but that's only possible after proof of work /// has been calculated and the onion request encryption has happened, which takes several seconds. - public static let fileSizeORMultiplier = 4.4 + public static let fileSizeORMultiplier: Double = 6 @objc public static let server = "https://file.getsession.org" From 0cc958f39ea2a20f4bca64c06ed23dfb4a9d5bb9 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 26 Aug 2020 15:07:25 +1000 Subject: [PATCH 08/12] Update version number --- Signal.xcodeproj/project.pbxproj | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 89581bd15..b50488241 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4088,7 +4088,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4102,7 +4102,7 @@ INFOPLIST_FILE = SignalShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -4150,7 +4150,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4169,7 +4169,7 @@ INFOPLIST_FILE = SignalShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -4204,7 +4204,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4223,7 +4223,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.utilities"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; @@ -4274,7 +4274,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4298,7 +4298,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.utilities"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; @@ -4336,7 +4336,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4348,7 +4348,7 @@ INFOPLIST_FILE = LokiPushNotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; @@ -4399,7 +4399,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4416,7 +4416,7 @@ INFOPLIST_FILE = LokiPushNotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; @@ -4600,7 +4600,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4635,7 +4635,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -4668,7 +4668,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 103; + CURRENT_PROJECT_VERSION = 104; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4703,7 +4703,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.4.5; + MARKETING_VERSION = 1.4.6; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From a1ef5c3c716011d7c5006486903291400a7179f9 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 26 Aug 2020 16:21:18 +1000 Subject: [PATCH 09/12] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index b50488241..82d991df0 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4088,7 +4088,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4150,7 +4150,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4204,7 +4204,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4274,7 +4274,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4336,7 +4336,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4399,7 +4399,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4600,7 +4600,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4668,7 +4668,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 104; + CURRENT_PROJECT_VERSION = 105; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 08c1acef51cc22688e97b5af694d7f428ad1b331 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 27 Aug 2020 14:42:40 +1000 Subject: [PATCH 10/12] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 82d991df0..acbe04bf1 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4088,7 +4088,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4150,7 +4150,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4204,7 +4204,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4274,7 +4274,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4336,7 +4336,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4399,7 +4399,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4600,7 +4600,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4668,7 +4668,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 105; + CURRENT_PROJECT_VERSION = 106; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 3bbe8f558df49acc47d1867b068f8b832923f608 Mon Sep 17 00:00:00 2001 From: Ryan ZHAO Date: Thu, 27 Aug 2020 15:49:17 +1000 Subject: [PATCH 11/12] Make replies show the user's display name rather than their Session ID --- .../ConversationView/Cells/OWSQuotedMessageView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m b/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m index 807914dcc..62493bc4b 100644 --- a/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m +++ b/Signal/src/ViewControllers/ConversationView/Cells/OWSQuotedMessageView.m @@ -549,7 +549,7 @@ const CGFloat kRemotelySourcedContentRowSpacing = 4; } } else { OWSContactsManager *contactsManager = Environment.shared.contactsManager; - __block NSString *quotedAuthor = [contactsManager contactOrProfileNameForPhoneIdentifier:self.quotedMessage.authorId]; + __block NSString *quotedAuthor = [SSKEnvironment.shared.profileManager profileNameForRecipientWithID:self.quotedMessage.authorId] ?: [contactsManager contactOrProfileNameForPhoneIdentifier:self.quotedMessage.authorId]; if (quotedAuthor == self.quotedMessage.authorId) { [OWSPrimaryStorage.sharedManager.dbReadConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { From 4d13c6bee5c1f0df53521f15c73b687dd7d12238 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 28 Aug 2020 11:10:59 +1000 Subject: [PATCH 12/12] Patch unread indicator bug --- .../ConversationViewController.m | 1 - .../ConversationView/ConversationViewModel.m | 12 +++++++-- SignalServiceKit/src/Contacts/TSThread.m | 26 +++++++++++++++++-- .../src/Messages/OWSMessageUtils.m | 25 ++++++++++++++++++ .../src/Messages/OWSReadReceiptManager.m | 5 +++- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m index 538b73f49..96f84c3ff 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewController.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewController.m @@ -3607,7 +3607,6 @@ typedef enum : NSUInteger { // and won't update the UI state immediately. - (void)didScrollToBottom { - id _Nullable lastVisibleViewItem = [self.viewItems lastObject]; if (lastVisibleViewItem) { uint64_t lastVisibleSortId = lastVisibleViewItem.interaction.sortId; diff --git a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m index 9e699b2b3..693392413 100644 --- a/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m +++ b/Signal/src/ViewControllers/ConversationView/ConversationViewModel.m @@ -63,8 +63,16 @@ NS_ASSUME_NONNULL_BEGIN interactionIndexMap[viewItem.interaction.uniqueId] = @(i); [interactionIds addObject:viewItem.interaction.uniqueId]; - if (viewItem.unreadIndicator != nil) { - _unreadIndicatorIndex = @(i); + if (viewItem.unreadIndicator != nil && [viewItem.interaction conformsToProtocol:@protocol(OWSReadTracking)]) { + id interaction = (id)viewItem.interaction; + + // Under normal circumstances !interaction.read should always evaluate to true at this point, but + // there is a bug that can somehow cause it to be false leading to conversations permanently being + // stuck with "unread" messages. + + if (!interaction.read) { + _unreadIndicatorIndex = @(i); + } } } _interactionIndexMap = [interactionIndexMap copy]; diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index ec78d578c..eeb2a87f0 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -348,7 +348,12 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa OWSFailDebug(@"Unexpected object in unseen messages: %@", [object class]); return; } - [messages addObject:(id)object]; + id unread = (id)object; + if (unread.read) { + [LKLogger print:@"Found an already read message in the * unseen * messages list."]; + return; + } + [messages addObject:unread]; }]; return [messages copy]; @@ -356,7 +361,24 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa - (NSUInteger)unreadMessageCountWithTransaction:(YapDatabaseReadTransaction *)transaction { - return [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInGroup:self.uniqueId]; + __block NSUInteger count = 0; + + YapDatabaseViewTransaction *unreadMessages = [transaction ext:TSUnreadDatabaseViewExtensionName]; + [unreadMessages enumerateKeysAndObjectsInGroup:self.uniqueId + usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { + if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { + OWSFailDebug(@"Unexpected object in unread messages: %@", [object class]); + return; + } + id unread = (id)object; + if (unread.read) { + [LKLogger print:@"Found an already read message in the * unread * messages list."]; + return; + } + count += 1; + }]; + + return count; } - (void)markAllAsReadWithTransaction:(YapDatabaseReadWriteTransaction *)transaction diff --git a/SignalServiceKit/src/Messages/OWSMessageUtils.m b/SignalServiceKit/src/Messages/OWSMessageUtils.m index 5b39aa3af..a3e5e54bc 100644 --- a/SignalServiceKit/src/Messages/OWSMessageUtils.m +++ b/SignalServiceKit/src/Messages/OWSMessageUtils.m @@ -18,6 +18,7 @@ #import "TSThread.h" #import "UIImage+OWS.h" #import +#import NS_ASSUME_NONNULL_BEGIN @@ -65,6 +66,30 @@ NS_ASSUME_NONNULL_BEGIN - (NSUInteger)unreadMessagesCount { + __block NSUInteger count = 0; + + [LKStorage readWithBlock:^(YapDatabaseReadTransaction *transaction) { + YapDatabaseViewTransaction *unreadMessages = [transaction ext:TSUnreadDatabaseViewExtensionName]; + NSArray *allGroups = [unreadMessages allGroups]; + for (NSString *groupID in allGroups) { + [unreadMessages enumerateKeysAndObjectsInGroup:groupID + usingBlock:^(NSString *collection, NSString *key, id object, NSUInteger index, BOOL *stop) { + if (![object conformsToProtocol:@protocol(OWSReadTracking)]) { + OWSFailDebug(@"Unexpected object in unread messages: %@", [object class]); + return; + } + id unread = (id)object; + if (unread.read) { + [LKLogger print:@"Found an already read message in the * unread * messages list."]; + return; + } + count += 1; + }]; + } + }]; + + return count; + __block NSUInteger numberOfItems; [self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { numberOfItems = [[transaction ext:TSUnreadDatabaseViewExtensionName] numberOfItemsInAllGroups]; diff --git a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m index c51fa0578..a5bdb80d5 100644 --- a/SignalServiceKit/src/Messages/OWSReadReceiptManager.m +++ b/SignalServiceKit/src/Messages/OWSReadReceiptManager.m @@ -491,7 +491,10 @@ NSString *const OWSReadReceiptManagerAreReadReceiptsEnabled = @"areReadReceiptsE return; } - OWSAssertDebug(!possiblyRead.read); + // Under normal circumstances !possiblyRead.read should always evaluate to true at this point, but + // there is a bug that can somehow cause it to be false leading to conversations permanently being + // stuck with "unread" messages. + OWSAssertDebug(possiblyRead.expireStartedAt == 0); if (!possiblyRead.read) { [newlyReadList addObject:possiblyRead];