From a3dcbf887e1cac3ddead2323f155b1ee8ca28ff8 Mon Sep 17 00:00:00 2001 From: Scott Nonnenberg Date: Tue, 11 Aug 2026 23:53:11 +1000 Subject: [PATCH] Additional cleanup on group/distributionList deletion --- pnpm-lock.yaml | 1 + pnpm-workspace.yaml | 1 + ts/models/conversations.preload.ts | 11 +++++++++ ts/services/storageRecordOps.preload.ts | 23 +++++++++++++++---- .../ducks/storyDistributionLists.preload.ts | 14 +++++++++++ ts/util/sendToGroup.preload.ts | 2 +- 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 84eb79f827..3ad396e05e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,7 @@ overrides: electron@<39.8.10: ^39.8.10 electron@<39.8.9: ^39.8.9 ip-address@<=10.3.0: ^10.3.1 + nanoid@<3.3.17: 3.3.18 pnpmfileChecksum: sha256-bByyW+G0/ld7ZSgtIlcAVRHgcUTBCQ31JLSwI1rhzys= diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 6587bda31a..0e9db85bc9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -69,6 +69,7 @@ overrides: electron@<39.8.10: ^39.8.10 electron@<39.8.9: ^39.8.9 ip-address@<=10.3.0: ^10.3.1 + nanoid@<3.3.17: 3.3.18 allowUnusedPatches: false ignorePatchFailures: false diff --git a/ts/models/conversations.preload.ts b/ts/models/conversations.preload.ts index 0823f1475a..690a916478 100644 --- a/ts/models/conversations.preload.ts +++ b/ts/models/conversations.preload.ts @@ -188,6 +188,7 @@ import * as Errors from '../types/errors.std.ts'; import { isMessageUnread } from '../util/isMessageUnread.std.ts'; import type { SenderKeyTargetType } from '../util/sendToGroup.preload.ts'; import { + getOurAddress, resetSenderKey, sendContentMessageToGroup, } from '../util/sendToGroup.preload.ts'; @@ -286,6 +287,7 @@ import { canConversationOnlyBeMutedAlways } from '../conversations/canConversati import { keyTransparency } from '../services/keyTransparency.preload.ts'; import type { PollSource } from '../messageModifiers/Polls.preload.ts'; import { isSignalServiceId } from '../types/SignalConversation.std.ts'; +import { QualifiedAddress } from '../types/QualifiedAddress.std.ts'; const { compact, isNumber, throttle, debounce } = lodash; @@ -5540,6 +5542,15 @@ export class ConversationModel { (this.get('left') || this.get('terminated')) ) { await safeCleanupAvatarFiles(this.attributes); + const senderKeyInfo = this.get('senderKeyInfo'); + if (senderKeyInfo?.distributionId) { + const ourAddress = getOurAddress(); + const ourAci = itemStorage.user.getCheckedAci(); + await signalProtocolStore.removeSenderKey( + new QualifiedAddress(ourAci, ourAddress), + senderKeyInfo.distributionId + ); + } this.set(GROUP_CLEANUP_FIELDS); } diff --git a/ts/services/storageRecordOps.preload.ts b/ts/services/storageRecordOps.preload.ts index 41c7fe87fa..41514a0392 100644 --- a/ts/services/storageRecordOps.preload.ts +++ b/ts/services/storageRecordOps.preload.ts @@ -134,6 +134,8 @@ import { toNumber } from '../util/toNumber.std.ts'; import { MAX_VALUE } from '../util/long.std.ts'; import { isKnownProtoEnumMember } from '../util/isKnownProtoEnumMember.std.ts'; import { Emoji } from '../axo/emoji.std.ts'; +import { getOurAddress } from '../util/sendToGroup.preload.ts'; +import { QualifiedAddress } from '../types/QualifiedAddress.std.ts'; const { isEqual } = lodash; @@ -2118,6 +2120,7 @@ export async function mergeStoryDistributionListRecord( const localStoryDistributionList = await DataReader.getStoryDistributionWithMembers(listId); + let senderKeyInfo = localStoryDistributionList?.senderKeyInfo; const details = logRecordChanges( localStoryDistributionList == null @@ -2141,14 +2144,24 @@ export async function mergeStoryDistributionListRecord( remoteListMembers = []; } - if (storyDistributionListRecord.$unknown) { - details.push('adding unknown fields'); - } - const deletedAtTimestamp = getTimestampFromLong( storyDistributionListRecord.deletedAtTimestamp ); + if (senderKeyInfo?.distributionId && deletedAtTimestamp) { + const ourAddress = getOurAddress(); + const ourAci = itemStorage.user.getCheckedAci(); + await signalProtocolStore.removeSenderKey( + new QualifiedAddress(ourAci, ourAddress), + senderKeyInfo.distributionId + ); + senderKeyInfo = undefined; + } + + if (storyDistributionListRecord.$unknown) { + details.push('adding unknown fields'); + } + const storyDistribution: StoryDistributionWithMembersType = { id: listId, name: storyDistributionListRecord.name, @@ -2156,7 +2169,7 @@ export async function mergeStoryDistributionListRecord( allowsReplies: storyDistributionListRecord.allowsReplies, isBlockList: storyDistributionListRecord.isBlockList, members: remoteListMembers, - senderKeyInfo: localStoryDistributionList?.senderKeyInfo, + senderKeyInfo, storageID, storageVersion, diff --git a/ts/state/ducks/storyDistributionLists.preload.ts b/ts/state/ducks/storyDistributionLists.preload.ts index cbf1112181..9c942b4b64 100644 --- a/ts/state/ducks/storyDistributionLists.preload.ts +++ b/ts/state/ducks/storyDistributionLists.preload.ts @@ -20,6 +20,9 @@ import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions.s import { useBoundActions } from '../../hooks/useBoundActions.std.ts'; import { itemStorage } from '../../textsecure/Storage.preload.ts'; import { strictAssert } from '../../util/assert.std.ts'; +import { signalProtocolStore } from '../../SignalProtocolStore.preload.ts'; +import { getOurAddress } from '../../util/sendToGroup.preload.ts'; +import { QualifiedAddress } from '../../types/QualifiedAddress.std.ts'; const { omit } = lodash; @@ -217,12 +220,15 @@ function deleteDistributionList( return; } + const { senderKeyInfo } = storyDistribution; + await DataWriter.modifyStoryDistributionWithMembers( { ...storyDistribution, deletedAtTimestamp, name: '', storageNeedsSync: true, + senderKeyInfo: undefined, }, { toAdd: [], @@ -237,6 +243,14 @@ function deleteDistributionList( await Promise.all( storiesToDelete.map(story => deleteStoryForEveryone(stories, story)) ); + if (senderKeyInfo?.distributionId) { + const ourAddress = getOurAddress(); + const ourAci = itemStorage.user.getCheckedAci(); + await signalProtocolStore.removeSenderKey( + new QualifiedAddress(ourAci, ourAddress), + senderKeyInfo.distributionId + ); + } log.info('deleteDistributionList: list deleted', listId); diff --git a/ts/util/sendToGroup.preload.ts b/ts/util/sendToGroup.preload.ts index 7445e69ab3..506911b2a6 100644 --- a/ts/util/sendToGroup.preload.ts +++ b/ts/util/sendToGroup.preload.ts @@ -1408,7 +1408,7 @@ export function _analyzeSenderKeyDevices( }; } -function getOurAddress(): Address { +export function getOurAddress(): Address { const ourAci = itemStorage.user.getCheckedAci(); const ourDeviceId = itemStorage.user.getDeviceId(); if (!ourDeviceId) {