session-ios/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ConfigurationMessages.swift

214 lines
10 KiB
Swift
Raw Normal View History

Merge branch 'feature/session-id-blinding-part-2' into feature/database-refactor # Conflicts: # Podfile # Podfile.lock # Session.xcodeproj/project.pbxproj # Session/Closed Groups/EditClosedGroupVC.swift # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/Context Menu/ContextMenuVC+Action.swift # Session/Conversations/Context Menu/ContextMenuVC.swift # Session/Conversations/ConversationMessageMapping.swift # Session/Conversations/ConversationSearch.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewItem.h # Session/Conversations/ConversationViewItem.m # Session/Conversations/ConversationViewModel.m # Session/Conversations/Input View/InputView.swift # Session/Conversations/Input View/MentionSelectionView.swift # Session/Conversations/LongTextViewController.swift # Session/Conversations/Message Cells/Content Views/LinkPreviewView.swift # Session/Conversations/Message Cells/MessageCell.swift # Session/Conversations/Message Cells/VisibleMessageCell.swift # Session/Conversations/Settings/OWSConversationSettingsViewController.m # Session/Conversations/Views & Modals/ConversationTitleView.swift # Session/Conversations/Views & Modals/DownloadAttachmentModal.swift # Session/Conversations/Views & Modals/JoinOpenGroupModal.swift # Session/Conversations/Views & Modals/LinkPreviewModal.swift # Session/Conversations/Views & Modals/MessagesTableView.swift # Session/Conversations/Views & Modals/URLModal.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/Message Requests/MessageRequestsViewController.swift # Session/Media Viewing & Editing/MediaDetailViewController.m # Session/Media Viewing & Editing/MediaPageViewController.swift # Session/Meta/AppDelegate.m # Session/Meta/AppDelegate.swift # Session/Meta/AppEnvironment.swift # Session/Meta/Signal-Bridging-Header.h # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Notifications/AppNotifications.swift # Session/Open Groups/JoinOpenGroupVC.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SeedModal.swift # Session/Settings/SettingsVC.swift # Session/Settings/ShareLogsModal.swift # Session/Shared/ConversationCell.swift # Session/Shared/UserSelectionVC.swift # Session/Utilities/BackgroundPoller.swift # Session/Utilities/MentionUtilities.swift # Session/Utilities/MockDataGenerator.swift # SessionMessagingKit/Database/OWSPrimaryStorage.m # SessionMessagingKit/Database/SSKPreferences.swift # SessionMessagingKit/Database/Storage+Contacts.swift # SessionMessagingKit/Database/Storage+Jobs.swift # SessionMessagingKit/Database/Storage+Messaging.swift # SessionMessagingKit/Database/Storage+OpenGroups.swift # SessionMessagingKit/Database/TSDatabaseView.m # SessionMessagingKit/File Server/FileServerAPIV2.swift # SessionMessagingKit/Jobs/AttachmentDownloadJob.swift # SessionMessagingKit/Jobs/AttachmentUploadJob.swift # SessionMessagingKit/Jobs/JobQueue.swift # SessionMessagingKit/Jobs/MessageReceiveJob.swift # SessionMessagingKit/Jobs/MessageSendJob.swift # SessionMessagingKit/Jobs/NotifyPNServerJob.swift # SessionMessagingKit/Messages/Control Messages/ClosedGroupControlMessage.swift # SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift # SessionMessagingKit/Messages/Message+Destination.swift # SessionMessagingKit/Messages/Signal/TSIncomingMessage.h # SessionMessagingKit/Messages/Signal/TSIncomingMessage.m # SessionMessagingKit/Messages/Signal/TSInfoMessage.h # SessionMessagingKit/Messages/Signal/TSInfoMessage.m # SessionMessagingKit/Messages/Signal/TSInteraction.h # SessionMessagingKit/Messages/Signal/TSInteraction.m # SessionMessagingKit/Messages/Signal/TSMessage.h # SessionMessagingKit/Messages/Signal/TSMessage.m # SessionMessagingKit/Open Groups/OpenGroupAPIV2+ObjC.swift # SessionMessagingKit/Open Groups/OpenGroupAPIV2.swift # SessionMessagingKit/Open Groups/OpenGroupManagerV2.swift # SessionMessagingKit/Open Groups/OpenGroupMessageV2.swift # SessionMessagingKit/Sending & Receiving/Mentions/MentionsManager.swift # SessionMessagingKit/Sending & Receiving/MessageReceiver+Decryption.swift # SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift # SessionMessagingKit/Sending & Receiving/MessageReceiver.swift # SessionMessagingKit/Sending & Receiving/MessageSender+ClosedGroups.swift # SessionMessagingKit/Sending & Receiving/MessageSender+Encryption.swift # SessionMessagingKit/Sending & Receiving/MessageSender.swift # SessionMessagingKit/Sending & Receiving/Notifications/NotificationsProtocol.h # SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift # SessionMessagingKit/Sending & Receiving/Pollers/OpenGroupPollerV2.swift # SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift # SessionMessagingKit/Storage.swift # SessionMessagingKit/Threads/Notification+Thread.swift # SessionMessagingKit/Threads/TSContactThread.h # SessionMessagingKit/Threads/TSContactThread.m # SessionMessagingKit/Threads/TSGroupModel.h # SessionMessagingKit/Threads/TSGroupModel.m # SessionMessagingKit/Threads/TSGroupThread.m # SessionMessagingKit/Utilities/General.swift # SessionNotificationServiceExtension/NSENotificationPresenter.swift # SessionNotificationServiceExtension/NotificationServiceExtension.swift # SessionSnodeKit/OnionRequestAPI+Encryption.swift # SessionSnodeKit/OnionRequestAPI.swift # SessionSnodeKit/SnodeAPI.swift # SessionSnodeKit/SnodeMessage.swift # SessionSnodeKit/Storage+SnodeAPI.swift # SessionSnodeKit/Storage.swift # SessionUtilitiesKit/General/Array+Utilities.swift # SessionUtilitiesKit/General/Dictionary+Utilities.swift # SessionUtilitiesKit/General/SNUserDefaults.swift # SessionUtilitiesKit/General/Set+Utilities.swift # SessionUtilitiesKit/Meta/SessionUtilitiesKit.h # SessionUtilitiesKit/Utilities/Optional+Utilities.swift # SessionUtilitiesKit/Utilities/Sodium+Conversion.swift # SignalUtilitiesKit/Configuration.swift # SignalUtilitiesKit/Database/Migrations/OpenGroupServerIdLookupMigration.swift # SignalUtilitiesKit/Messaging/FullTextSearcher.swift # SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift # SignalUtilitiesKit/Profile Pictures/Identicon+ObjC.swift # SignalUtilitiesKit/To Do/OWSProfileManager.m # SignalUtilitiesKit/Utilities/NoopNotificationsManager.swift # SignalUtilitiesKit/Utilities/UIView+OWS.swift
2022-06-08 06:29:51 +02:00
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import GRDB
import Sodium
import SessionUtilitiesKit
extension MessageReceiver {
internal static func handleConfigurationMessage(_ db: Database, message: ConfigurationMessage) throws {
guard !Features.useSharedUtilForUserConfig else {
// TODO: Show warning prompt for X days
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
)
// 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) == .blinded {
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.legacyClosedGroup)
.fetchAll(db))
.defaulting(to: [])
.map { $0.id }
try message.closedGroups.forEach { closedGroup in
guard !existingClosedGroupsIds.contains(closedGroup.publicKey) else { return }
let keyPair: Box.KeyPair = Box.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,
messageSentTimestamp: message.sentTimestamp!
)
}
}
// Open groups
for openGroupURL in message.openGroups {
if let (room, server, publicKey) = OpenGroupManager.parseOpenGroup(from: openGroupURL) {
OpenGroupManager.shared
.add(
db,
roomToken: room,
server: server,
publicKey: publicKey,
calledFromConfigHandling: true
)
Work on the PromiseKit refactor # Conflicts: # Session.xcodeproj/project.pbxproj # Session/Conversations/ConversationVC+Interaction.swift # Session/Home/Message Requests/MessageRequestsViewModel.swift # Session/Notifications/AppNotifications.swift # Session/Notifications/PushRegistrationManager.swift # Session/Notifications/SyncPushTokensJob.swift # Session/Notifications/UserNotificationsAdaptee.swift # Session/Settings/BlockedContactsViewModel.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # Session/Utilities/BackgroundPoller.swift # SessionMessagingKit/Database/Models/ClosedGroup.swift # SessionMessagingKit/File Server/FileServerAPI.swift # SessionMessagingKit/Open Groups/OpenGroupAPI.swift # SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift # SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+UnsendRequests.swift # SessionMessagingKit/Sending & Receiving/Message Handling/MessageSender+ClosedGroups.swift # SessionMessagingKit/Sending & Receiving/MessageSender+Convenience.swift # SessionMessagingKit/Sending & Receiving/MessageSender.swift # SessionMessagingKit/Sending & Receiving/Notifications/PushNotificationAPI.swift # SessionMessagingKit/Sending & Receiving/Pollers/ClosedGroupPoller.swift # SessionMessagingKit/Sending & Receiving/Pollers/CurrentUserPoller.swift # SessionMessagingKit/Sending & Receiving/Pollers/Poller.swift # SessionMessagingKit/Utilities/ProfileManager.swift # SessionSnodeKit/Networking/SnodeAPI.swift # SessionSnodeKit/OnionRequestAPI.swift # SessionUtilitiesKit/Networking/HTTP.swift
2022-11-27 22:32:32 +01:00
.sinkUntilComplete()
}
}
}
}
}