2023-08-16 20:54:39 +00:00
|
|
|
// Copyright 2023 Signal Messenger, LLC
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
|
|
import { assert } from 'chai';
|
|
|
|
import { v4 as generateGuid } from 'uuid';
|
|
|
|
|
2024-07-22 18:16:33 +00:00
|
|
|
import type { WritableDB } from '../../sql/Interface';
|
|
|
|
import { createDB, updateToVersion, insertData, getTableData } from './helpers';
|
2023-08-16 20:54:39 +00:00
|
|
|
|
|
|
|
const CONVO_ID = generateGuid();
|
|
|
|
const GROUP_ID = generateGuid();
|
|
|
|
const UUID = generateGuid();
|
|
|
|
const PNI = generateGuid();
|
|
|
|
const OUR_UUID = generateGuid();
|
|
|
|
const OUR_PNI = generateGuid();
|
|
|
|
const THEIR_UUID = generateGuid();
|
|
|
|
|
|
|
|
describe('SQL/updateToSchemaVersion88', () => {
|
2024-07-22 18:16:33 +00:00
|
|
|
let db: WritableDB;
|
2023-08-16 20:54:39 +00:00
|
|
|
|
|
|
|
beforeEach(() => {
|
2024-07-22 18:16:33 +00:00
|
|
|
db = createDB();
|
2023-08-17 00:11:09 +00:00
|
|
|
updateToVersion(db, 86);
|
2023-08-16 20:54:39 +00:00
|
|
|
|
|
|
|
insertData(db, 'items', [
|
|
|
|
{
|
|
|
|
id: 'uuid_id',
|
|
|
|
json: {
|
|
|
|
id: 'uuid_id',
|
|
|
|
value: `${OUR_UUID}.1`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'pni',
|
|
|
|
json: {
|
|
|
|
id: 'pni',
|
|
|
|
value: OUR_PNI,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
db.close();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should migrate conversations', () => {
|
|
|
|
insertData(db, 'conversations', [
|
|
|
|
{
|
|
|
|
id: CONVO_ID,
|
|
|
|
type: 'direct',
|
|
|
|
uuid: UUID,
|
|
|
|
json: {
|
|
|
|
id: CONVO_ID,
|
|
|
|
uuid: UUID,
|
|
|
|
pni: PNI,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: GROUP_ID,
|
|
|
|
type: 'group',
|
|
|
|
json: {
|
|
|
|
id: GROUP_ID,
|
|
|
|
bannedMembersV2: [
|
|
|
|
{
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
lastMessageBodyRanges: [
|
|
|
|
{
|
|
|
|
mentionUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
membersV2: [
|
|
|
|
{
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
pendingAdminApprovalV2: [
|
|
|
|
{
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
pendingMembersV2: [
|
|
|
|
{
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
senderKeyInfo: {
|
|
|
|
memberDevices: [{ identifier: CONVO_ID }],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
updateToVersion(db, 88);
|
|
|
|
assert.deepStrictEqual(getTableData(db, 'conversations'), [
|
|
|
|
{
|
|
|
|
id: CONVO_ID,
|
|
|
|
type: 'direct',
|
|
|
|
serviceId: UUID,
|
|
|
|
json: {
|
|
|
|
id: CONVO_ID,
|
|
|
|
serviceId: UUID,
|
|
|
|
pni: `PNI:${PNI}`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: GROUP_ID,
|
|
|
|
type: 'group',
|
|
|
|
json: {
|
|
|
|
id: GROUP_ID,
|
|
|
|
bannedMembersV2: [{ serviceId: THEIR_UUID }],
|
|
|
|
lastMessageBodyRanges: [{ mentionAci: THEIR_UUID }],
|
|
|
|
membersV2: [{ aci: THEIR_UUID }],
|
|
|
|
pendingAdminApprovalV2: [{ aci: THEIR_UUID }],
|
|
|
|
pendingMembersV2: [{ serviceId: THEIR_UUID }],
|
|
|
|
senderKeyInfo: {
|
|
|
|
memberDevices: [{ serviceId: UUID }],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should migrate items', () => {
|
|
|
|
insertData(db, 'items', [
|
|
|
|
{
|
|
|
|
id: 'registrationIdMap',
|
|
|
|
json: {
|
|
|
|
id: 'registrationIdMap',
|
|
|
|
value: {
|
|
|
|
[OUR_UUID]: 123,
|
|
|
|
[OUR_PNI]: 456,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'identityKeyMap',
|
|
|
|
json: {
|
|
|
|
id: 'identityKeyMap',
|
|
|
|
value: {
|
|
|
|
[OUR_UUID]: {},
|
|
|
|
[OUR_PNI]: {},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
updateToVersion(db, 88);
|
|
|
|
assert.deepStrictEqual(getTableData(db, 'items'), [
|
|
|
|
{
|
|
|
|
id: 'uuid_id',
|
|
|
|
json: {
|
|
|
|
id: 'uuid_id',
|
|
|
|
value: `${OUR_UUID}.1`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'pni',
|
|
|
|
json: {
|
|
|
|
id: 'pni',
|
|
|
|
value: `PNI:${OUR_PNI}`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'registrationIdMap',
|
|
|
|
json: {
|
|
|
|
id: 'registrationIdMap',
|
|
|
|
value: {
|
|
|
|
[OUR_UUID]: 123,
|
|
|
|
[`PNI:${OUR_PNI}`]: 456,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'identityKeyMap',
|
|
|
|
json: {
|
|
|
|
id: 'identityKeyMap',
|
|
|
|
value: {
|
|
|
|
[OUR_UUID]: {},
|
|
|
|
[`PNI:${OUR_PNI}`]: {},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should migrate sessions', () => {
|
|
|
|
insertData(db, 'sessions', [
|
|
|
|
{
|
|
|
|
id: `${OUR_UUID}:${THEIR_UUID}.1`,
|
|
|
|
ourUuid: OUR_UUID,
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
json: {
|
|
|
|
id: `${OUR_UUID}:${THEIR_UUID}.1`,
|
|
|
|
ourUuid: OUR_UUID,
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: `${OUR_PNI}:${THEIR_UUID}.1`,
|
|
|
|
ourUuid: OUR_PNI,
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
json: {
|
|
|
|
id: `${OUR_PNI}:${THEIR_UUID}.1`,
|
|
|
|
ourUuid: OUR_PNI,
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
updateToVersion(db, 88);
|
|
|
|
assert.deepStrictEqual(getTableData(db, 'sessions'), [
|
|
|
|
{
|
|
|
|
id: `${OUR_UUID}:${THEIR_UUID}.1`,
|
|
|
|
ourServiceId: OUR_UUID,
|
|
|
|
serviceId: THEIR_UUID,
|
|
|
|
json: {
|
|
|
|
id: `${OUR_UUID}:${THEIR_UUID}.1`,
|
|
|
|
ourServiceId: OUR_UUID,
|
|
|
|
serviceId: THEIR_UUID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: `PNI:${OUR_PNI}:${THEIR_UUID}.1`,
|
|
|
|
ourServiceId: `PNI:${OUR_PNI}`,
|
|
|
|
serviceId: THEIR_UUID,
|
|
|
|
json: {
|
|
|
|
id: `PNI:${OUR_PNI}:${THEIR_UUID}.1`,
|
|
|
|
ourServiceId: `PNI:${OUR_PNI}`,
|
|
|
|
serviceId: THEIR_UUID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should migrate messages', () => {
|
|
|
|
insertData(db, 'messages', [
|
|
|
|
{
|
|
|
|
id: 'message-id',
|
|
|
|
json: {
|
|
|
|
id: 'message-id',
|
|
|
|
bodyRanges: [{ mentionUuid: THEIR_UUID }],
|
|
|
|
quote: {
|
|
|
|
bodyRanges: [{ mentionUuid: THEIR_UUID }],
|
|
|
|
},
|
|
|
|
sourceUuid: THEIR_UUID,
|
|
|
|
expirationTimerUpdate: {
|
|
|
|
sourceUuid: THEIR_UUID,
|
|
|
|
},
|
2023-08-28 22:03:32 +00:00
|
|
|
reactions: [{ targetAuthorUuid: THEIR_UUID }],
|
|
|
|
storyReaction: { targetAuthorUuid: THEIR_UUID },
|
2023-08-16 20:54:39 +00:00
|
|
|
storyReplyContext: {
|
|
|
|
authorUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
editHistory: [
|
|
|
|
{
|
|
|
|
bodyRanges: [{ mentionUuid: THEIR_UUID }],
|
|
|
|
quote: {
|
|
|
|
bodyRanges: [{ mentionUuid: THEIR_UUID }],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
groupV2Change: {
|
|
|
|
from: 'abc',
|
|
|
|
details: [
|
|
|
|
{
|
|
|
|
type: 'member-add',
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'pending-add-one',
|
|
|
|
uuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
updateToVersion(db, 88);
|
|
|
|
assert.deepStrictEqual(getTableData(db, 'messages'), [
|
|
|
|
{
|
|
|
|
id: 'message-id',
|
|
|
|
json: {
|
|
|
|
id: 'message-id',
|
|
|
|
bodyRanges: [{ mentionAci: THEIR_UUID }],
|
|
|
|
quote: {
|
|
|
|
bodyRanges: [{ mentionAci: THEIR_UUID }],
|
|
|
|
},
|
|
|
|
sourceServiceId: THEIR_UUID,
|
|
|
|
expirationTimerUpdate: {
|
|
|
|
sourceServiceId: THEIR_UUID,
|
|
|
|
},
|
2023-08-28 22:03:32 +00:00
|
|
|
reactions: [{}],
|
|
|
|
storyReaction: {},
|
2023-08-16 20:54:39 +00:00
|
|
|
storyReplyContext: {
|
|
|
|
authorAci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
editHistory: [
|
|
|
|
{
|
|
|
|
bodyRanges: [{ mentionAci: THEIR_UUID }],
|
|
|
|
quote: {
|
|
|
|
bodyRanges: [{ mentionAci: THEIR_UUID }],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
groupV2Change: {
|
|
|
|
from: 'abc',
|
|
|
|
details: [
|
|
|
|
{
|
|
|
|
type: 'member-add',
|
|
|
|
aci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: 'pending-add-one',
|
|
|
|
serviceId: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
mentionsMe: 0,
|
|
|
|
rowid: 1,
|
|
|
|
seenStatus: 0,
|
|
|
|
shouldAffectActivity: 1,
|
|
|
|
shouldAffectPreview: 1,
|
|
|
|
isChangeCreatedByUs: 0,
|
|
|
|
isGroupLeaveEvent: 0,
|
|
|
|
isGroupLeaveEventFromOther: 0,
|
|
|
|
isStory: 0,
|
|
|
|
isTimerChangeFromSync: 0,
|
|
|
|
isUserInitiatedMessage: 1,
|
|
|
|
expiresAt: 9007199254740991,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (const table of ['preKeys', 'signedPreKeys', 'kyberPreKeys']) {
|
|
|
|
// eslint-disable-next-line no-loop-func
|
|
|
|
it(`should migrate ${table}`, () => {
|
|
|
|
insertData(db, table, [
|
|
|
|
{
|
|
|
|
id: `${OUR_UUID}:123`,
|
|
|
|
json: {
|
|
|
|
id: `${OUR_UUID}:123`,
|
|
|
|
ourUuid: OUR_UUID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: `${OUR_PNI}:456`,
|
|
|
|
json: {
|
|
|
|
id: `${OUR_PNI}:456`,
|
|
|
|
ourUuid: OUR_PNI,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
updateToVersion(db, 88);
|
|
|
|
assert.deepStrictEqual(getTableData(db, table), [
|
|
|
|
{
|
|
|
|
id: `${OUR_UUID}:123`,
|
|
|
|
json: {
|
|
|
|
id: `${OUR_UUID}:123`,
|
|
|
|
ourServiceId: OUR_UUID,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: `PNI:${OUR_PNI}:456`,
|
|
|
|
json: {
|
|
|
|
id: `PNI:${OUR_PNI}:456`,
|
|
|
|
ourServiceId: `PNI:${OUR_PNI}`,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
it('should migrate jobs', () => {
|
|
|
|
insertData(db, 'conversations', [
|
|
|
|
{
|
|
|
|
id: CONVO_ID,
|
|
|
|
type: 'direct',
|
|
|
|
uuid: UUID,
|
|
|
|
json: {
|
|
|
|
id: CONVO_ID,
|
|
|
|
uuid: UUID,
|
|
|
|
pni: PNI,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
|
|
|
insertData(db, 'jobs', [
|
|
|
|
{
|
|
|
|
id: 'a',
|
|
|
|
queueType: 'conversation',
|
|
|
|
data: {
|
|
|
|
type: 'DeleteStoryForEveryone',
|
|
|
|
updatedStoryRecipients: [
|
|
|
|
{
|
|
|
|
destinationUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'b',
|
|
|
|
queueType: 'conversation',
|
|
|
|
data: {
|
|
|
|
type: 'ResendRequest',
|
|
|
|
senderUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'c',
|
|
|
|
queueType: 'conversation',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
receipts: [
|
|
|
|
{
|
|
|
|
senderUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'd',
|
|
|
|
queueType: 'read sync',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
readSyncs: [
|
|
|
|
{
|
|
|
|
senderUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'e',
|
|
|
|
queueType: 'view sync',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
viewSyncs: [
|
|
|
|
{
|
|
|
|
senderUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'f',
|
|
|
|
queueType: 'view once open sync',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
viewOnceOpens: [
|
|
|
|
{
|
|
|
|
senderUuid: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'g',
|
|
|
|
queueType: 'single proto',
|
|
|
|
data: {
|
|
|
|
identifier: CONVO_ID,
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
updateToVersion(db, 88);
|
|
|
|
assert.deepStrictEqual(getTableData(db, 'jobs'), [
|
|
|
|
{
|
|
|
|
id: 'a',
|
|
|
|
queueType: 'conversation',
|
|
|
|
data: {
|
|
|
|
type: 'DeleteStoryForEveryone',
|
|
|
|
updatedStoryRecipients: [
|
|
|
|
{
|
|
|
|
destinationServiceId: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'b',
|
|
|
|
queueType: 'conversation',
|
|
|
|
data: {
|
|
|
|
type: 'ResendRequest',
|
|
|
|
senderAci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'c',
|
|
|
|
queueType: 'conversation',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
receipts: [
|
|
|
|
{
|
|
|
|
senderAci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'd',
|
|
|
|
queueType: 'read sync',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
readSyncs: [
|
|
|
|
{
|
|
|
|
senderAci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'e',
|
|
|
|
queueType: 'view sync',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
viewSyncs: [
|
|
|
|
{
|
|
|
|
senderAci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'f',
|
|
|
|
queueType: 'view once open sync',
|
|
|
|
data: {
|
|
|
|
type: 'Receipts',
|
|
|
|
viewOnceOpens: [
|
|
|
|
{
|
|
|
|
senderAci: THEIR_UUID,
|
|
|
|
},
|
|
|
|
],
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: 'g',
|
|
|
|
queueType: 'single proto',
|
|
|
|
data: {
|
|
|
|
serviceId: UUID,
|
|
|
|
},
|
|
|
|
timestamp: 1,
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
});
|
|
|
|
});
|