diff --git a/Session/Settings/NukeDataModal.swift b/Session/Settings/NukeDataModal.swift index e44eb22a9..625d85b52 100644 --- a/Session/Settings/NukeDataModal.swift +++ b/Session/Settings/NukeDataModal.swift @@ -188,7 +188,7 @@ final class NukeDataModal: Modal { .subscribe(on: DispatchQueue.global(qos: .default)) .flatMap { results in SnodeAPI - .deleteAllMessages() + .deleteAllMessages(namespace: .all) .map { results.reduce($0) { result, next in result.updated(with: next) } } .eraseToAnyPublisher() } diff --git a/SessionMessagingKit/Database/Migrations/_013_SessionUtilChanges.swift b/SessionMessagingKit/Database/Migrations/_013_SessionUtilChanges.swift index 3923227e2..ea8c28885 100644 --- a/SessionMessagingKit/Database/Migrations/_013_SessionUtilChanges.swift +++ b/SessionMessagingKit/Database/Migrations/_013_SessionUtilChanges.swift @@ -166,6 +166,7 @@ enum _013_SessionUtilChanges: Migration { .notNull() t.column(.timestampMs, .integer) .notNull() + .defaults(to: 0) t.primaryKey([.variant, .publicKey]) } diff --git a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift index ac0a974d4..1a13665af 100644 --- a/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift +++ b/SessionMessagingKit/Sending & Receiving/Message Handling/MessageReceiver+ClosedGroups.swift @@ -78,8 +78,11 @@ extension MessageReceiver { changeTimestampMs: Int64(sentTimestamp) ) else { - // If the closed group already exists then store the encryption keys (just in case - there can be - // some weird edge-cases where we don't have keys we need if we don't store them) + // If the closed group already exists then store the encryption keys (since the config only stores + // the latest key we won't be able to decrypt older messages if we were added to the group within + // the last two weeks and the key has been rotated - unfortunately if the user was added more than + // two weeks ago and the keys were rotated within the last two weeks then we won't be able to decrypt + // messages received before the key rotation) let groupPublicKey: String = publicKeyAsData.toHexString() let receivedTimestamp: TimeInterval = (TimeInterval(SnodeAPI.currentOffsetTimestampMs()) / 1000) let newKeyPair: ClosedGroupKeyPair = ClosedGroupKeyPair( diff --git a/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift b/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift index f6d6e74a5..8fb7d949e 100644 --- a/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift +++ b/SessionMessagingKit/SessionUtil/Config Handling/SessionUtil+Shared.swift @@ -3,6 +3,7 @@ import UIKit import GRDB import SessionUIKit +import SessionSnodeKit import SessionUtil import SessionUtilitiesKit @@ -72,7 +73,7 @@ internal extension SessionUtil { conf: conf, for: variant, publicKey: publicKey, - timestampMs: Int64(Date().timeIntervalSince1970 * 1000) + timestampMs: SnodeAPI.currentOffsetTimestampMs() )?.save(db) return config_needs_push(conf) @@ -342,21 +343,30 @@ public extension SessionUtil { // FIXME: Remove this once `useSharedUtilForUserConfig` is permanent guard SessionUtil.userConfigsEnabled(db) else { return true } + let userPublicKey: String = getUserHexEncodedPublicKey() let configVariant: ConfigDump.Variant = { switch threadVariant { - case .contact: return .contacts + case .contact: return (threadId == userPublicKey ? .userProfile : .contacts) case .legacyGroup, .group, .community: return .userGroups } }() return SessionUtil - .config(for: configVariant, publicKey: getUserHexEncodedPublicKey()) + .config(for: configVariant, publicKey: userPublicKey) .wrappedValue .map { conf in var cThreadId: [CChar] = threadId.cArray.nullTerminated() switch threadVariant { case .contact: + // The 'Note to Self' conversation is stored in the 'userProfile' config + guard threadId != userPublicKey else { + return ( + !visibleOnly || + SessionUtil.shouldBeVisible(priority: user_profile_get_nts_priority(conf)) + ) + } + var contact: contacts_contact = contacts_contact() guard contacts_get(conf, &contact, &cThreadId) else { return false } diff --git a/SessionSnodeKit/Models/DeleteAllMessagesRequest.swift b/SessionSnodeKit/Models/DeleteAllMessagesRequest.swift index bd3526273..5104dbcca 100644 --- a/SessionSnodeKit/Models/DeleteAllMessagesRequest.swift +++ b/SessionSnodeKit/Models/DeleteAllMessagesRequest.swift @@ -13,12 +13,12 @@ extension SnodeAPI { /// /// **Note:** If omitted when sending the request, messages are deleted from the default namespace /// only (namespace 0) - let namespace: SnodeAPI.Namespace? + let namespace: SnodeAPI.Namespace // MARK: - Init public init( - namespace: SnodeAPI.Namespace?, + namespace: SnodeAPI.Namespace, pubkey: String, timestampMs: UInt64, ed25519PublicKey: [UInt8], @@ -39,11 +39,10 @@ extension SnodeAPI { override public func encode(to encoder: Encoder) throws { var container: KeyedEncodingContainer = encoder.container(keyedBy: CodingKeys.self) - // If no namespace is specified it defaults to the default namespace only (namespace - // 0), so instead in this case we want to explicitly delete from `all` namespaces + // The 'all' namespace should be sent through as `all` instead of a numerical value switch namespace { - case .some(let namespace): try container.encode(namespace, forKey: .namespace) - case .none: try container.encode("all", forKey: .namespace) + case .all: try container.encode(namespace.verificationString, forKey: .namespace) + default: try container.encode(namespace, forKey: .namespace) } try super.encode(to: encoder) @@ -58,12 +57,7 @@ extension SnodeAPI { /// The signature must be signed by the ed25519 pubkey in `pubkey` (omitting the leading prefix). /// Must be base64 encoded for json requests; binary for OMQ requests. let verificationBytes: [UInt8] = SnodeAPI.Endpoint.deleteAll.rawValue.bytes - .appending( - contentsOf: (namespace == nil ? - "all" : - namespace?.verificationString - )?.bytes - ) + .appending(contentsOf: namespace.verificationString.bytes) .appending(contentsOf: timestampMs.map { "\($0)" }?.data(using: .ascii)?.bytes) guard diff --git a/SessionSnodeKit/Networking/SnodeAPI.swift b/SessionSnodeKit/Networking/SnodeAPI.swift index a7c8468c1..21acab8da 100644 --- a/SessionSnodeKit/Networking/SnodeAPI.swift +++ b/SessionSnodeKit/Networking/SnodeAPI.swift @@ -939,7 +939,7 @@ public final class SnodeAPI { /// Clears all the user's data from their swarm. Returns a dictionary of snode public key to deletion confirmation. public static func deleteAllMessages( - namespace: SnodeAPI.Namespace? = nil, + namespace: SnodeAPI.Namespace, using dependencies: SSKDependencies = SSKDependencies() ) -> AnyPublisher<[String: Bool], Error> { guard let userED25519KeyPair = Identity.fetchUserEd25519KeyPair() else { @@ -987,7 +987,7 @@ public final class SnodeAPI { /// Clears all the user's data from their swarm. Returns a dictionary of snode public key to deletion confirmation. public static func deleteAllMessages( beforeMs: UInt64, - namespace: SnodeAPI.Namespace? = nil, + namespace: SnodeAPI.Namespace, using dependencies: SSKDependencies = SSKDependencies() ) -> AnyPublisher<[String: Bool], Error> { guard let userED25519KeyPair = Identity.fetchUserEd25519KeyPair() else { diff --git a/SessionSnodeKit/Types/SnodeAPINamespace.swift b/SessionSnodeKit/Types/SnodeAPINamespace.swift index 726377bc2..73dd9182d 100644 --- a/SessionSnodeKit/Types/SnodeAPINamespace.swift +++ b/SessionSnodeKit/Types/SnodeAPINamespace.swift @@ -14,6 +14,8 @@ public extension SnodeAPI { case legacyClosedGroup = -10 + case all = -9999990 + // MARK: Variables var requiresReadAuthentication: Bool { @@ -50,7 +52,7 @@ public extension SnodeAPI { case .configUserProfile, .configContacts, .configConvoInfoVolatile, .configUserGroups, - .configClosedGroupInfo: + .configClosedGroupInfo, .all: return false } } @@ -58,6 +60,7 @@ public extension SnodeAPI { var verificationString: String { switch self { case .`default`: return "" + case .all: return "all" default: return "\(self.rawValue)" } } @@ -85,7 +88,7 @@ public extension SnodeAPI { case .configUserProfile, .configContacts, .configConvoInfoVolatile, .configUserGroups, - .configClosedGroupInfo: + .configClosedGroupInfo, .all: return 1 } }