Add unsupported/sse message export/import
This commit is contained in:
parent
c67a346218
commit
481928fa4f
7 changed files with 396 additions and 116 deletions
|
@ -77,6 +77,7 @@ message AccountData {
|
||||||
bool hasSeenGroupStoryEducationSheet = 15;
|
bool hasSeenGroupStoryEducationSheet = 15;
|
||||||
bool hasCompletedUsernameOnboarding = 16;
|
bool hasCompletedUsernameOnboarding = 16;
|
||||||
PhoneNumberSharingMode phoneNumberSharingMode = 17;
|
PhoneNumberSharingMode phoneNumberSharingMode = 17;
|
||||||
|
ChatStyle defaultChatStyle = 18;
|
||||||
}
|
}
|
||||||
|
|
||||||
bytes profileKey = 1;
|
bytes profileKey = 1;
|
||||||
|
@ -228,7 +229,7 @@ message Chat {
|
||||||
uint64 muteUntilMs = 6;
|
uint64 muteUntilMs = 6;
|
||||||
bool markedUnread = 7;
|
bool markedUnread = 7;
|
||||||
bool dontNotifyForMentionsIfMuted = 8;
|
bool dontNotifyForMentionsIfMuted = 8;
|
||||||
FilePointer wallpaper = 9;
|
ChatStyle style = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -725,6 +726,7 @@ message SimpleChatUpdate {
|
||||||
BAD_DECRYPT = 9;
|
BAD_DECRYPT = 9;
|
||||||
PAYMENTS_ACTIVATED = 10;
|
PAYMENTS_ACTIVATED = 10;
|
||||||
PAYMENT_ACTIVATION_REQUEST = 11;
|
PAYMENT_ACTIVATION_REQUEST = 11;
|
||||||
|
UNSUPPORTED_PROTOCOL_MESSAGE = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type type = 1;
|
Type type = 1;
|
||||||
|
@ -1008,3 +1010,79 @@ message StickerPackSticker {
|
||||||
string emoji = 1;
|
string emoji = 1;
|
||||||
uint32 id = 2;
|
uint32 id = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
message ChatStyle {
|
||||||
|
message Gradient {
|
||||||
|
uint32 angle = 1; // degrees
|
||||||
|
repeated uint32 colors = 2;
|
||||||
|
repeated float positions = 3; // percent from 0 to 1
|
||||||
|
}
|
||||||
|
|
||||||
|
message AutomaticBubbleColor {
|
||||||
|
}
|
||||||
|
|
||||||
|
enum WallpaperPreset {
|
||||||
|
UNKNOWN_WALLPAPER_PRESET = 0;
|
||||||
|
SOLID_BLUSH = 1;
|
||||||
|
SOLID_COPPER = 2;
|
||||||
|
SOLID_DUST = 3;
|
||||||
|
SOLID_CELADON = 4;
|
||||||
|
SOLID_RAINFOREST = 5;
|
||||||
|
SOLID_PACIFIC = 6;
|
||||||
|
SOLID_FROST = 7;
|
||||||
|
SOLID_NAVY = 8;
|
||||||
|
SOLID_LILAC = 9;
|
||||||
|
SOLID_PINK = 10;
|
||||||
|
SOLID_EGGPLANT = 11;
|
||||||
|
SOLID_SILVER = 12;
|
||||||
|
GRADIENT_SUNSET = 13;
|
||||||
|
GRADIENT_NOIR = 14;
|
||||||
|
GRADIENT_HEATMAP = 15;
|
||||||
|
GRADIENT_AQUA = 16;
|
||||||
|
GRADIENT_IRIDESCENT = 17;
|
||||||
|
GRADIENT_MONSTERA = 18;
|
||||||
|
GRADIENT_BLISS = 19;
|
||||||
|
GRADIENT_SKY = 20;
|
||||||
|
GRADIENT_PEACH = 21;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BubbleColorPreset {
|
||||||
|
UNKNOWN_BUBBLE_COLOR_PRESET = 0;
|
||||||
|
SOLID_ULTRAMARINE = 1;
|
||||||
|
SOLID_CRIMSON = 2;
|
||||||
|
SOLID_VERMILION = 3;
|
||||||
|
SOLID_BURLAP = 4;
|
||||||
|
SOLID_FOREST = 5;
|
||||||
|
SOLID_WINTERGREEN = 6;
|
||||||
|
SOLID_TEAL = 7;
|
||||||
|
SOLID_BLUE = 8;
|
||||||
|
SOLID_INDIGO = 9;
|
||||||
|
SOLID_VIOLET = 10;
|
||||||
|
SOLID_PLUM = 11;
|
||||||
|
SOLID_TAUPE = 12;
|
||||||
|
SOLID_STEEL = 13;
|
||||||
|
GRADIENT_EMBER = 14;
|
||||||
|
GRADIENT_MIDNIGHT = 15;
|
||||||
|
GRADIENT_INFRARED = 16;
|
||||||
|
GRADIENT_LAGOON = 17;
|
||||||
|
GRADIENT_FLUORESCENT = 18;
|
||||||
|
GRADIENT_BASIL = 19;
|
||||||
|
GRADIENT_SUBLIME = 20;
|
||||||
|
GRADIENT_SEA = 21;
|
||||||
|
GRADIENT_TANGERINE = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof wallpaper {
|
||||||
|
WallpaperPreset wallpaperPreset = 1;
|
||||||
|
FilePointer wallpaperPhoto = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
oneof bubbleColor {
|
||||||
|
BubbleColorPreset bubbleColorPreset = 3;
|
||||||
|
Gradient bubbleGradient = 4;
|
||||||
|
uint32 bubbleSolidColor = 5;
|
||||||
|
// Bubble setting is automatically determined based on the wallpaper setting.
|
||||||
|
AutomaticBubbleColor autoBubbleColor = 6;
|
||||||
|
}
|
||||||
|
}
|
|
@ -620,12 +620,8 @@ export class BackupExportStream extends Readable {
|
||||||
const isOutgoing = message.type === 'outgoing';
|
const isOutgoing = message.type === 'outgoing';
|
||||||
const isIncoming = message.type === 'incoming';
|
const isIncoming = message.type === 'incoming';
|
||||||
|
|
||||||
if (isOutgoing) {
|
// Pacify typescript
|
||||||
authorId = this.getOrPushPrivateRecipient({
|
if (message.sourceServiceId) {
|
||||||
serviceId: aboutMe.aci,
|
|
||||||
});
|
|
||||||
// Pacify typescript
|
|
||||||
} else if (message.sourceServiceId) {
|
|
||||||
authorId = this.getOrPushPrivateRecipient({
|
authorId = this.getOrPushPrivateRecipient({
|
||||||
serviceId: message.sourceServiceId,
|
serviceId: message.sourceServiceId,
|
||||||
e164: message.source,
|
e164: message.source,
|
||||||
|
@ -635,7 +631,15 @@ export class BackupExportStream extends Readable {
|
||||||
serviceId: message.sourceServiceId,
|
serviceId: message.sourceServiceId,
|
||||||
e164: message.source,
|
e164: message.source,
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
strictAssert(!isIncoming, 'Incoming message must have source');
|
||||||
|
|
||||||
|
// Author must be always present, even if we are directionless
|
||||||
|
authorId = this.getOrPushPrivateRecipient({
|
||||||
|
serviceId: aboutMe.aci,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isOutgoing || isIncoming) {
|
if (isOutgoing || isIncoming) {
|
||||||
strictAssert(authorId, 'Incoming/outgoing messages require an author');
|
strictAssert(authorId, 'Incoming/outgoing messages require an author');
|
||||||
}
|
}
|
||||||
|
@ -1088,7 +1092,15 @@ export class BackupExportStream extends Readable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPhoneNumberDiscovery(message)) {
|
if (isPhoneNumberDiscovery(message)) {
|
||||||
// TODO (DESKTOP-6964): need to add to protos
|
const e164 = message.phoneNumberDiscovery?.e164;
|
||||||
|
if (!e164) {
|
||||||
|
return { kind: NonBubbleResultKind.Drop };
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMessage.sessionSwitchover = {
|
||||||
|
e164: Long.fromString(e164),
|
||||||
|
};
|
||||||
|
return { kind: NonBubbleResultKind.Directionless, patch };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUniversalTimerNotification(message)) {
|
if (isUniversalTimerNotification(message)) {
|
||||||
|
@ -1097,7 +1109,9 @@ export class BackupExportStream extends Readable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isContactRemovedNotification(message)) {
|
if (isContactRemovedNotification(message)) {
|
||||||
// TODO (DESKTOP-6964): this doesn't appear to be in the protos at all
|
// Transient, drop it
|
||||||
|
// TODO: DESKTOP-7124
|
||||||
|
return { kind: NonBubbleResultKind.Drop };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isGiftBadge(message)) {
|
if (isGiftBadge(message)) {
|
||||||
|
@ -1111,10 +1125,14 @@ export class BackupExportStream extends Readable {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUnsupportedMessage(message)) {
|
if (isUnsupportedMessage(message)) {
|
||||||
// TODO (DESKTOP-6964): need to add to protos
|
const simpleUpdate = new Backups.SimpleChatUpdate();
|
||||||
}
|
simpleUpdate.type =
|
||||||
|
Backups.SimpleChatUpdate.Type.UNSUPPORTED_PROTOCOL_MESSAGE;
|
||||||
|
|
||||||
// TODO (DESKTOP-6964): session switchover
|
updateMessage.simpleUpdate = simpleUpdate;
|
||||||
|
|
||||||
|
return { kind: NonBubbleResultKind.Directed, patch };
|
||||||
|
}
|
||||||
|
|
||||||
if (isGroupV1Migration(message)) {
|
if (isGroupV1Migration(message)) {
|
||||||
const { groupMigration } = message;
|
const { groupMigration } = message;
|
||||||
|
@ -1177,7 +1195,7 @@ export class BackupExportStream extends Readable {
|
||||||
|
|
||||||
updateMessage.simpleUpdate = simpleUpdate;
|
updateMessage.simpleUpdate = simpleUpdate;
|
||||||
|
|
||||||
return { kind: NonBubbleResultKind.Directionless, patch };
|
return { kind: NonBubbleResultKind.Directed, patch };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isChatSessionRefreshed(message)) {
|
if (isChatSessionRefreshed(message)) {
|
||||||
|
|
|
@ -671,12 +671,14 @@ export class BackupImportStream extends Writable {
|
||||||
conversation.isArchived = chat.archived === true;
|
conversation.isArchived = chat.archived === true;
|
||||||
conversation.isPinned = chat.pinnedOrder != null;
|
conversation.isPinned = chat.pinnedOrder != null;
|
||||||
|
|
||||||
conversation.expireTimer = chat.expirationTimerMs
|
conversation.expireTimer =
|
||||||
? DurationInSeconds.fromMillis(chat.expirationTimerMs.toNumber())
|
chat.expirationTimerMs && !chat.expirationTimerMs.isZero()
|
||||||
: undefined;
|
? DurationInSeconds.fromMillis(chat.expirationTimerMs.toNumber())
|
||||||
conversation.muteExpiresAt = chat.muteUntilMs
|
: undefined;
|
||||||
? getTimestampFromLong(chat.muteUntilMs)
|
conversation.muteExpiresAt =
|
||||||
: undefined;
|
chat.muteUntilMs && !chat.muteUntilMs.isZero()
|
||||||
|
? getTimestampFromLong(chat.muteUntilMs)
|
||||||
|
: undefined;
|
||||||
conversation.markedUnread = chat.markedUnread === true;
|
conversation.markedUnread = chat.markedUnread === true;
|
||||||
conversation.dontNotifyForMentionsIfMuted =
|
conversation.dontNotifyForMentionsIfMuted =
|
||||||
chat.dontNotifyForMentionsIfMuted === true;
|
chat.dontNotifyForMentionsIfMuted === true;
|
||||||
|
@ -715,7 +717,6 @@ export class BackupImportStream extends Writable {
|
||||||
|
|
||||||
let attributes: MessageAttributesType = {
|
let attributes: MessageAttributesType = {
|
||||||
id: generateUuid(),
|
id: generateUuid(),
|
||||||
canReplyToStory: false,
|
|
||||||
conversationId: chatConvo.id,
|
conversationId: chatConvo.id,
|
||||||
received_at: incrementMessageCounter(),
|
received_at: incrementMessageCounter(),
|
||||||
sent_at: timestamp,
|
sent_at: timestamp,
|
||||||
|
@ -723,13 +724,14 @@ export class BackupImportStream extends Writable {
|
||||||
sourceServiceId: authorConvo?.serviceId,
|
sourceServiceId: authorConvo?.serviceId,
|
||||||
timestamp,
|
timestamp,
|
||||||
type: item.outgoing != null ? 'outgoing' : 'incoming',
|
type: item.outgoing != null ? 'outgoing' : 'incoming',
|
||||||
unidentifiedDeliveryReceived: false,
|
expirationStartTimestamp:
|
||||||
expirationStartTimestamp: item.expireStartDate
|
item.expireStartDate && !item.expireStartDate.isZero()
|
||||||
? getTimestampFromLong(item.expireStartDate)
|
? getTimestampFromLong(item.expireStartDate)
|
||||||
: undefined,
|
: undefined,
|
||||||
expireTimer: item.expiresInMs
|
expireTimer:
|
||||||
? DurationInSeconds.fromMillis(item.expiresInMs.toNumber())
|
item.expiresInMs && !item.expiresInMs.isZero()
|
||||||
: undefined,
|
? DurationInSeconds.fromMillis(item.expiresInMs.toNumber())
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
const additionalMessages: Array<MessageAttributesType> = [];
|
const additionalMessages: Array<MessageAttributesType> = [];
|
||||||
|
|
||||||
|
@ -1110,9 +1112,10 @@ export class BackupImportStream extends Writable {
|
||||||
const { expiresInMs } = updateMessage.expirationTimerChange;
|
const { expiresInMs } = updateMessage.expirationTimerChange;
|
||||||
|
|
||||||
const sourceServiceId = author?.serviceId ?? aboutMe.aci;
|
const sourceServiceId = author?.serviceId ?? aboutMe.aci;
|
||||||
const expireTimer = isNumber(expiresInMs)
|
const expireTimer =
|
||||||
? DurationInSeconds.fromMillis(expiresInMs)
|
isNumber(expiresInMs) && expiresInMs
|
||||||
: DurationInSeconds.fromSeconds(0);
|
? DurationInSeconds.fromMillis(expiresInMs)
|
||||||
|
: DurationInSeconds.fromSeconds(0);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: {
|
message: {
|
||||||
|
@ -1178,8 +1181,21 @@ export class BackupImportStream extends Writable {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateMessage.sessionSwitchover) {
|
||||||
|
const { e164 } = updateMessage.sessionSwitchover;
|
||||||
|
strictAssert(e164 != null, 'sessionSwitchover must have an old e164');
|
||||||
|
return {
|
||||||
|
message: {
|
||||||
|
type: 'phone-number-discovery',
|
||||||
|
phoneNumberDiscovery: {
|
||||||
|
e164: `+${e164}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
additionalMessages: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// TODO (DESKTOP-6964): check these fields
|
// TODO (DESKTOP-6964): check these fields
|
||||||
// updateMessage.sessionSwitchover
|
|
||||||
// updateMessage.callingMessage
|
// updateMessage.callingMessage
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -1703,9 +1719,10 @@ export class BackupImportStream extends Writable {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const sourceServiceId = fromAciObject(Aci.fromUuidBytes(updaterAci));
|
const sourceServiceId = fromAciObject(Aci.fromUuidBytes(updaterAci));
|
||||||
const expireTimer = isNumber(expiresInMs)
|
const expireTimer =
|
||||||
? DurationInSeconds.fromMillis(expiresInMs)
|
isNumber(expiresInMs) && expiresInMs
|
||||||
: undefined;
|
? DurationInSeconds.fromMillis(expiresInMs)
|
||||||
|
: undefined;
|
||||||
additionalMessages.push({
|
additionalMessages.push({
|
||||||
type: 'timer-notification',
|
type: 'timer-notification',
|
||||||
sourceServiceId,
|
sourceServiceId,
|
||||||
|
@ -1841,6 +1858,13 @@ export class BackupImportStream extends Writable {
|
||||||
kind: PaymentEventKind.ActivationRequest,
|
kind: PaymentEventKind.ActivationRequest,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
case Type.UNSUPPORTED_PROTOCOL_MESSAGE:
|
||||||
|
return {
|
||||||
|
supportedVersionAtReceive:
|
||||||
|
SignalService.DataMessage.ProtocolVersion.CURRENT - 2,
|
||||||
|
requiredProtocolVersion:
|
||||||
|
SignalService.DataMessage.ProtocolVersion.CURRENT - 1,
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import Data from '../../sql/Client';
|
||||||
import { SignalService as Proto } from '../../protobuf';
|
import { SignalService as Proto } from '../../protobuf';
|
||||||
|
|
||||||
import { generateAci, generatePni } from '../../types/ServiceId';
|
import { generateAci, generatePni } from '../../types/ServiceId';
|
||||||
|
import type { ServiceIdString } from '../../types/ServiceId';
|
||||||
import type { MessageAttributesType } from '../../model-types';
|
import type { MessageAttributesType } from '../../model-types';
|
||||||
import type { GroupV2ChangeType } from '../../groups';
|
import type { GroupV2ChangeType } from '../../groups';
|
||||||
import { getRandomBytes } from '../../Crypto';
|
import { getRandomBytes } from '../../Crypto';
|
||||||
|
@ -42,7 +43,13 @@ let counter = 0;
|
||||||
|
|
||||||
function createMessage(
|
function createMessage(
|
||||||
change: GroupV2ChangeType,
|
change: GroupV2ChangeType,
|
||||||
{ disableIncrement }: { disableIncrement: boolean } = {
|
{
|
||||||
|
disableIncrement = false,
|
||||||
|
sourceServiceId = change.from || OUR_ACI,
|
||||||
|
}: {
|
||||||
|
disableIncrement?: boolean;
|
||||||
|
sourceServiceId?: ServiceIdString;
|
||||||
|
} = {
|
||||||
disableIncrement: false,
|
disableIncrement: false,
|
||||||
}
|
}
|
||||||
): MessageAttributesType {
|
): MessageAttributesType {
|
||||||
|
@ -60,6 +67,7 @@ function createMessage(
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
type: 'group-v2-change',
|
type: 'group-v2-change',
|
||||||
|
sourceServiceId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,16 +703,19 @@ describe('backup/groupv2/notifications', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('MemberAddFromInvited items', async () => {
|
it('MemberAddFromInvited items', async () => {
|
||||||
const firstBefore = createMessage({
|
const firstBefore = createMessage(
|
||||||
from: OUR_PNI,
|
{
|
||||||
details: [
|
from: OUR_PNI,
|
||||||
{
|
details: [
|
||||||
type: 'member-add-from-invite',
|
{
|
||||||
aci: OUR_ACI,
|
type: 'member-add-from-invite',
|
||||||
inviter: CONTACT_B,
|
aci: OUR_ACI,
|
||||||
},
|
inviter: CONTACT_B,
|
||||||
],
|
},
|
||||||
});
|
],
|
||||||
|
},
|
||||||
|
{ sourceServiceId: OUR_ACI }
|
||||||
|
);
|
||||||
const firstAfter = createMessage(
|
const firstAfter = createMessage(
|
||||||
{
|
{
|
||||||
from: OUR_ACI,
|
from: OUR_ACI,
|
||||||
|
@ -719,15 +730,18 @@ describe('backup/groupv2/notifications', () => {
|
||||||
{ disableIncrement: true }
|
{ disableIncrement: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const secondBefore = createMessage({
|
const secondBefore = createMessage(
|
||||||
from: OUR_PNI,
|
{
|
||||||
details: [
|
from: OUR_PNI,
|
||||||
{
|
details: [
|
||||||
type: 'member-add-from-invite',
|
{
|
||||||
aci: OUR_ACI,
|
type: 'member-add-from-invite',
|
||||||
},
|
aci: OUR_ACI,
|
||||||
],
|
},
|
||||||
});
|
],
|
||||||
|
},
|
||||||
|
{ sourceServiceId: OUR_ACI }
|
||||||
|
);
|
||||||
const secondAfter = createMessage(
|
const secondAfter = createMessage(
|
||||||
{
|
{
|
||||||
from: OUR_ACI,
|
from: OUR_ACI,
|
||||||
|
@ -741,15 +755,18 @@ describe('backup/groupv2/notifications', () => {
|
||||||
{ disableIncrement: true }
|
{ disableIncrement: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const thirdBefore = createMessage({
|
const thirdBefore = createMessage(
|
||||||
from: CONTACT_A_PNI,
|
{
|
||||||
details: [
|
from: CONTACT_A_PNI,
|
||||||
{
|
details: [
|
||||||
type: 'member-add-from-invite',
|
{
|
||||||
aci: CONTACT_A,
|
type: 'member-add-from-invite',
|
||||||
},
|
aci: CONTACT_A,
|
||||||
],
|
},
|
||||||
});
|
],
|
||||||
|
},
|
||||||
|
{ sourceServiceId: CONTACT_A }
|
||||||
|
);
|
||||||
const thirdAfter = createMessage(
|
const thirdAfter = createMessage(
|
||||||
{
|
{
|
||||||
from: CONTACT_A,
|
from: CONTACT_A,
|
||||||
|
@ -763,16 +780,19 @@ describe('backup/groupv2/notifications', () => {
|
||||||
{ disableIncrement: true }
|
{ disableIncrement: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
const fourthBefore = createMessage({
|
const fourthBefore = createMessage(
|
||||||
from: CONTACT_A_PNI,
|
{
|
||||||
details: [
|
from: CONTACT_A_PNI,
|
||||||
{
|
details: [
|
||||||
type: 'member-add-from-invite',
|
{
|
||||||
aci: CONTACT_A,
|
type: 'member-add-from-invite',
|
||||||
pni: CONTACT_A_PNI,
|
aci: CONTACT_A,
|
||||||
},
|
pni: CONTACT_A_PNI,
|
||||||
],
|
},
|
||||||
});
|
],
|
||||||
|
},
|
||||||
|
{ sourceServiceId: CONTACT_A }
|
||||||
|
);
|
||||||
const fourthAfter = createMessage(
|
const fourthAfter = createMessage(
|
||||||
{
|
{
|
||||||
from: CONTACT_A,
|
from: CONTACT_A,
|
||||||
|
@ -829,14 +849,17 @@ describe('backup/groupv2/notifications', () => {
|
||||||
|
|
||||||
it('MemberAddFromLink items asymmetric', async () => {
|
it('MemberAddFromLink items asymmetric', async () => {
|
||||||
const before: Array<MessageAttributesType> = [
|
const before: Array<MessageAttributesType> = [
|
||||||
createMessage({
|
createMessage(
|
||||||
details: [
|
{
|
||||||
{
|
details: [
|
||||||
type: 'member-add-from-link',
|
{
|
||||||
aci: CONTACT_A,
|
type: 'member-add-from-link',
|
||||||
},
|
aci: CONTACT_A,
|
||||||
],
|
},
|
||||||
}),
|
],
|
||||||
|
},
|
||||||
|
{ sourceServiceId: CONTACT_A }
|
||||||
|
),
|
||||||
];
|
];
|
||||||
const after: Array<MessageAttributesType> = [
|
const after: Array<MessageAttributesType> = [
|
||||||
createMessage(
|
createMessage(
|
||||||
|
@ -2008,6 +2031,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
};
|
};
|
||||||
|
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
@ -2023,6 +2047,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
};
|
};
|
||||||
|
|
||||||
const messages: Array<MessageAttributesType> = [
|
const messages: Array<MessageAttributesType> = [
|
||||||
|
@ -2099,6 +2124,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
|
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
@ -2114,6 +2140,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
|
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
@ -2129,6 +2156,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
|
|
||||||
const messages: Array<MessageAttributesType> = [
|
const messages: Array<MessageAttributesType> = [
|
||||||
|
@ -2160,6 +2188,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
const legacyAfter = {
|
const legacyAfter = {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
|
@ -2173,6 +2202,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
|
|
||||||
counter += 1;
|
counter += 1;
|
||||||
|
@ -2191,6 +2221,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
const allDataAfter = {
|
const allDataAfter = {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
|
@ -2204,6 +2235,7 @@ describe('backup/groupv2/notifications', () => {
|
||||||
received_at: counter,
|
received_at: counter,
|
||||||
sent_at: counter,
|
sent_at: counter,
|
||||||
timestamp: counter,
|
timestamp: counter,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
};
|
};
|
||||||
|
|
||||||
const before = [legacyBefore, allDataBefore];
|
const before = [legacyBefore, allDataBefore];
|
||||||
|
|
|
@ -4,13 +4,18 @@
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
import { pick, sortBy } from 'lodash';
|
import { sortBy } from 'lodash';
|
||||||
import { createReadStream } from 'fs';
|
import { createReadStream } from 'fs';
|
||||||
import { mkdtemp, rm } from 'fs/promises';
|
import { mkdtemp, rm } from 'fs/promises';
|
||||||
|
|
||||||
import type { MessageAttributesType } from '../../model-types';
|
import type { MessageAttributesType } from '../../model-types';
|
||||||
|
import type {
|
||||||
|
SendStateByConversationId,
|
||||||
|
SendState,
|
||||||
|
} from '../../messages/MessageSendState';
|
||||||
|
|
||||||
import { backupsService } from '../../services/backups';
|
import { backupsService } from '../../services/backups';
|
||||||
|
import { isUnsupportedMessage } from '../../state/selectors/message';
|
||||||
import { generateAci, generatePni } from '../../types/ServiceId';
|
import { generateAci, generatePni } from '../../types/ServiceId';
|
||||||
import Data from '../../sql/Client';
|
import Data from '../../sql/Client';
|
||||||
import { getRandomBytes } from '../../Crypto';
|
import { getRandomBytes } from '../../Crypto';
|
||||||
|
@ -37,37 +42,67 @@ function sortAndNormalize(
|
||||||
messages: Array<MessageAttributesType>
|
messages: Array<MessageAttributesType>
|
||||||
): Array<unknown> {
|
): Array<unknown> {
|
||||||
return sortBy(messages, 'sent_at').map(message => {
|
return sortBy(messages, 'sent_at').map(message => {
|
||||||
const shallow = pick(
|
const {
|
||||||
message,
|
changedId,
|
||||||
'contact',
|
conversationId,
|
||||||
'conversationMerge',
|
editHistory,
|
||||||
'droppedGV2MemberIds',
|
key_changed: keyChanged,
|
||||||
'expirationTimerUpdate',
|
reactions,
|
||||||
'flags',
|
sendStateByConversationId,
|
||||||
'groupMigration',
|
verifiedChanged,
|
||||||
'groupV2Change',
|
|
||||||
'invitedGV2Members',
|
// This is not in the backup
|
||||||
'isErased',
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
'payment',
|
id: _id,
|
||||||
'profileChange',
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
'sent_at',
|
received_at: _receivedAt,
|
||||||
'sticker',
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
'timestamp',
|
sourceDevice: _sourceDevice,
|
||||||
'type',
|
|
||||||
'verified'
|
...rest
|
||||||
);
|
} = message;
|
||||||
|
|
||||||
|
function mapSendState(
|
||||||
|
sendState?: SendStateByConversationId
|
||||||
|
): SendStateByConversationId | undefined {
|
||||||
|
if (sendState == null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: Record<string, SendState> = {};
|
||||||
|
for (const [id, state] of Object.entries(sendState)) {
|
||||||
|
result[mapConvoId(id) ?? id] = state;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...shallow,
|
...rest,
|
||||||
reactions: message.reactions?.map(({ fromId, ...rest }) => {
|
conversationId: mapConvoId(conversationId),
|
||||||
|
reactions: reactions?.map(({ fromId, ...restOfReaction }) => {
|
||||||
return {
|
return {
|
||||||
from: mapConvoId(fromId),
|
from: mapConvoId(fromId),
|
||||||
...rest,
|
...restOfReaction,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
changedId: mapConvoId(message.changedId),
|
changedId: mapConvoId(changedId),
|
||||||
key_changed: mapConvoId(message.key_changed),
|
key_changed: mapConvoId(keyChanged),
|
||||||
verifiedChanged: mapConvoId(message.verifiedChanged),
|
verifiedChanged: mapConvoId(verifiedChanged),
|
||||||
|
sendStateByConverationId: mapSendState(sendStateByConversationId),
|
||||||
|
editHistory: editHistory?.map(history => {
|
||||||
|
const {
|
||||||
|
sendStateByConversationId: historySendState,
|
||||||
|
...restOfHistory
|
||||||
|
} = history;
|
||||||
|
|
||||||
|
return {
|
||||||
|
...restOfHistory,
|
||||||
|
sendStateByConversationId: mapSendState(historySendState),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
|
||||||
|
// Not an original property, but useful
|
||||||
|
isUnsupported: isUnsupportedMessage(message),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -83,7 +118,7 @@ async function updateConvoIdToTitle() {
|
||||||
for (const convo of all) {
|
for (const convo of all) {
|
||||||
CONVO_ID_TO_STABLE_ID.set(
|
CONVO_ID_TO_STABLE_ID.set(
|
||||||
convo.id,
|
convo.id,
|
||||||
convo.serviceId ?? convo.e164 ?? convo.id
|
convo.serviceId ?? convo.e164 ?? convo.masterKey ?? convo.id
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ import { generateAci } from '../../types/ServiceId';
|
||||||
import { PaymentEventKind } from '../../types/Payment';
|
import { PaymentEventKind } from '../../types/Payment';
|
||||||
import { ContactFormType } from '../../types/EmbeddedContact';
|
import { ContactFormType } from '../../types/EmbeddedContact';
|
||||||
import { DurationInSeconds } from '../../util/durations';
|
import { DurationInSeconds } from '../../util/durations';
|
||||||
|
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||||
|
import { SeenStatus } from '../../MessageSeenStatus';
|
||||||
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
import { loadCallsHistory } from '../../services/callHistoryLoader';
|
||||||
import { setupBasics, symmetricRoundtripHarness } from './helpers';
|
import { setupBasics, symmetricRoundtripHarness, OUR_ACI } from './helpers';
|
||||||
|
|
||||||
const CONTACT_A = generateAci();
|
const CONTACT_A = generateAci();
|
||||||
const GROUP_ID = Bytes.toBase64(getRandomBytes(32));
|
const GROUP_ID = Bytes.toBase64(getRandomBytes(32));
|
||||||
|
@ -57,10 +59,13 @@ describe('backup/non-bubble messages', () => {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
sourceServiceId: CONTACT_A,
|
||||||
sourceDevice: 1,
|
sourceDevice: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
flags: Proto.DataMessage.Flags.END_SESSION,
|
flags: Proto.DataMessage.Flags.END_SESSION,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -75,6 +80,7 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: OUR_ACI,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -88,6 +94,7 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -102,6 +109,7 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -117,6 +125,7 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -132,6 +141,7 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -142,10 +152,10 @@ describe('backup/non-bubble messages', () => {
|
||||||
conversationId: contactA.id,
|
conversationId: contactA.id,
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'change-number-notification',
|
type: 'change-number-notification',
|
||||||
sourceServiceId: CONTACT_A,
|
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -159,6 +169,7 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -169,10 +180,10 @@ describe('backup/non-bubble messages', () => {
|
||||||
conversationId: contactA.id,
|
conversationId: contactA.id,
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'delivery-issue',
|
type: 'delivery-issue',
|
||||||
sourceServiceId: CONTACT_A,
|
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -188,8 +199,11 @@ describe('backup/non-bubble messages', () => {
|
||||||
kind: PaymentEventKind.Activation,
|
kind: PaymentEventKind.Activation,
|
||||||
},
|
},
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -205,8 +219,11 @@ describe('backup/non-bubble messages', () => {
|
||||||
kind: PaymentEventKind.ActivationRequest,
|
kind: PaymentEventKind.ActivationRequest,
|
||||||
},
|
},
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
@ -219,10 +236,13 @@ describe('backup/non-bubble messages', () => {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
sourceServiceId: CONTACT_A,
|
||||||
sourceDevice: 1,
|
sourceDevice: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
payment: {
|
payment: {
|
||||||
kind: PaymentEventKind.Notification,
|
kind: PaymentEventKind.Notification,
|
||||||
note: 'note with text',
|
note: 'note with text',
|
||||||
|
@ -239,10 +259,13 @@ describe('backup/non-bubble messages', () => {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
sourceServiceId: CONTACT_A,
|
||||||
sourceDevice: 1,
|
sourceDevice: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
payment: {
|
payment: {
|
||||||
kind: PaymentEventKind.Notification,
|
kind: PaymentEventKind.Notification,
|
||||||
note: 'note with text',
|
note: 'note with text',
|
||||||
|
@ -267,10 +290,13 @@ describe('backup/non-bubble messages', () => {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
sourceServiceId: CONTACT_A,
|
||||||
sourceDevice: 1,
|
sourceDevice: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
contact: [
|
contact: [
|
||||||
{
|
{
|
||||||
name: {
|
name: {
|
||||||
|
@ -306,10 +332,13 @@ describe('backup/non-bubble messages', () => {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
sourceServiceId: CONTACT_A,
|
||||||
sourceDevice: 1,
|
sourceDevice: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
// TODO (DESKTOP-6845): properly handle data FilePointer
|
// TODO (DESKTOP-6845): properly handle data FilePointer
|
||||||
sticker: {
|
sticker: {
|
||||||
emoji: '👍',
|
emoji: '👍',
|
||||||
|
@ -337,10 +366,13 @@ describe('backup/non-bubble messages', () => {
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'incoming',
|
type: 'incoming',
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
|
received_at_ms: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
sourceServiceId: CONTACT_A,
|
||||||
sourceDevice: 1,
|
sourceDevice: 1,
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
isErased: true,
|
isErased: true,
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
@ -375,9 +407,8 @@ describe('backup/non-bubble messages', () => {
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
|
||||||
sourceDevice: 1,
|
|
||||||
changedId: contactA.id,
|
changedId: contactA.id,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
profileChange: {
|
profileChange: {
|
||||||
type: 'name',
|
type: 'name',
|
||||||
oldName: 'Old Name',
|
oldName: 'Old Name',
|
||||||
|
@ -393,11 +424,10 @@ describe('backup/non-bubble messages', () => {
|
||||||
conversationId: contactA.id,
|
conversationId: contactA.id,
|
||||||
id: generateGuid(),
|
id: generateGuid(),
|
||||||
type: 'conversation-merge',
|
type: 'conversation-merge',
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
received_at: 1,
|
received_at: 1,
|
||||||
sent_at: 1,
|
sent_at: 1,
|
||||||
timestamp: 1,
|
timestamp: 1,
|
||||||
sourceServiceId: CONTACT_A,
|
|
||||||
sourceDevice: 1,
|
|
||||||
conversationMerge: {
|
conversationMerge: {
|
||||||
renderInfo: {
|
renderInfo: {
|
||||||
type: 'private',
|
type: 'private',
|
||||||
|
@ -407,4 +437,42 @@ describe('backup/non-bubble messages', () => {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('roundtrips session switchover', async () => {
|
||||||
|
await symmetricRoundtripHarness([
|
||||||
|
{
|
||||||
|
conversationId: contactA.id,
|
||||||
|
id: generateGuid(),
|
||||||
|
type: 'phone-number-discovery',
|
||||||
|
received_at: 1,
|
||||||
|
sent_at: 1,
|
||||||
|
timestamp: 1,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
|
phoneNumberDiscovery: {
|
||||||
|
e164: '+12125551234',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: DESKTOP-7122
|
||||||
|
it.skip('roundtrips unsupported message', async () => {
|
||||||
|
await symmetricRoundtripHarness([
|
||||||
|
{
|
||||||
|
conversationId: contactA.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,
|
||||||
|
supportedVersionAtReceive: 1,
|
||||||
|
requiredProtocolVersion: 2,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,9 +5,12 @@
|
||||||
|
|
||||||
import { ipcRenderer as ipc } from 'electron';
|
import { ipcRenderer as ipc } from 'electron';
|
||||||
import { sync } from 'fast-glob';
|
import { sync } from 'fast-glob';
|
||||||
|
import { inspect } from 'util';
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
import { assert } from 'chai';
|
import { assert, config as chaiConfig } from 'chai';
|
||||||
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
|
import { reporters } from 'mocha';
|
||||||
|
|
||||||
import { getSignalProtocolStore } from '../../SignalProtocolStore';
|
import { getSignalProtocolStore } from '../../SignalProtocolStore';
|
||||||
import { initMessageCleanup } from '../../services/messageStateCleanup';
|
import { initMessageCleanup } from '../../services/messageStateCleanup';
|
||||||
|
@ -16,6 +19,28 @@ import { initializeRedux } from '../../state/initializeRedux';
|
||||||
import * as Stickers from '../../types/Stickers';
|
import * as Stickers from '../../types/Stickers';
|
||||||
import { ThemeType } from '../../types/Util';
|
import { ThemeType } from '../../types/Util';
|
||||||
|
|
||||||
|
// Show actual objects instead of abbreviated errors
|
||||||
|
chaiConfig.truncateThreshold = 0;
|
||||||
|
|
||||||
|
function patchDeepEqual(method: 'deepEqual' | 'deepStrictEqual'): void {
|
||||||
|
const originalFn = assert[method];
|
||||||
|
assert[method] = (...args) => {
|
||||||
|
try {
|
||||||
|
return originalFn(...args);
|
||||||
|
} catch (error) {
|
||||||
|
reporters.base.useColors = false;
|
||||||
|
error.message = reporters.base.generateDiff(
|
||||||
|
inspect(error.actual, { depth: Infinity, sorted: true }),
|
||||||
|
inspect(error.expected, { depth: Infinity, sorted: true })
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
patchDeepEqual('deepEqual');
|
||||||
|
patchDeepEqual('deepStrictEqual');
|
||||||
|
|
||||||
window.assert = assert;
|
window.assert = assert;
|
||||||
|
|
||||||
// This is a hack to let us run TypeScript tests in the renderer process. See the
|
// This is a hack to let us run TypeScript tests in the renderer process. See the
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue