mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Removed 'useSharedUtilForUserConfig' flag and most legacy config logic
This commit is contained in:
parent
4d098914b2
commit
0e952b40bb
21 changed files with 29 additions and 1018 deletions
|
@ -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 = "<group>"; };
|
||||
7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = "<group>"; };
|
||||
7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
|
||||
7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
|
||||
7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
|
||||
7B93D07527CF1A8900811CB6 /* MockDataGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockDataGenerator.swift; sourceTree = "<group>"; };
|
||||
7B9F71C828470667006DFE7B /* ReactionListSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionListSheet.swift; sourceTree = "<group>"; };
|
||||
|
@ -1771,7 +1768,6 @@
|
|||
FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+TypingIndicators.swift"; sourceTree = "<group>"; };
|
||||
FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+DataExtractionNotification.swift"; sourceTree = "<group>"; };
|
||||
FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ExpirationTimers.swift"; sourceTree = "<group>"; };
|
||||
FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ConfigurationMessages.swift"; sourceTree = "<group>"; };
|
||||
FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+UnsendRequests.swift"; sourceTree = "<group>"; };
|
||||
FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Calls.swift"; sourceTree = "<group>"; };
|
||||
FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+VisibleMessages.swift"; sourceTree = "<group>"; };
|
||||
|
@ -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 */,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,13 +30,6 @@ enum Onboarding {
|
|||
_ requestId: UUID,
|
||||
using dependencies: Dependencies = Dependencies()
|
||||
) -> AnyPublisher<String?, Error> {
|
||||
// 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)
|
||||
|
|
|
@ -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
|
||||
]
|
||||
]
|
||||
)
|
||||
}
|
||||
|
|
|
@ -649,23 +649,18 @@ public enum SMKLegacy {
|
|||
|
||||
@objc(SNConfigurationMessage)
|
||||
internal final class _ConfigurationMessage: _ControlMessage {
|
||||
internal var closedGroups: Set<_CMClosedGroup> = []
|
||||
internal var openGroups: Set<String> = []
|
||||
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<String>? { 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<String>
|
||||
internal let admins: Set<String>
|
||||
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<String>?,
|
||||
let admins = coder.decodeObject(forKey: "admins") as! Set<String>?
|
||||
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)
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<Void, Error> {
|
||||
// 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
|
||||
|
|
|
@ -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<CMClosedGroup> = 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<String> = 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<CMContact> = 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
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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<CMClosedGroup> = []
|
||||
public var openGroups: Set<String> = []
|
||||
public var displayName: String?
|
||||
public var profilePictureUrl: String?
|
||||
public var profileKey: Data?
|
||||
public var contacts: Set<CMContact> = []
|
||||
|
||||
public override var isSelfSendValid: Bool { true }
|
||||
|
||||
|
||||
// MARK: - Initialization
|
||||
|
||||
public init(
|
||||
displayName: String?,
|
||||
profilePictureUrl: String?,
|
||||
profileKey: Data?,
|
||||
closedGroups: Set<CMClosedGroup>,
|
||||
openGroups: Set<String>,
|
||||
contacts: Set<CMContact>
|
||||
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<CodingKeys> = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
closedGroups = ((try? container.decode(Set<CMClosedGroup>.self, forKey: .closedGroups)) ?? [])
|
||||
openGroups = ((try? container.decode(Set<String>.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<CMContact>.self, forKey: .contacts)) ?? [])
|
||||
}
|
||||
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
|
||||
|
||||
var container: KeyedEncodingContainer<CodingKeys> = 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<String>
|
||||
public let admins: Set<String>
|
||||
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<String>,
|
||||
admins: Set<String>,
|
||||
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<CodingKeys> = 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<String>.self, forKey: .members)
|
||||
admins = try container.decode(Set<String>.self, forKey: .admins)
|
||||
expirationTimer = try container.decode(UInt32.self, forKey: .expirationTimer)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container: KeyedEncodingContainer<CodingKeys> = 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<CodingKeys> = 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 ?? "" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -50,9 +50,6 @@ internal extension SessionUtil {
|
|||
publicKey: String,
|
||||
change: (UnsafeMutablePointer<config_object>?) 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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<Bool> = Atomic(false)
|
||||
private static let requiredMigrationsCompleted: Atomic<Bool> = Atomic(false)
|
||||
private static let requiredMigrationIdentifiers: Set<String> = [
|
||||
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<String> = 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<config_object>?) -> 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<ConfigDump> = ((try? ConfigDump.fetchSet(db)) ?? [])
|
||||
let existingDumpVariants: Set<ConfigDump.Variant> = 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<ConfigDump.Variant> 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 }
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -37,7 +37,6 @@ public enum SNUserDefaults {
|
|||
}
|
||||
|
||||
public enum Date: Swift.String {
|
||||
case lastConfigurationSync
|
||||
case lastProfilePictureUpload
|
||||
case lastOpenGroupImageUpdate
|
||||
case lastOpen
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue