Export tombstones for gv1 updates in gv2 groups

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal 2024-07-08 10:52:44 -05:00 committed by GitHub
parent 0cf4f3da7f
commit 4f2143500c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 112 additions and 4 deletions

View file

@ -33,6 +33,7 @@ import { explodePromise } from '../../util/explodePromise';
import {
isDirectConversation,
isGroup,
isGroupV1,
isGroupV2,
isMe,
} from '../../util/whatTypeOfConversation';
@ -307,6 +308,11 @@ export class BackupExportStream extends Readable {
window.storage.get('pinnedConversationIds') || [];
for (const { attributes } of window.ConversationController.getAll()) {
if (isGroupV1(attributes)) {
log.warn('backups: skipping gv1 conversation');
continue;
}
const recipientId = this.getRecipientId(attributes);
let pinnedOrder: number | null = null;
@ -773,6 +779,15 @@ export class BackupExportStream extends Readable {
message: MessageAttributesType,
{ aboutMe, callHistoryByCallId, backupLevel }: ToChatItemOptionsType
): Promise<Backups.IChatItem | undefined> {
const conversation = window.ConversationController.get(
message.conversationId
);
if (conversation && isGroupV1(conversation.attributes)) {
log.warn('backups: skipping gv1 message');
return undefined;
}
const chatId = this.getRecipientId({ id: message.conversationId });
if (chatId === undefined) {
log.warn('backups: message chat not found');
@ -1324,9 +1339,21 @@ export class BackupExportStream extends Readable {
return { kind: NonBubbleResultKind.Drop };
}
// Create a GV2 tombstone for a deprecated GV1 notification
if (isGroupUpdate(message)) {
// GV1 is deprecated.
return { kind: NonBubbleResultKind.Drop };
updateMessage.groupChange = {
updates: [
{
genericGroupUpdate: {
updaterAci: message.sourceServiceId
? this.serviceIdToBytes(message.sourceServiceId)
: undefined,
},
},
],
};
return { kind: NonBubbleResultKind.Directionless, patch };
}
if (isUnsupportedMessage(message)) {

View file

@ -8,13 +8,22 @@ import type { ConversationModel } from '../../models/conversations';
import { GiftBadgeStates } from '../../components/conversation/Message';
import Data from '../../sql/Client';
import { getRandomBytes } from '../../Crypto';
import * as Bytes from '../../Bytes';
import { generateAci } from '../../types/ServiceId';
import { ReadStatus } from '../../messages/MessageReadStatus';
import { SeenStatus } from '../../MessageSeenStatus';
import { loadCallsHistory } from '../../services/callHistoryLoader';
import { setupBasics, symmetricRoundtripHarness, OUR_ACI } from './helpers';
import { ID_V1_LENGTH } from '../../groups';
import {
setupBasics,
asymmetricRoundtripHarness,
symmetricRoundtripHarness,
OUR_ACI,
} from './helpers';
const CONTACT_A = generateAci();
const GV1_ID = Bytes.toBinary(getRandomBytes(ID_V1_LENGTH));
const BADGE_RECEIPT =
'AEpyZxbRBT+T5PQw9Wcx1QE2aFvL7LoLir9V4UF09Kk9qiP4SpIlHdlWHrAICy6F' +
@ -27,6 +36,7 @@ const BADGE_RECEIPT =
describe('backup/bubble messages', () => {
let contactA: ConversationModel;
let gv1: ConversationModel;
beforeEach(async () => {
await Data._removeAllMessages();
@ -41,6 +51,14 @@ describe('backup/bubble messages', () => {
{ systemGivenName: 'CONTACT_A' }
);
gv1 = await window.ConversationController.getOrCreateAndWait(
GV1_ID,
'group',
{
groupVersion: 1,
}
);
await loadCallsHistory();
});
@ -383,4 +401,26 @@ describe('backup/bubble messages', () => {
},
]);
});
it('drops gv1 messages', async () => {
await asymmetricRoundtripHarness(
[
{
conversationId: gv1.id,
id: generateGuid(),
type: 'incoming',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
timestamp: 3,
sourceServiceId: CONTACT_A,
body: 'd',
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
},
],
[]
);
});
});

View file

@ -17,7 +17,12 @@ import { DurationInSeconds } from '../../util/durations';
import { ReadStatus } from '../../messages/MessageReadStatus';
import { SeenStatus } from '../../MessageSeenStatus';
import { loadCallsHistory } from '../../services/callHistoryLoader';
import { setupBasics, symmetricRoundtripHarness, OUR_ACI } from './helpers';
import {
setupBasics,
asymmetricRoundtripHarness,
symmetricRoundtripHarness,
OUR_ACI,
} from './helpers';
const CONTACT_A = generateAci();
const GROUP_ID = Bytes.toBase64(getRandomBytes(32));
@ -501,4 +506,40 @@ describe('backup/non-bubble messages', () => {
},
]);
});
it('creates a tombstone for gv1 update in gv2 group', async () => {
await asymmetricRoundtripHarness(
[
{
conversationId: group.id,
id: generateGuid(),
type: 'incoming',
received_at: 1,
received_at_ms: 1,
sourceServiceId: CONTACT_A,
sourceDevice: 1,
sent_at: 1,
timestamp: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
group_update: {},
},
],
[
{
conversationId: group.id,
id: 'does not matter',
type: 'group-v2-change',
groupV2Change: {
details: [{ type: 'summary' }],
from: CONTACT_A,
},
received_at: 1,
sent_at: 1,
sourceServiceId: CONTACT_A,
timestamp: 1,
},
]
);
});
});