Added code to ignore migrating open group messages older than 6 months

This commit is contained in:
Morgan Pretty 2022-06-09 19:00:43 +10:00
parent eeccfb47d5
commit 07f4f7a4ea
9 changed files with 103 additions and 182 deletions

View File

@ -291,8 +291,6 @@
C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EEF09255B49A8007E1867 /* SNProtoEnvelope+Conversion.swift */; };
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA87255A57FC00E217F9 /* TypingIndicators.swift */; };
C32C5A24256DB7DB003C73A2 /* SNUserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB6B255A580F00E217F9 /* SNUserDefaults.swift */; };
C32C5A2D256DB849003C73A2 /* LKGroupUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */; };
C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5A47256DB8F0003C73A2 /* ECKeyPair+Hexadecimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA73255A57FA00E217F9 /* ECKeyPair+Hexadecimal.swift */; };
C32C5A48256DB8F0003C73A2 /* BuildConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */; };
C32C5A88256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = C32C5A87256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift */; };
@ -1405,11 +1403,9 @@
C33FDBB6255A581600E217F9 /* DataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataSource.m; sourceTree = "<group>"; };
C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKKeychainStorage.swift; sourceTree = "<group>"; };
C33FDBC2255A581700E217F9 /* SSKAsserts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SSKAsserts.h; sourceTree = "<group>"; };
C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LKGroupUtilities.h; sourceTree = "<group>"; };
C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSSignalAddress.swift; sourceTree = "<group>"; };
C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = "<group>"; };
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = "<group>"; };
C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = "<group>"; };
C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = "<group>"; };
C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = "<group>"; };
C33FDC03255A581D00E217F9 /* ByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteParser.h; sourceTree = "<group>"; };
@ -2445,15 +2441,6 @@
path = General;
sourceTree = "<group>";
};
B8A582B9258C696200AFD84C /* Messaging */ = {
isa = PBXGroup;
children = (
C33FDBCA255A581700E217F9 /* LKGroupUtilities.h */,
C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */,
);
path = Messaging;
sourceTree = "<group>";
};
B8B3201F258B1A540020074B /* Contacts */ = {
isa = PBXGroup;
children = (
@ -3158,7 +3145,6 @@
B8A582B0258C66C900AFD84C /* General */,
FD9004102818ABB000ABAAF6 /* JobRunner */,
B8A582AF258C665E00AFD84C /* Media */,
B8A582B9258C696200AFD84C /* Messaging */,
B8A582AE258C65D000AFD84C /* Networking */,
B8A582AD258C655E00AFD84C /* PromiseKit */,
FD09796527F6B0A800936362 /* Utilities */,
@ -4027,7 +4013,6 @@
files = (
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */,
C3D9E38A256760390040E4F3 /* OWSFileSystem.h in Headers */,
C32C5A36256DB856003C73A2 /* LKGroupUtilities.h in Headers */,
C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */,
C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */,
B8856DF8256F1633001CE70E /* NSString+SSK.h in Headers */,
@ -5036,7 +5021,6 @@
C352A36D2557858E00338F3E /* NSTimer+Proxying.m in Sources */,
FD09797B27FBB25900936362 /* Updatable.swift in Sources */,
FDCDB8F12817ABE600352A0C /* Optional+Utilities.swift in Sources */,
C32C5A2D256DB849003C73A2 /* LKGroupUtilities.m in Sources */,
7B7CB192271508AD0079FF93 /* CallRingTonePlayer.swift in Sources */,
C3C2ABD22553C6C900C340D1 /* Data+SecureRandom.swift in Sources */,
FD848B8B283DC509000E298B /* PagedDatabaseObserver.swift in Sources */,

View File

@ -412,7 +412,7 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
object: nil
)
notificationCenter.addObserver(self, selector: #selector(handleContactThreadReplaced(_:)), name: .contactThreadReplaced, object: nil) // TODO: Is this needed???
// notificationCenter.addObserver(self, selector: #selector(handleContactThreadReplaced(_:)), name: .contactThreadReplaced, object: nil)
}
override func viewWillAppear(_ animated: Bool) {
@ -1096,87 +1096,88 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
}
@objc private func handleContactThreadReplaced(_ notification: Notification) {
// Ensure the current thread is one of the removed ones
guard let newThreadId: String = notification.userInfo?[NotificationUserInfoKey.threadId] as? String else { return }
guard let removedThreadIds: [String] = notification.userInfo?[NotificationUserInfoKey.removedThreadIds] as? [String] else {
return
}
guard let threadId: String = thread.uniqueId, removedThreadIds.contains(threadId) else { return }
// Then look to swap the current ConversationVC with a replacement one with the new thread
DispatchQueue.main.async {
guard let navController: UINavigationController = self.navigationController else { return }
guard let viewControllerIndex: Int = navController.viewControllers.firstIndex(of: self) else { return }
guard let newThread: TSContactThread = TSContactThread.fetch(uniqueId: newThreadId) else { return }
// Let the view controller know we are replacing the thread
self.isReplacingThread = true
// Create the new ConversationVC and swap the old one out for it
let conversationVC: ConversationVC = ConversationVC(thread: newThread)
let currentlyOnThisScreen: Bool = (navController.topViewController == self)
navController.viewControllers = [
(viewControllerIndex == 0 ?
[] :
navController.viewControllers[0..<viewControllerIndex]
),
[conversationVC],
(viewControllerIndex == (navController.viewControllers.count - 1) ?
[] :
navController.viewControllers[(viewControllerIndex + 1)..<navController.viewControllers.count]
)
].flatMap { $0 }
// If the top vew controller isn't the current one then we need to make sure to swap out child ones as well
if !currentlyOnThisScreen {
let maybeSettingsViewController: UIViewController? = navController
.viewControllers[viewControllerIndex..<navController.viewControllers.count]
.first(where: { $0 is OWSConversationSettingsViewController })
// Update the settings screen (if there is one)
if let settingsViewController: OWSConversationSettingsViewController = maybeSettingsViewController as? OWSConversationSettingsViewController {
settingsViewController.configure(with: newThread, uiDatabaseConnection: OWSPrimaryStorage.shared().uiDatabaseConnection)
}
}
// Try to minimise painful UX issues by keeping the 'first responder' state, current input text and
// cursor position (Unfortunately there doesn't seem to be a way to prevent the keyboard from
// flickering during the swap but other than that it's relatively seamless)
if self.snInputView.inputTextViewIsFirstResponder {
conversationVC.isReplacingThread = true
conversationVC.snInputView.frame = self.snInputView.frame
conversationVC.snInputView.text = self.snInputView.text
conversationVC.snInputView.selectedRange = self.snInputView.selectedRange
// Make the current snInputView invisible and add the new one the the UI
self.snInputView.alpha = 0
self.snInputView.superview?.addSubview(conversationVC.snInputView)
// Add the old first responder to the window so it the keyboard won't get dismissed when the
// OS removes it's parent view from the view hierarchy due to the view controller swap
var maybeOldFirstResponderView: UIView?
if let oldFirstResponderView: UIView = UIResponder.currentFirstResponder() as? UIView {
maybeOldFirstResponderView = oldFirstResponderView
self.view.window?.addSubview(oldFirstResponderView)
}
// On the next run loop setup the first responder state for the new screen and remove the
// old first responder from the window
DispatchQueue.main.async {
UIView.performWithoutAnimation {
conversationVC.isReplacingThread = false
maybeOldFirstResponderView?.resignFirstResponder()
maybeOldFirstResponderView?.removeFromSuperview()
conversationVC.snInputView.removeFromSuperview()
_ = conversationVC.becomeFirstResponder()
conversationVC.snInputView.inputTextViewBecomeFirstResponder()
}
}
}
}
print("ASDASDASD")
// // Ensure the current thread is one of the removed ones
// guard let newThreadId: String = notification.userInfo?[NotificationUserInfoKey.threadId] as? String else { return }
// guard let removedThreadIds: [String] = notification.userInfo?[NotificationUserInfoKey.removedThreadIds] as? [String] else {
// return
// }
// guard let threadId: String = thread.uniqueId, removedThreadIds.contains(threadId) else { return }
//
// // Then look to swap the current ConversationVC with a replacement one with the new thread
// DispatchQueue.main.async {
// guard let navController: UINavigationController = self.navigationController else { return }
// guard let viewControllerIndex: Int = navController.viewControllers.firstIndex(of: self) else { return }
// guard let newThread: TSContactThread = TSContactThread.fetch(uniqueId: newThreadId) else { return }
//
// // Let the view controller know we are replacing the thread
// self.isReplacingThread = true
//
// // Create the new ConversationVC and swap the old one out for it
// let conversationVC: ConversationVC = ConversationVC(thread: newThread)
// let currentlyOnThisScreen: Bool = (navController.topViewController == self)
//
// navController.viewControllers = [
// (viewControllerIndex == 0 ?
// [] :
// navController.viewControllers[0..<viewControllerIndex]
// ),
// [conversationVC],
// (viewControllerIndex == (navController.viewControllers.count - 1) ?
// [] :
// navController.viewControllers[(viewControllerIndex + 1)..<navController.viewControllers.count]
// )
// ].flatMap { $0 }
//
// // If the top vew controller isn't the current one then we need to make sure to swap out child ones as well
// if !currentlyOnThisScreen {
// let maybeSettingsViewController: UIViewController? = navController
// .viewControllers[viewControllerIndex..<navController.viewControllers.count]
// .first(where: { $0 is OWSConversationSettingsViewController })
//
// // Update the settings screen (if there is one)
// if let settingsViewController: OWSConversationSettingsViewController = maybeSettingsViewController as? OWSConversationSettingsViewController {
// settingsViewController.configure(with: newThread, uiDatabaseConnection: OWSPrimaryStorage.shared().uiDatabaseConnection)
// }
// }
//
// // Try to minimise painful UX issues by keeping the 'first responder' state, current input text and
// // cursor position (Unfortunately there doesn't seem to be a way to prevent the keyboard from
// // flickering during the swap but other than that it's relatively seamless)
// if self.snInputView.inputTextViewIsFirstResponder {
// conversationVC.isReplacingThread = true
// conversationVC.snInputView.frame = self.snInputView.frame
// conversationVC.snInputView.text = self.snInputView.text
// conversationVC.snInputView.selectedRange = self.snInputView.selectedRange
//
// // Make the current snInputView invisible and add the new one the the UI
// self.snInputView.alpha = 0
// self.snInputView.superview?.addSubview(conversationVC.snInputView)
//
// // Add the old first responder to the window so it the keyboard won't get dismissed when the
// // OS removes it's parent view from the view hierarchy due to the view controller swap
// var maybeOldFirstResponderView: UIView?
//
// if let oldFirstResponderView: UIView = UIResponder.currentFirstResponder() as? UIView {
// maybeOldFirstResponderView = oldFirstResponderView
// self.view.window?.addSubview(oldFirstResponderView)
// }
//
// // On the next run loop setup the first responder state for the new screen and remove the
// // old first responder from the window
// DispatchQueue.main.async {
// UIView.performWithoutAnimation {
// conversationVC.isReplacingThread = false
// maybeOldFirstResponderView?.resignFirstResponder()
// maybeOldFirstResponderView?.removeFromSuperview()
// conversationVC.snInputView.removeFromSuperview()
//
// _ = conversationVC.becomeFirstResponder()
// conversationVC.snInputView.inputTextViewBecomeFirstResponder()
// }
// }
// }
// }
}
// MARK: - UITableViewDataSource

View File

@ -48,6 +48,5 @@
#import <SignalUtilitiesKit/OWSDispatch.h>
#import <SignalUtilitiesKit/OWSError.h>
#import <SessionUtilitiesKit/OWSFileSystem.h>
#import <SessionUtilitiesKit/LKGroupUtilities.h>
#import <SessionUtilitiesKit/UIImage+OWS.h>
#import <YYImage/YYImage.h>

View File

@ -12,6 +12,7 @@ public enum SMKLegacy {
internal static let contactThreadPrefix = "c"
internal static let groupThreadPrefix = "g"
internal static let closedGroupIdPrefix = "__textsecure_group__!"
internal static let openGroupIdPrefix = "__loki_public_chat_group__!"
internal static let closedGroupKeyPairPrefix = "SNClosedGroupEncryptionKeyPairCollection-"
internal static let databaseMigrationCollection = "OWSDatabaseMigration"

View File

@ -24,6 +24,7 @@ enum _003_YDBToGRDBMigration: Migration {
// MARK: - Read from Legacy Database
let timestampNow: TimeInterval = Date().timeIntervalSince1970
var shouldFailMigration: Bool = false
var legacyMigrations: Set<SMKLegacy._DBMigration> = []
var contacts: Set<SMKLegacy._Contact> = []
@ -210,6 +211,23 @@ enum _003_YDBToGRDBMigration: Migration {
return
}
/// Prune interactions from OpenGroup thread interactions which are older than 6 months
///
/// The old structure for the open group id was `g{base64String(Data(__loki_public_chat_group__!{server.room}))}
/// so we process the uniqueThreadId to see if it matches that
if
interaction.uniqueThreadId.starts(with: SMKLegacy.groupThreadPrefix),
let base64Data: Data = Data(base64Encoded: interaction.uniqueThreadId.substring(from: SMKLegacy.groupThreadPrefix.count)),
let groupIdString: String = String(data: base64Data, encoding: .utf8),
(
groupIdString.starts(with: SMKLegacy.openGroupIdPrefix) ||
groupIdString.starts(with: "http")
),
interaction.timestamp < UInt64(floor((timestampNow - GarbageCollectionJob.approxSixMonthsInSeconds) * 1000))
{
return
}
interactions[interaction.uniqueThreadId] = (interactions[interaction.uniqueThreadId] ?? [])
.appending(interaction)

View File

@ -11,7 +11,7 @@ public enum GarbageCollectionJob: JobExecutor {
public static var maxFailureCount: Int = -1
public static var requiresThreadId: Bool = false
public static let requiresInteractionId: Bool = false
private static let approxSixMonthsInSeconds: TimeInterval = (6 * 30 * 24 * 60 * 60)
public static let approxSixMonthsInSeconds: TimeInterval = (6 * 30 * 24 * 60 * 60)
public static func run(
_ job: Job,

View File

@ -1,23 +0,0 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface LKGroupUtilities : NSObject
+(NSString *)getEncodedOpenGroupID:(NSString *)groupID;
+(NSData *)getEncodedOpenGroupIDAsData:(NSString *)groupID;
+(NSString *)getEncodedClosedGroupID:(NSString *)groupID;
+(NSData *)getEncodedClosedGroupIDAsData:(NSString *)groupID;
+(NSString *)getEncodedMMSGroupID:(NSString *)groupID;
+(NSData *)getEncodedMMSGroupIDAsData:(NSString *)groupID;
+(NSString *)getEncodedGroupID:(NSData *)groupID;
+(NSString *)getDecodedGroupID:(NSData *)groupID;
+(NSData *)getDecodedGroupIDAsData:(NSData *)groupID;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,58 +0,0 @@
#import "LKGroupUtilities.h"
@implementation LKGroupUtilities
#define ClosedGroupPrefix @"__textsecure_group__!"
#define MMSGroupPrefix @"__signal_mms_group__!"
#define OpenGroupPrefix @"__loki_public_chat_group__!"
+(NSString *)getEncodedOpenGroupID:(NSString *)groupID
{
return [OpenGroupPrefix stringByAppendingString:groupID];
}
+(NSData *)getEncodedOpenGroupIDAsData:(NSString *)groupID
{
return [[OpenGroupPrefix stringByAppendingString:groupID] dataUsingEncoding:NSUTF8StringEncoding];
}
+(NSString *)getEncodedClosedGroupID:(NSString *)groupID
{
return [ClosedGroupPrefix stringByAppendingString:groupID];
}
+(NSData *)getEncodedClosedGroupIDAsData:(NSString *)groupID
{
return [[ClosedGroupPrefix stringByAppendingString:groupID] dataUsingEncoding:NSUTF8StringEncoding];
}
+(NSString *)getEncodedMMSGroupID:(NSString *)groupID
{
return [MMSGroupPrefix stringByAppendingString:groupID];
}
+(NSData *)getEncodedMMSGroupIDAsData:(NSString *)groupID
{
return [[MMSGroupPrefix stringByAppendingString:groupID] dataUsingEncoding:NSUTF8StringEncoding];
}
+(NSString *)getEncodedGroupID:(NSData *)groupID
{
return [[NSString alloc] initWithData:groupID encoding:NSUTF8StringEncoding];
}
+(NSString *)getDecodedGroupID:(NSData *)groupID
{
NSString *encodedGroupID = [[NSString alloc] initWithData:groupID encoding:NSUTF8StringEncoding];
if ([encodedGroupID componentsSeparatedByString:@"!"].count > 1) {
return [encodedGroupID componentsSeparatedByString:@"!"][1];
}
return [encodedGroupID componentsSeparatedByString:@"!"][0];
}
+(NSData *)getDecodedGroupIDAsData:(NSData *)groupID
{
return [[LKGroupUtilities getDecodedGroupID:groupID] dataUsingEncoding:NSUTF8StringEncoding];
}
@end

View File

@ -5,7 +5,6 @@ FOUNDATION_EXPORT const unsigned char SessionUtilitiesKitVersionString[];
#import <SessionUtilitiesKit/AppContext.h>
#import <SessionUtilitiesKit/DataSource.h>
#import <SessionUtilitiesKit/LKGroupUtilities.h>
#import <SessionUtilitiesKit/MIMETypeUtil.h>
#import <SessionUtilitiesKit/NSData+Image.h>
#import <SessionUtilitiesKit/NSNotificationCenter+OWS.h>