diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index cac7103f7..6795e47d3 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -128,7 +128,6 @@ 7B8C44C528B49DDA00FBE25F /* NewConversationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */; }; 7B8D5FC428332600008324D9 /* VisibleMessage+Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */; }; 7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */; }; - 7B93D07027CF194000811CB6 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */; }; 7B93D07127CF194000811CB6 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */; }; 7B93D07727CF1A8A00811CB6 /* MockDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D07527CF1A8900811CB6 /* MockDataGenerator.swift */; }; 7B9F71C928470667006DFE7B /* ReactionListSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9F71C828470667006DFE7B /* ReactionListSheet.swift */; }; @@ -652,7 +651,6 @@ FD5C72F9284F0E880029977D /* MessageReceiver+TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */; }; FD5C72FB284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */; }; FD5C72FD284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */; }; - FD5C72FF284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */; }; FD5C7301284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */; }; FD5C7303284F0FA50029977D /* MessageReceiver+Calls.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */; }; FD5C7305284F0FF30029977D /* MessageReceiver+VisibleMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */; }; @@ -1237,7 +1235,6 @@ 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationVC.swift; sourceTree = ""; }; 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = ""; }; 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = ""; }; - 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = ""; }; 7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = ""; }; 7B93D07527CF1A8900811CB6 /* MockDataGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockDataGenerator.swift; sourceTree = ""; }; 7B9F71C828470667006DFE7B /* ReactionListSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionListSheet.swift; sourceTree = ""; }; @@ -1771,7 +1768,6 @@ FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+TypingIndicators.swift"; sourceTree = ""; }; FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+DataExtractionNotification.swift"; sourceTree = ""; }; FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ExpirationTimers.swift"; sourceTree = ""; }; - FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ConfigurationMessages.swift"; sourceTree = ""; }; FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+UnsendRequests.swift"; sourceTree = ""; }; FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Calls.swift"; sourceTree = ""; }; FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+VisibleMessages.swift"; sourceTree = ""; }; @@ -2730,7 +2726,6 @@ C34A977325A3E34A00852C71 /* ClosedGroupControlMessage.swift */, FD8ECF8A2935DB4B00C0D1BB /* SharedConfigMessage.swift */, C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */, - 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */, B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */, C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */, 7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */, @@ -4002,7 +3997,6 @@ FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */, FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */, FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */, - FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */, FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */, FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */, FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */, @@ -5864,7 +5858,6 @@ FD23CE222A661D000000B97C /* OpenGroupAPI+Crypto.swift in Sources */, FD245C652850665400B966DD /* ClosedGroupControlMessage.swift in Sources */, FDC4387827B5C35400C60D73 /* SendMessageRequest.swift in Sources */, - 7B93D07027CF194000811CB6 /* ConfigurationMessage+Convenience.swift in Sources */, FD5C72FD284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift in Sources */, C32C5A88256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift in Sources */, B8D0A25925E367AC00C1835E /* Notification+MessageReceiver.swift in Sources */, @@ -5874,7 +5867,6 @@ C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */, FD716E682850318E00C96BF4 /* CallMode.swift in Sources */, FD09799527FE7B8E00936362 /* Interaction.swift in Sources */, - FD5C72FF284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift in Sources */, FD37EA0D28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift in Sources */, 7BAA7B6628D2DE4700AE1489 /* _009_OpenGroupPermission.swift in Sources */, FDC4380927B31D4E00C60D73 /* OpenGroupAPIError.swift in Sources */, diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 50a7b6151..21c87c49a 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -283,14 +283,6 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData // Start polling if needed (i.e. if the user just created or restored their Session ID) if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate { appDelegate.startPollersIfNeeded() - - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - if !SessionUtil.userConfigsEnabled { - // Do this only if we created a new Session ID, or if we already received the initial configuration message - if UserDefaults.standard[.hasSyncedInitialConfiguration] { - appDelegate.syncConfigurationIfNeeded() - } - } } // Onion request path countries cache diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index a11d1f669..df4a88901 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -522,7 +522,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD startPollersIfNeeded() if CurrentAppContext().isMainApp { - syncConfigurationIfNeeded() handleAppActivatedWithOngoingCallIfNeeded() } } @@ -868,36 +867,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD presentingVC.present(callVC, animated: true, completion: nil) } - - // MARK: - Config Sync - - func syncConfigurationIfNeeded() { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard !SessionUtil.userConfigsEnabled else { return } - - let lastSync: Date = (UserDefaults.standard[.lastConfigurationSync] ?? .distantPast) - - guard Date().timeIntervalSince(lastSync) > (7 * 24 * 60 * 60) else { return } // Sync every 2 days - - Storage.shared - .writeAsync( - updates: { db in - ConfigurationSyncJob.enqueue(db, publicKey: getUserHexEncodedPublicKey(db)) - }, - completion: { _, result in - switch result { - case .failure: break - case .success: - // Only update the 'lastConfigurationSync' timestamp if we have done the - // first sync (Don't want a new device config sync to override config - // syncs from other devices) - if UserDefaults.standard[.hasSyncedInitialConfiguration] { - UserDefaults.standard[.lastConfigurationSync] = Date() - } - } - } - ) - } } // MARK: - LifecycleMethod diff --git a/Session/Onboarding/Onboarding.swift b/Session/Onboarding/Onboarding.swift index 123b2fd33..1a5956d29 100644 --- a/Session/Onboarding/Onboarding.swift +++ b/Session/Onboarding/Onboarding.swift @@ -30,13 +30,6 @@ enum Onboarding { _ requestId: UUID, using dependencies: Dependencies = Dependencies() ) -> AnyPublisher { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled else { - return Just(nil) - .setFailureType(to: Error.self) - .eraseToAnyPublisher() - } - let userPublicKey: String = getUserHexEncodedPublicKey() return SnodeAPI.getSwarm(for: userPublicKey) diff --git a/SessionMessagingKit/Configuration.swift b/SessionMessagingKit/Configuration.swift index 0aa4f5d37..314a5ca7e 100644 --- a/SessionMessagingKit/Configuration.swift +++ b/SessionMessagingKit/Configuration.swift @@ -31,14 +31,8 @@ public enum SNMessagingKit: MigratableTarget { // Just to make the external API _011_AddPendingReadReceipts.self, _012_AddFTSIfNeeded.self, _013_SessionUtilChanges.self, - // Wait until the feature is turned on before doing the migration that generates - // the config dump data - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - (Features.useSharedUtilForUserConfig(db) ? - _014_GenerateInitialUserConfigDumps.self : - (nil as Migration.Type?) - ) - ].compactMap { $0 } + _014_GenerateInitialUserConfigDumps.self + ] ] ) } diff --git a/SessionMessagingKit/Database/LegacyDatabase/SMKLegacy.swift b/SessionMessagingKit/Database/LegacyDatabase/SMKLegacy.swift index 7967974ac..f950fde8f 100644 --- a/SessionMessagingKit/Database/LegacyDatabase/SMKLegacy.swift +++ b/SessionMessagingKit/Database/LegacyDatabase/SMKLegacy.swift @@ -649,23 +649,18 @@ public enum SMKLegacy { @objc(SNConfigurationMessage) internal final class _ConfigurationMessage: _ControlMessage { - internal var closedGroups: Set<_CMClosedGroup> = [] - internal var openGroups: Set = [] internal var displayName: String? internal var profilePictureURL: String? internal var profileKey: Data? - internal var contacts: Set<_CMContact> = [] // MARK: NSCoding public required init?(coder: NSCoder) { super.init(coder: coder) - if let closedGroups = coder.decodeObject(forKey: "closedGroups") as! Set<_CMClosedGroup>? { self.closedGroups = closedGroups } - if let openGroups = coder.decodeObject(forKey: "openGroups") as! Set? { self.openGroups = openGroups } + if let displayName = coder.decodeObject(forKey: "displayName") as! String? { self.displayName = displayName } if let profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String? { self.profilePictureURL = profilePictureURL } if let profileKey = coder.decodeObject(forKey: "profileKey") as! Data? { self.profileKey = profileKey } - if let contacts = coder.decodeObject(forKey: "contacts") as! Set<_CMContact>? { self.contacts = contacts } } public override func encode(with coder: NSCoder) { @@ -679,126 +674,12 @@ public enum SMKLegacy { ConfigurationMessage( displayName: displayName, profilePictureUrl: profilePictureURL, - profileKey: profileKey, - closedGroups: closedGroups - .map { $0.toNonLegacy() } - .asSet(), - openGroups: openGroups, - contacts: contacts - .map { $0.toNonLegacy() } - .asSet() + profileKey: profileKey ) ) } } - // MARK: - Config Message Closed Group - - @objc(CMClosedGroup) - internal final class _CMClosedGroup: NSObject, NSCoding { - internal let publicKey: String - internal let name: String - internal let encryptionKeyPair: SUKLegacy.KeyPair - internal let members: Set - internal let admins: Set - internal let expirationTimer: UInt32 - - // MARK: NSCoding - - public required init?(coder: NSCoder) { - guard - let publicKey = coder.decodeObject(forKey: "publicKey") as! String?, - let name = coder.decodeObject(forKey: "name") as! String?, - let encryptionKeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as! SUKLegacy.KeyPair?, - let members = coder.decodeObject(forKey: "members") as! Set?, - let admins = coder.decodeObject(forKey: "admins") as! Set? - else { return nil } - - self.publicKey = publicKey - self.name = name - self.encryptionKeyPair = encryptionKeyPair - self.members = members - self.admins = admins - self.expirationTimer = (coder.decodeObject(forKey: "expirationTimer") as? UInt32 ?? 0) - } - - public func encode(with coder: NSCoder) { - fatalError("encode(with:) should never be called for legacy types") - } - - // MARK: Non-Legacy Conversion - - internal func toNonLegacy() -> ConfigurationMessage.CMClosedGroup { - return ConfigurationMessage.CMClosedGroup( - publicKey: publicKey, - name: name, - encryptionKeyPublicKey: encryptionKeyPair.publicKey, - encryptionKeySecretKey: encryptionKeyPair.privateKey, - members: members, - admins: admins, - expirationTimer: expirationTimer - ) - } - } - - // MARK: - Config Message Contact - - @objc(SNConfigurationMessageContact) - internal final class _CMContact: NSObject, NSCoding { - internal var publicKey: String? - internal var displayName: String? - internal var profilePictureURL: String? - internal var profileKey: Data? - - internal var hasIsApproved: Bool - internal var isApproved: Bool - internal var hasIsBlocked: Bool - internal var isBlocked: Bool - internal var hasDidApproveMe: Bool - internal var didApproveMe: Bool - - // MARK: NSCoding - - public required init?(coder: NSCoder) { - guard - let publicKey = coder.decodeObject(forKey: "publicKey") as! String?, - let displayName = coder.decodeObject(forKey: "displayName") as! String? - else { return nil } - - self.publicKey = publicKey - self.displayName = displayName - self.profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String? - self.profileKey = coder.decodeObject(forKey: "profileKey") as! Data? - self.hasIsApproved = (coder.decodeObject(forKey: "hasIsApproved") as? Bool ?? false) - self.isApproved = (coder.decodeObject(forKey: "isApproved") as? Bool ?? false) - self.hasIsBlocked = (coder.decodeObject(forKey: "hasIsBlocked") as? Bool ?? false) - self.isBlocked = (coder.decodeObject(forKey: "isBlocked") as? Bool ?? false) - self.hasDidApproveMe = (coder.decodeObject(forKey: "hasDidApproveMe") as? Bool ?? false) - self.didApproveMe = (coder.decodeObject(forKey: "didApproveMe") as? Bool ?? false) - } - - public func encode(with coder: NSCoder) { - fatalError("encode(with:) should never be called for legacy types") - } - - // MARK: Non-Legacy Conversion - - internal func toNonLegacy() -> ConfigurationMessage.CMContact { - return ConfigurationMessage.CMContact( - publicKey: publicKey, - displayName: displayName, - profilePictureUrl: profilePictureURL, - profileKey: profileKey, - hasIsApproved: hasIsApproved, - isApproved: isApproved, - hasIsBlocked: hasIsBlocked, - isBlocked: isBlocked, - hasDidApproveMe: hasDidApproveMe, - didApproveMe: didApproveMe - ) - } - } - // MARK: - Unsend Request @objc(SNUnsendRequest) diff --git a/SessionMessagingKit/Database/Migrations/_003_YDBToGRDBMigration.swift b/SessionMessagingKit/Database/Migrations/_003_YDBToGRDBMigration.swift index 8918c1c9b..4873cb107 100644 --- a/SessionMessagingKit/Database/Migrations/_003_YDBToGRDBMigration.swift +++ b/SessionMessagingKit/Database/Migrations/_003_YDBToGRDBMigration.swift @@ -1851,14 +1851,6 @@ enum _003_YDBToGRDBMigration: Migration { SMKLegacy._ConfigurationMessage.self, forClassName: "SNConfigurationMessage" ) - NSKeyedUnarchiver.setClass( - SMKLegacy._CMClosedGroup.self, - forClassName: "SNClosedGroup" - ) - NSKeyedUnarchiver.setClass( - SMKLegacy._CMContact.self, - forClassName: "SNConfigurationMessage.SNConfigurationMessageContact" - ) NSKeyedUnarchiver.setClass( SMKLegacy._UnsendRequest.self, forClassName: "SNUnsendRequest" diff --git a/SessionMessagingKit/Database/Migrations/_014_GenerateInitialUserConfigDumps.swift b/SessionMessagingKit/Database/Migrations/_014_GenerateInitialUserConfigDumps.swift index 04b565056..442431a70 100644 --- a/SessionMessagingKit/Database/Migrations/_014_GenerateInitialUserConfigDumps.swift +++ b/SessionMessagingKit/Database/Migrations/_014_GenerateInitialUserConfigDumps.swift @@ -6,8 +6,6 @@ import SessionUtil import SessionUtilitiesKit /// This migration goes through the current state of the database and generates config dumps for the user config types -/// -/// **Note:** This migration won't be run until the `useSharedUtilForUserConfig` feature flag is enabled enum _014_GenerateInitialUserConfigDumps: Migration { static let target: TargetMigrations.Identifier = .messagingKit static let identifier: String = "GenerateInitialUserConfigDumps" diff --git a/SessionMessagingKit/Jobs/Types/ConfigurationSyncJob.swift b/SessionMessagingKit/Jobs/Types/ConfigurationSyncJob.swift index f19caf473..4b1d8011f 100644 --- a/SessionMessagingKit/Jobs/Types/ConfigurationSyncJob.swift +++ b/SessionMessagingKit/Jobs/Types/ConfigurationSyncJob.swift @@ -20,10 +20,7 @@ public enum ConfigurationSyncJob: JobExecutor { deferred: @escaping (Job, Dependencies) -> (), using dependencies: Dependencies ) { - guard - SessionUtil.userConfigsEnabled, - Identity.userCompletedRequiredOnboarding() - else { return success(job, true, dependencies) } + guard Identity.userCompletedRequiredOnboarding() else { return success(job, true, dependencies) } // It's possible for multiple ConfigSyncJob's with the same target (user/group) to try to run at the // same time since as soon as one is started we will enqueue a second one, rather than adding dependencies @@ -200,35 +197,6 @@ public extension ConfigurationSyncJob { publicKey: String, dependencies: Dependencies = Dependencies() ) { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled(db) else { - // If we don't have a userKeyPair (or name) yet then there is no need to sync the - // configuration as the user doesn't fully exist yet (this will get triggered on - // the first launch of a fresh install due to the migrations getting run and a few - // times during onboarding) - guard - Identity.userCompletedRequiredOnboarding(db), - let legacyConfigMessage: Message = try? ConfigurationMessage.getCurrent(db) - else { return } - - let publicKey: String = getUserHexEncodedPublicKey(db) - - dependencies.jobRunner.add( - db, - job: Job( - variant: .messageSend, - threadId: publicKey, - details: MessageSendJob.Details( - destination: Message.Destination.contact(publicKey: publicKey), - message: legacyConfigMessage - ) - ), - canStartJob: true, - using: dependencies - ) - return - } - // Upsert a config sync job if needed dependencies.jobRunner.upsert( db, @@ -268,30 +236,6 @@ public extension ConfigurationSyncJob { } static func run(using dependencies: Dependencies = Dependencies()) -> AnyPublisher { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled else { - return Storage.shared - .writePublisher { db -> MessageSender.PreparedSendData in - // If we don't have a userKeyPair yet then there is no need to sync the configuration - // as the user doesn't exist yet (this will get triggered on the first launch of a - // fresh install due to the migrations getting run) - guard Identity.userCompletedRequiredOnboarding(db) else { throw StorageError.generic } - - let publicKey: String = getUserHexEncodedPublicKey(db, using: dependencies) - - return try MessageSender.preparedSendData( - db, - message: try ConfigurationMessage.getCurrent(db), - to: Message.Destination.contact(publicKey: publicKey), - namespace: .default, - interactionId: nil, - using: dependencies - ) - } - .flatMap { MessageSender.sendImmediate(data: $0, using: dependencies) } - .eraseToAnyPublisher() - } - // Trigger the job emitting the result when completed return Deferred { Future { resolver in diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift deleted file mode 100644 index 6c8c5977a..000000000 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation -import GRDB -import SessionUtilitiesKit - -extension ConfigurationMessage { - public static func getCurrent(_ db: Database) throws -> ConfigurationMessage { - let currentUserProfile: Profile = Profile.fetchOrCreateCurrentUser(db) - let displayName: String = currentUserProfile.name - let profilePictureUrl: String? = currentUserProfile.profilePictureUrl - let profileKey: Data? = currentUserProfile.profileEncryptionKey - let closedGroups: Set = try ClosedGroup.fetchAll(db) - .compactMap { closedGroup -> CMClosedGroup? in - guard let latestKeyPair: ClosedGroupKeyPair = try closedGroup.fetchLatestKeyPair(db) else { - return nil - } - - return CMClosedGroup( - publicKey: closedGroup.publicKey, - name: closedGroup.name, - encryptionKeyPublicKey: latestKeyPair.publicKey, - encryptionKeySecretKey: latestKeyPair.secretKey, - members: try closedGroup.members - .select(GroupMember.Columns.profileId) - .asRequest(of: String.self) - .fetchSet(db), - admins: try closedGroup.admins - .select(GroupMember.Columns.profileId) - .asRequest(of: String.self) - .fetchSet(db), - expirationTimer: (try? DisappearingMessagesConfiguration - .fetchOne(db, id: closedGroup.threadId) - .map { ($0.isEnabled ? UInt32($0.durationSeconds) : 0) }) - .defaulting(to: 0) - ) - } - .asSet() - // The default room promise creates an OpenGroup with an empty `roomToken` value, - // we don't want to start a poller for this as the user hasn't actually joined a room - let openGroups: Set = try OpenGroup - .filter(OpenGroup.Columns.roomToken != "") - .filter(OpenGroup.Columns.isActive) - .fetchAll(db) - .compactMap { openGroup in - SessionUtil.communityUrlFor( - server: openGroup.server, - roomToken: openGroup.roomToken, - publicKey: openGroup.publicKey - ) - } - .asSet() - let contacts: Set = try Contact - .filter(Contact.Columns.id != currentUserProfile.id) - .fetchAll(db) - .map { contact -> CMContact in - // Can just default the 'hasX' values to true as they will be set to this - // when converting to proto anyway - let profile: Profile? = try? Profile.fetchOne(db, id: contact.id) - - return CMContact( - publicKey: contact.id, - displayName: (profile?.name ?? contact.id), - profilePictureUrl: profile?.profilePictureUrl, - profileKey: profile?.profileEncryptionKey, - hasIsApproved: true, - isApproved: contact.isApproved, - hasIsBlocked: true, - isBlocked: contact.isBlocked, - hasDidApproveMe: true, - didApproveMe: contact.didApproveMe - ) - } - .asSet() - - return ConfigurationMessage( - displayName: displayName, - profilePictureUrl: profilePictureUrl, - profileKey: profileKey, - closedGroups: closedGroups, - openGroups: openGroups, - contacts: contacts - ) - } -} diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift index 44977dd52..d161ef92e 100644 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift +++ b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage.swift @@ -6,361 +6,80 @@ import SessionUtilitiesKit public final class ConfigurationMessage: ControlMessage { private enum CodingKeys: String, CodingKey { - case closedGroups - case openGroups case displayName case profilePictureUrl case profileKey - case contacts } - public var closedGroups: Set = [] - public var openGroups: Set = [] public var displayName: String? public var profilePictureUrl: String? public var profileKey: Data? - public var contacts: Set = [] public override var isSelfSendValid: Bool { true } - + // MARK: - Initialization public init( displayName: String?, profilePictureUrl: String?, - profileKey: Data?, - closedGroups: Set, - openGroups: Set, - contacts: Set + profileKey: Data? ) { super.init() - + self.displayName = displayName self.profilePictureUrl = profilePictureUrl self.profileKey = profileKey - self.closedGroups = closedGroups - self.openGroups = openGroups - self.contacts = contacts } - + // MARK: - Codable - + required init(from decoder: Decoder) throws { try super.init(from: decoder) - + let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) - - closedGroups = ((try? container.decode(Set.self, forKey: .closedGroups)) ?? []) - openGroups = ((try? container.decode(Set.self, forKey: .openGroups)) ?? []) + displayName = try? container.decode(String.self, forKey: .displayName) profilePictureUrl = try? container.decode(String.self, forKey: .profilePictureUrl) profileKey = try? container.decode(Data.self, forKey: .profileKey) - contacts = ((try? container.decode(Set.self, forKey: .contacts)) ?? []) } - + public override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) - + var container: KeyedEncodingContainer = encoder.container(keyedBy: CodingKeys.self) - - try container.encodeIfPresent(closedGroups, forKey: .closedGroups) - try container.encodeIfPresent(openGroups, forKey: .openGroups) + try container.encodeIfPresent(displayName, forKey: .displayName) try container.encodeIfPresent(profilePictureUrl, forKey: .profilePictureUrl) try container.encodeIfPresent(profileKey, forKey: .profileKey) - try container.encodeIfPresent(contacts, forKey: .contacts) } // MARK: - Proto Conversion public override class func fromProto(_ proto: SNProtoContent, sender: String) -> ConfigurationMessage? { guard let configurationProto = proto.configurationMessage else { return nil } + let displayName = configurationProto.displayName let profilePictureUrl = configurationProto.profilePicture let profileKey = configurationProto.profileKey - let closedGroups = Set(configurationProto.closedGroups.compactMap { CMClosedGroup.fromProto($0) }) - let openGroups = Set(configurationProto.openGroups) - let contacts = Set(configurationProto.contacts.compactMap { CMContact.fromProto($0) }) - + return ConfigurationMessage( displayName: displayName, profilePictureUrl: profilePictureUrl, - profileKey: profileKey, - closedGroups: closedGroups, - openGroups: openGroups, - contacts: contacts + profileKey: profileKey ) } - public override func toProto(_ db: Database) -> SNProtoContent? { - let configurationProto = SNProtoConfigurationMessage.builder() - if let displayName = displayName { configurationProto.setDisplayName(displayName) } - if let profilePictureUrl = profilePictureUrl { configurationProto.setProfilePicture(profilePictureUrl) } - if let profileKey = profileKey { configurationProto.setProfileKey(profileKey) } - configurationProto.setClosedGroups(closedGroups.compactMap { $0.toProto() }) - configurationProto.setOpenGroups([String](openGroups)) - configurationProto.setContacts(contacts.compactMap { $0.toProto() }) - let contentProto = SNProtoContent.builder() - do { - contentProto.setConfigurationMessage(try configurationProto.build()) - return try contentProto.build() - } catch { - SNLog("Couldn't construct configuration proto from: \(self).") - return nil - } - } + public override func toProto(_ db: Database) -> SNProtoContent? { return nil } // MARK: - Description public var description: String { """ - ConfigurationMessage( - closedGroups: \([CMClosedGroup](closedGroups).prettifiedDescription), - openGroups: \([String](openGroups).prettifiedDescription), + LegacyConfigurationMessage( displayName: \(displayName ?? "null"), profilePictureUrl: \(profilePictureUrl ?? "null"), - profileKey: \(profileKey?.toHexString() ?? "null"), - contacts: \([CMContact](contacts).prettifiedDescription) + profileKey: \(profileKey?.toHexString() ?? "null") ) """ } } - -// MARK: - Closed Group - -extension ConfigurationMessage { - public struct CMClosedGroup: Codable, Hashable, CustomStringConvertible { - private enum CodingKeys: String, CodingKey { - case publicKey - case name - case encryptionKeyPublicKey - case encryptionKeySecretKey - case members - case admins - case expirationTimer - } - - public let publicKey: String - public let name: String - public let encryptionKeyPublicKey: Data - public let encryptionKeySecretKey: Data - public let members: Set - public let admins: Set - public let expirationTimer: UInt32 - - public var isValid: Bool { !members.isEmpty && !admins.isEmpty } - - // MARK: - Initialization - - public init( - publicKey: String, - name: String, - encryptionKeyPublicKey: Data, - encryptionKeySecretKey: Data, - members: Set, - admins: Set, - expirationTimer: UInt32 - ) { - self.publicKey = publicKey - self.name = name - self.encryptionKeyPublicKey = encryptionKeyPublicKey - self.encryptionKeySecretKey = encryptionKeySecretKey - self.members = members - self.admins = admins - self.expirationTimer = expirationTimer - } - - // MARK: - Codable - - public init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) - - publicKey = try container.decode(String.self, forKey: .publicKey) - name = try container.decode(String.self, forKey: .name) - encryptionKeyPublicKey = try container.decode(Data.self, forKey: .encryptionKeyPublicKey) - encryptionKeySecretKey = try container.decode(Data.self, forKey: .encryptionKeySecretKey) - members = try container.decode(Set.self, forKey: .members) - admins = try container.decode(Set.self, forKey: .admins) - expirationTimer = try container.decode(UInt32.self, forKey: .expirationTimer) - } - - public func encode(to encoder: Encoder) throws { - var container: KeyedEncodingContainer = encoder.container(keyedBy: CodingKeys.self) - - try container.encode(publicKey, forKey: .publicKey) - try container.encode(name, forKey: .name) - try container.encode(encryptionKeyPublicKey, forKey: .encryptionKeyPublicKey) - try container.encode(encryptionKeySecretKey, forKey: .encryptionKeySecretKey) - try container.encode(members, forKey: .members) - try container.encode(admins, forKey: .admins) - try container.encode(expirationTimer, forKey: .expirationTimer) - } - - public static func fromProto(_ proto: SNProtoConfigurationMessageClosedGroup) -> CMClosedGroup? { - guard - let publicKey = proto.publicKey?.toHexString(), - let name = proto.name, - let encryptionKeyPairAsProto = proto.encryptionKeyPair - else { return nil } - - let members = Set(proto.members.map { $0.toHexString() }) - let admins = Set(proto.admins.map { $0.toHexString() }) - let expirationTimer = proto.expirationTimer - let result = CMClosedGroup( - publicKey: publicKey, - name: name, - encryptionKeyPublicKey: encryptionKeyPairAsProto.publicKey, - encryptionKeySecretKey: encryptionKeyPairAsProto.privateKey, - members: members, - admins: admins, - expirationTimer: expirationTimer - ) - - guard result.isValid else { return nil } - return result - } - - public func toProto() -> SNProtoConfigurationMessageClosedGroup? { - guard isValid else { return nil } - let result = SNProtoConfigurationMessageClosedGroup.builder() - result.setPublicKey(Data(hex: publicKey)) - result.setName(name) - do { - let encryptionKeyPairAsProto = try SNProtoKeyPair.builder( - publicKey: encryptionKeyPublicKey, - privateKey: encryptionKeySecretKey - ).build() - result.setEncryptionKeyPair(encryptionKeyPairAsProto) - } catch { - SNLog("Couldn't construct closed group proto from: \(self).") - return nil - } - result.setMembers(members.map { Data(hex: $0) }) - result.setAdmins(admins.map { Data(hex: $0) }) - result.setExpirationTimer(expirationTimer) - do { - return try result.build() - } catch { - SNLog("Couldn't construct closed group proto from: \(self).") - return nil - } - } - - public var description: String { name } - } -} - -// MARK: - Contact - -extension ConfigurationMessage { - public struct CMContact: Codable, Hashable, CustomStringConvertible { - private enum CodingKeys: String, CodingKey { - case publicKey - case displayName - case profilePictureUrl - case profileKey - - case hasIsApproved - case isApproved - case hasIsBlocked - case isBlocked - case hasDidApproveMe - case didApproveMe - } - - public var publicKey: String? - public var displayName: String? - public var profilePictureUrl: String? - public var profileKey: Data? - - public var hasIsApproved: Bool - public var isApproved: Bool - public var hasIsBlocked: Bool - public var isBlocked: Bool - public var hasDidApproveMe: Bool - public var didApproveMe: Bool - - public var isValid: Bool { publicKey != nil && displayName != nil } - - public init( - publicKey: String?, - displayName: String?, - profilePictureUrl: String?, - profileKey: Data?, - hasIsApproved: Bool, - isApproved: Bool, - hasIsBlocked: Bool, - isBlocked: Bool, - hasDidApproveMe: Bool, - didApproveMe: Bool - ) { - self.publicKey = publicKey - self.displayName = displayName - self.profilePictureUrl = profilePictureUrl - self.profileKey = profileKey - self.hasIsApproved = hasIsApproved - self.isApproved = isApproved - self.hasIsBlocked = hasIsBlocked - self.isBlocked = isBlocked - self.hasDidApproveMe = hasDidApproveMe - self.didApproveMe = didApproveMe - } - - // MARK: - Codable - - public init(from decoder: Decoder) throws { - let container: KeyedDecodingContainer = try decoder.container(keyedBy: CodingKeys.self) - - publicKey = try? container.decode(String.self, forKey: .publicKey) - displayName = try? container.decode(String.self, forKey: .displayName) - profilePictureUrl = try? container.decode(String.self, forKey: .profilePictureUrl) - profileKey = try? container.decode(Data.self, forKey: .profileKey) - - hasIsApproved = try container.decode(Bool.self, forKey: .hasIsApproved) - isApproved = try container.decode(Bool.self, forKey: .isApproved) - hasIsBlocked = try container.decode(Bool.self, forKey: .hasIsBlocked) - isBlocked = try container.decode(Bool.self, forKey: .isBlocked) - hasDidApproveMe = try container.decode(Bool.self, forKey: .hasDidApproveMe) - didApproveMe = try container.decode(Bool.self, forKey: .didApproveMe) - } - - public static func fromProto(_ proto: SNProtoConfigurationMessageContact) -> CMContact? { - let result: CMContact = CMContact( - publicKey: proto.publicKey.toHexString(), - displayName: proto.name, - profilePictureUrl: proto.profilePicture, - profileKey: proto.profileKey, - hasIsApproved: proto.hasIsApproved, - isApproved: proto.isApproved, - hasIsBlocked: proto.hasIsBlocked, - isBlocked: proto.isBlocked, - hasDidApproveMe: proto.hasDidApproveMe, - didApproveMe: proto.didApproveMe - ) - - guard result.isValid else { return nil } - return result - } - - public func toProto() -> SNProtoConfigurationMessageContact? { - guard isValid else { return nil } - guard let publicKey = publicKey, let displayName = displayName else { return nil } - let result = SNProtoConfigurationMessageContact.builder(publicKey: Data(hex: publicKey), name: displayName) - if let profilePictureUrl = profilePictureUrl { result.setProfilePicture(profilePictureUrl) } - if let profileKey = profileKey { result.setProfileKey(profileKey) } - - if hasIsApproved { result.setIsApproved(isApproved) } - if hasIsBlocked { result.setIsBlocked(isBlocked) } - if hasDidApproveMe { result.setDidApproveMe(didApproveMe) } - - do { - return try result.build() - } catch { - SNLog("Couldn't construct contact proto from: \(self).") - return nil - } - } - - public var description: String { displayName ?? "" } - } -} diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ConfigurationMessages.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ConfigurationMessages.swift deleted file mode 100644 index 390bf8381..000000000 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ConfigurationMessages.swift +++ /dev/null @@ -1,235 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import Foundation -import GRDB -import Sodium -import SessionUIKit -import SessionUtilitiesKit - -extension MessageReceiver { - internal static func handleLegacyConfigurationMessage( - _ db: Database, - message: ConfigurationMessage, - using dependencies: Dependencies - ) throws { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard !SessionUtil.userConfigsEnabled(db) else { - TopBannerController.show(warning: .outdatedUserConfig) - return - } - - let userPublicKey = getUserHexEncodedPublicKey(db) - - guard message.sender == userPublicKey else { return } - - SNLog("Configuration message received.") - - // Note: `message.sentTimestamp` is in ms (convert to TimeInterval before converting to - // seconds to maintain the accuracy) - let isInitialSync: Bool = (!UserDefaults.standard[.hasSyncedInitialConfiguration]) - let messageSentTimestamp: TimeInterval = TimeInterval((message.sentTimestamp ?? 0) / 1000) - let lastConfigTimestamp: TimeInterval = UserDefaults.standard[.lastConfigurationSync] - .defaulting(to: Date(timeIntervalSince1970: 0)) - .timeIntervalSince1970 - - // Handle user profile changes - try ProfileManager.updateProfileIfNeeded( - db, - publicKey: userPublicKey, - name: message.displayName, - avatarUpdate: { - guard - let profilePictureUrl: String = message.profilePictureUrl, - let profileKey: Data = message.profileKey - else { return .none } - - return .updateTo( - url: profilePictureUrl, - key: profileKey, - fileName: nil - ) - }(), - sentTimestamp: messageSentTimestamp, - calledFromConfigHandling: true, - using: dependencies - ) - - // Create a contact for the current user if needed (also force-approve the current user - // in case the account got into a weird state or restored directly from a migration) - let userContact: Contact = Contact.fetchOrCreate(db, id: userPublicKey) - - if !userContact.isTrusted || !userContact.isApproved || !userContact.didApproveMe { - try userContact.save(db) - try Contact - .filter(id: userPublicKey) - .updateAll( // Handling a config update so don't use `updateAllAndConfig` - db, - Contact.Columns.isTrusted.set(to: true), - Contact.Columns.isApproved.set(to: true), - Contact.Columns.didApproveMe.set(to: true) - ) - } - - if isInitialSync || messageSentTimestamp > lastConfigTimestamp { - if isInitialSync { - UserDefaults.standard[.hasSyncedInitialConfiguration] = true - NotificationCenter.default.post(name: .initialConfigurationMessageReceived, object: nil) - } - - UserDefaults.standard[.lastConfigurationSync] = Date(timeIntervalSince1970: messageSentTimestamp) - - // Contacts - try message.contacts.forEach { contactInfo in - guard let sessionId: String = contactInfo.publicKey else { return } - - // If the contact is a blinded contact then only add them if they haven't already been - // unblinded - if SessionId.Prefix(from: sessionId) == .blinded15 || SessionId.Prefix(from: sessionId) == .blinded25 { - let hasUnblindedContact: Bool = BlindedIdLookup - .filter(BlindedIdLookup.Columns.blindedId == sessionId) - .filter(BlindedIdLookup.Columns.sessionId != nil) - .isNotEmpty(db) - - if hasUnblindedContact { - return - } - } - - // Note: We only update the contact and profile records if the data has actually changed - // in order to avoid triggering UI updates for every thread on the home screen - let contact: Contact = Contact.fetchOrCreate(db, id: sessionId) - let profile: Profile = Profile.fetchOrCreate(db, id: sessionId) - - if - profile.name != contactInfo.displayName || - profile.profilePictureUrl != contactInfo.profilePictureUrl || - profile.profileEncryptionKey != contactInfo.profileKey - { - try profile.save(db) - try Profile - .filter(id: sessionId) - .updateAll( // Handling a config update so don't use `updateAllAndConfig` - db, - [ - Profile.Columns.name.set(to: contactInfo.displayName), - (contactInfo.profilePictureUrl == nil ? nil : - Profile.Columns.profilePictureUrl.set(to: contactInfo.profilePictureUrl) - ), - (contactInfo.profileKey == nil ? nil : - Profile.Columns.profileEncryptionKey.set(to: contactInfo.profileKey) - ) - ].compactMap { $0 } - ) - } - - /// We only update these values if the proto actually has values for them (this is to prevent an - /// edge case where an old client could override the values with default values since they aren't included) - /// - /// **Note:** Since message requests have no reverse, we should only handle setting `isApproved` - /// and `didApproveMe` to `true`. This may prevent some weird edge cases where a config message - /// swapping `isApproved` and `didApproveMe` to `false` - if - (contactInfo.hasIsApproved && (contact.isApproved != contactInfo.isApproved)) || - (contactInfo.hasIsBlocked && (contact.isBlocked != contactInfo.isBlocked)) || - (contactInfo.hasDidApproveMe && (contact.didApproveMe != contactInfo.didApproveMe)) - { - try contact.save(db) - try Contact - .filter(id: sessionId) - .updateAll( // Handling a config update so don't use `updateAllAndConfig` - db, - [ - (!contactInfo.hasIsApproved || !contactInfo.isApproved ? nil : - Contact.Columns.isApproved.set(to: true) - ), - (!contactInfo.hasIsBlocked ? nil : - Contact.Columns.isBlocked.set(to: contactInfo.isBlocked) - ), - (!contactInfo.hasDidApproveMe || !contactInfo.didApproveMe ? nil : - Contact.Columns.didApproveMe.set(to: contactInfo.didApproveMe) - ) - ].compactMap { $0 } - ) - } - - // If the contact is blocked - if contactInfo.hasIsBlocked && contactInfo.isBlocked { - // If this message changed them to the blocked state and there is an existing thread - // associated with them that is a message request thread then delete it (assume - // that the current user had deleted that message request) - if - contactInfo.isBlocked != contact.isBlocked, // 'contact.isBlocked' will be the old value - let thread: SessionThread = try? SessionThread.fetchOne(db, id: sessionId), - thread.isMessageRequest(db) - { - _ = try thread.delete(db) - } - } - } - - // Closed groups - // - // Note: Only want to add these for initial sync to avoid re-adding closed groups the user - // intentionally left (any closed groups joined since the first processed sync message should - // get added via the 'handleNewClosedGroup' method anyway as they will have come through in the - // past two weeks) - if isInitialSync { - let existingClosedGroupsIds: [String] = (try? SessionThread - .filter(SessionThread.Columns.variant == SessionThread.Variant.legacyGroup) - .fetchAll(db)) - .defaulting(to: []) - .map { $0.id } - - try message.closedGroups.forEach { closedGroup in - guard !existingClosedGroupsIds.contains(closedGroup.publicKey) else { return } - - let keyPair: KeyPair = KeyPair( - publicKey: closedGroup.encryptionKeyPublicKey.bytes, - secretKey: closedGroup.encryptionKeySecretKey.bytes - ) - - try MessageReceiver.handleNewClosedGroup( - db, - groupPublicKey: closedGroup.publicKey, - name: closedGroup.name, - encryptionKeyPair: keyPair, - members: [String](closedGroup.members), - admins: [String](closedGroup.admins), - expirationTimer: closedGroup.expirationTimer, - formationTimestampMs: message.sentTimestamp!, - calledFromConfigHandling: false, // Legacy config isn't an issue - using: dependencies - ) - } - } - - // Open groups - for openGroupURL in message.openGroups { - if let (room, server, publicKey) = SessionUtil.parseCommunity(url: openGroupURL) { - let successfullyAddedGroup: Bool = OpenGroupManager.shared - .add( - db, - roomToken: room, - server: server, - publicKey: publicKey, - calledFromConfigHandling: true - ) - - if successfullyAddedGroup { - db.afterNextTransactionNested { _ in - OpenGroupManager.shared.performInitialRequestsAfterAdd( - successfullyAddedGroup: successfullyAddedGroup, - roomToken: room, - server: server, - publicKey: publicKey, - calledFromConfigHandling: false - ) - .subscribe(on: OpenGroupAPI.workQueue) - .sinkUntilComplete() - } - } - } - } - } - } -} diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index e1d1b8be8..5310c536b 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -3,6 +3,7 @@ import Foundation import GRDB import Sodium +import SessionUIKit import SessionUtilitiesKit import SessionSnodeKit @@ -242,13 +243,6 @@ public enum MessageReceiver { message: message ) - case let message as ConfigurationMessage: - try MessageReceiver.handleLegacyConfigurationMessage( - db, - message: message, - using: dependencies - ) - case let message as UnsendRequest: try MessageReceiver.handleUnsendRequest( db, @@ -282,6 +276,7 @@ public enum MessageReceiver { ) // SharedConfigMessages should be handled by the 'SharedUtil' instead of this + case is ConfigurationMessage: TopBannerController.show(warning: .outdatedUserConfig) case is SharedConfigMessage: throw MessageReceiverError.invalidSharedConfigMessageHandling default: fatalError() diff --git a/SessionMessagingKit/Sending & Receiving/Notification+MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/Notification+MessageReceiver.swift index d5c5b48fa..df890e31d 100644 --- a/SessionMessagingKit/Sending & Receiving/Notification+MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/Notification+MessageReceiver.swift @@ -3,18 +3,9 @@ import Foundation public extension Notification.Name { - - // FIXME: Remove once `useSharedUtilForUserConfig` is permanent - static let initialConfigurationMessageReceived = Notification.Name("initialConfigurationMessageReceived") static let missedCall = Notification.Name("missedCall") } public extension Notification.Key { static let senderId = Notification.Key("senderId") } - -@objc public extension NSNotification { - - // FIXME: Remove once `useSharedUtilForUserConfig` is permanent - @objc static let initialConfigurationMessageReceived = Notification.Name.initialConfigurationMessageReceived.rawValue as NSString -} diff --git a/SessionMessagingKit/Sending & Receiving/Pollers/CurrentUserPoller.swift b/SessionMessagingKit/Sending & Receiving/Pollers/CurrentUserPoller.swift index 3e62ad28c..bf69dd878 100644 --- a/SessionMessagingKit/Sending & Receiving/Pollers/CurrentUserPoller.swift +++ b/SessionMessagingKit/Sending & Receiving/Pollers/CurrentUserPoller.swift @@ -14,12 +14,7 @@ public final class CurrentUserPoller: Poller { // MARK: - Settings - override var namespaces: [SnodeAPI.Namespace] { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled else { return [.default] } - - return CurrentUserPoller.namespaces - } + override var namespaces: [SnodeAPI.Namespace] { CurrentUserPoller.namespaces } /// After polling a given snode this many times we always switch to a new one. /// diff --git a/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift b/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift index 909ea9ce7..25b2606e6 100644 --- a/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift +++ b/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift @@ -50,9 +50,6 @@ internal extension SessionUtil { publicKey: String, change: (UnsafeMutablePointer?) throws -> () ) throws { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled(db, ignoreRequirementsForRunningMigrations: true) else { return } - // Since we are doing direct memory manipulation we are using an `Atomic` // type which has blocking access in it's `mutate` closure let needsPush: Bool @@ -307,9 +304,6 @@ internal extension SessionUtil { targetConfig: ConfigDump.Variant, changeTimestampMs: Int64 ) -> Bool { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled(db) else { return true } - let targetPublicKey: String = { switch targetConfig { default: return getUserHexEncodedPublicKey(db) @@ -349,10 +343,7 @@ public extension SessionUtil { threadVariant: SessionThread.Variant, visibleOnly: Bool ) -> Bool { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled(db) else { return true } - - let userPublicKey: String = getUserHexEncodedPublicKey() + let userPublicKey: String = getUserHexEncodedPublicKey(db) let configVariant: ConfigDump.Variant = { switch threadVariant { case .contact: return (threadId == userPublicKey ? .userProfile : .contacts) diff --git a/SessionMessagingKit/SessionUtil/Database/QueryInterfaceRequest+Utilities.swift b/SessionMessagingKit/SessionUtil/Database/QueryInterfaceRequest+Utilities.swift index a8be039fe..a7285604e 100644 --- a/SessionMessagingKit/SessionUtil/Database/QueryInterfaceRequest+Utilities.swift +++ b/SessionMessagingKit/SessionUtil/Database/QueryInterfaceRequest+Utilities.swift @@ -91,11 +91,7 @@ public extension QueryInterfaceRequest where RowDecoder: FetchableRecord & Table let updatedData: [RowDecoder] = try self.updateAndFetchAll(db, assignments.map { $0.assignment }) // Then check if any of the changes could affect the config - guard - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - SessionUtil.userConfigsEnabled(db, ignoreRequirementsForRunningMigrations: true), - SessionUtil.assignmentsRequireConfigUpdate(assignments) - else { return updatedData } + guard SessionUtil.assignmentsRequireConfigUpdate(assignments) else { return updatedData } defer { // If we changed a column that requires a config update then we may as well automatically diff --git a/SessionMessagingKit/SessionUtil/SessionUtil.swift b/SessionMessagingKit/SessionUtil/SessionUtil.swift index d933238a5..a353e8ed1 100644 --- a/SessionMessagingKit/SessionUtil/SessionUtil.swift +++ b/SessionMessagingKit/SessionUtil/SessionUtil.swift @@ -6,25 +6,6 @@ import SessionSnodeKit import SessionUtil import SessionUtilitiesKit -// MARK: - Features - -public extension Features { - static func useSharedUtilForUserConfig(_ db: Database? = nil) -> Bool { - guard Date().timeIntervalSince1970 < 1690761600 else { return true } - guard !SessionUtil.hasCheckedMigrationsCompleted.wrappedValue else { - return SessionUtil.userConfigsEnabledIgnoringFeatureFlag - } - - if let db: Database = db { - return SessionUtil.refreshingUserConfigsEnabled(db) - } - - return Storage.shared - .read { db in SessionUtil.refreshingUserConfigsEnabled(db) } - .defaulting(to: false) - } -} - // MARK: - SessionUtil public enum SessionUtil { @@ -70,10 +51,7 @@ public enum SessionUtil { /// Returns `true` if there is a config which needs to be pushed, but returns `false` if the configs are all up to date or haven't been /// loaded yet (eg. fresh install) public static var needsSync: Bool { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled else { return false } - - return configStore + configStore .wrappedValue .contains { _, atomicConf in guard atomicConf.wrappedValue != nil else { return false } @@ -84,56 +62,6 @@ public enum SessionUtil { public static var libSessionVersion: String { String(cString: LIBSESSION_UTIL_VERSION_STR) } - fileprivate static let hasCheckedMigrationsCompleted: Atomic = Atomic(false) - private static let requiredMigrationsCompleted: Atomic = Atomic(false) - private static let requiredMigrationIdentifiers: Set = [ - TargetMigrations.Identifier.messagingKit.key(with: _013_SessionUtilChanges.self), - TargetMigrations.Identifier.messagingKit.key(with: _014_GenerateInitialUserConfigDumps.self) - ] - - public static var userConfigsEnabled: Bool { - return userConfigsEnabled(nil) - } - - public static func userConfigsEnabled(_ db: Database?) -> Bool { - Features.useSharedUtilForUserConfig(db) && - SessionUtil.userConfigsEnabledIgnoringFeatureFlag - } - - public static var userConfigsEnabledIgnoringFeatureFlag: Bool { - SessionUtil.requiredMigrationsCompleted.wrappedValue - } - - internal static func userConfigsEnabled( - _ db: Database, - ignoreRequirementsForRunningMigrations: Bool - ) -> Bool { - // First check if we are enabled regardless of what we want to ignore - guard - Features.useSharedUtilForUserConfig(db), - !SessionUtil.requiredMigrationsCompleted.wrappedValue, - !SessionUtil.refreshingUserConfigsEnabled(db), - ignoreRequirementsForRunningMigrations, - let currentlyRunningMigration: (identifier: TargetMigrations.Identifier, migration: Migration.Type) = Storage.shared.currentlyRunningMigration - else { return true } - - let nonIgnoredMigrationIdentifiers: Set = SessionUtil.requiredMigrationIdentifiers - .removing(currentlyRunningMigration.identifier.key(with: currentlyRunningMigration.migration)) - - return Storage.appliedMigrationIdentifiers(db) - .isSuperset(of: nonIgnoredMigrationIdentifiers) - } - - @discardableResult public static func refreshingUserConfigsEnabled(_ db: Database) -> Bool { - let result: Bool = Storage.appliedMigrationIdentifiers(db) - .isSuperset(of: SessionUtil.requiredMigrationIdentifiers) - - requiredMigrationsCompleted.mutate { $0 = result } - hasCheckedMigrationsCompleted.mutate { $0 = true } - - return result - } - internal static func lastError(_ conf: UnsafeMutablePointer?) -> String { return (conf?.pointee.last_error.map { String(cString: $0) } ?? "Unknown") } @@ -141,9 +69,6 @@ public enum SessionUtil { // MARK: - Loading public static func clearMemoryState() { - // Ensure we have a loaded state before we continue - guard !SessionUtil.configStore.wrappedValue.isEmpty else { return } - SessionUtil.configStore.mutate { confStore in confStore.removeAll() } @@ -169,9 +94,6 @@ public enum SessionUtil { return } - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled(db, ignoreRequirementsForRunningMigrations: true) else { return } - // Retrieve the existing dumps from the database let existingDumps: Set = ((try? ConfigDump.fetchSet(db)) ?? []) let existingDumpVariants: Set = existingDumps @@ -395,9 +317,6 @@ public enum SessionUtil { } public static func configHashes(for publicKey: String) -> [String] { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled else { return [] } - return Storage.shared .read { db -> Set in guard Identity.userExists(db) else { return [] } @@ -437,8 +356,6 @@ public enum SessionUtil { messages: [SharedConfigMessage], publicKey: String ) throws { - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - guard SessionUtil.userConfigsEnabled(db) else { return } guard !messages.isEmpty else { return } guard !publicKey.isEmpty else { throw MessageReceiverError.noThread } diff --git a/SessionMessagingKit/Utilities/ProfileManager.swift b/SessionMessagingKit/Utilities/ProfileManager.swift index 7266b30f6..e8407c8c7 100644 --- a/SessionMessagingKit/Utilities/ProfileManager.swift +++ b/SessionMessagingKit/Utilities/ProfileManager.swift @@ -509,8 +509,7 @@ public struct ProfileManager { // Name if let name: String = name, !name.isEmpty, name != profile.name { - // FIXME: Remove the `userConfigsEnabled` check once `useSharedUtilForUserConfig` is permanent - if sentTimestamp > profile.lastNameUpdate || (isCurrentUser && (calledFromConfigHandling || !SessionUtil.userConfigsEnabled(db))) { + if sentTimestamp > profile.lastNameUpdate || (isCurrentUser && calledFromConfigHandling) { profileChanges.append(Profile.Columns.name.set(to: name)) profileChanges.append(Profile.Columns.lastNameUpdate.set(to: sentTimestamp)) } @@ -520,8 +519,7 @@ public struct ProfileManager { var avatarNeedsDownload: Bool = false var targetAvatarUrl: String? = nil - // FIXME: Remove the `userConfigsEnabled` check once `useSharedUtilForUserConfig` is permanent - if sentTimestamp > profile.lastProfilePictureUpdate || (isCurrentUser && (calledFromConfigHandling || !SessionUtil.userConfigsEnabled(db))) { + if sentTimestamp > profile.lastProfilePictureUpdate || (isCurrentUser && calledFromConfigHandling) { switch avatarUpdate { case .none: break case .uploadImageData: preconditionFailure("Invalid options for this function") @@ -571,25 +569,6 @@ public struct ProfileManager { profileChanges ) } - // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent - else if !SessionUtil.userConfigsEnabled(db) { - // If we have a contact record for the profile (ie. it's a synced profile) then - // should should send an updated config message, otherwise we should just update - // the local state (the shared util has this logic build in to it's handling) - if (try? Contact.exists(db, id: publicKey)) == true { - try Profile - .filter(id: publicKey) - .updateAllAndConfig(db, profileChanges) - } - else { - try Profile - .filter(id: publicKey) - .updateAll( - db, - profileChanges - ) - } - } else { try Profile .filter(id: publicKey) diff --git a/SessionUtilitiesKit/General/SNUserDefaults.swift b/SessionUtilitiesKit/General/SNUserDefaults.swift index bc55e8231..7564c9753 100644 --- a/SessionUtilitiesKit/General/SNUserDefaults.swift +++ b/SessionUtilitiesKit/General/SNUserDefaults.swift @@ -37,7 +37,6 @@ public enum SNUserDefaults { } public enum Date: Swift.String { - case lastConfigurationSync case lastProfilePictureUpload case lastOpenGroupImageUpdate case lastOpen diff --git a/SignalUtilitiesKit/Utilities/AppSetup.swift b/SignalUtilitiesKit/Utilities/AppSetup.swift index 58f0c6856..f656ba41d 100644 --- a/SignalUtilitiesKit/Utilities/AppSetup.swift +++ b/SignalUtilitiesKit/Utilities/AppSetup.swift @@ -84,12 +84,6 @@ public enum AppSetup { ) } - // Refresh the migration state for 'SessionUtil' so it's logic can start running - // correctly when called (doing this here instead of automatically via the - // `SessionUtil.userConfigsEnabled` property to avoid having to use the correct - // method when calling within a database read/write closure) - Storage.shared.read { db in SessionUtil.refreshingUserConfigsEnabled(db) } - migrationsCompletion(result, (needsConfigSync || SessionUtil.needsSync)) // The 'if' is only there to prevent the "variable never read" warning from showing