Import/export gift badges, other fields

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal 2024-06-12 17:57:02 -05:00 committed by GitHub
parent ab41aa1942
commit d426109734
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 536 additions and 55 deletions

View file

@ -118,6 +118,7 @@ describe('backup/attachments', () => {
timestamp,
readStatus: ReadStatus.Read,
seenStatus: SeenStatus.Seen,
unidentifiedDeliveryReceived: true,
...overrides,
};
}

View file

@ -5,6 +5,7 @@ import { v4 as generateGuid } from 'uuid';
import { SendStatus } from '../../messages/MessageSendState';
import type { ConversationModel } from '../../models/conversations';
import { GiftBadgeStates } from '../../components/conversation/Message';
import Data from '../../sql/Client';
import { generateAci } from '../../types/ServiceId';
@ -15,6 +16,15 @@ import { setupBasics, symmetricRoundtripHarness, OUR_ACI } from './helpers';
const CONTACT_A = generateAci();
const BADGE_RECEIPT =
'AEpyZxbRBT+T5PQw9Wcx1QE2aFvL7LoLir9V4UF09Kk9qiP4SpIlHdlWHrAICy6F' +
'6WdbdCj45fY6cadDKbBmkw+abohRTJnItrFhyKurnA5X+mZHZv4OvS+aZFmAYS6J' +
'W+hpkbI+Fk7Gu3mEix7Pgz1I2EwGFlUBpm7/nuD5A0cKLrUJAMM142fnOEervePV' +
'bf0c6Sw5X5aCsBw9J+dxFUGAAAAAAAAAAMH58UUeUj2oH1jfqc0Hb2RUtdA3ee8X' +
'0Pp83WT8njwFw5rNGSHeKqOvBZzfAhMGJoiz7l1XfIfsPIreaFb/tA9aq2bOAdDl' +
'5OYlxxl6DnjQ3+g3k9ycpl0elkaQnPW2Ai7yjeJ/96K1qssR2a/2b7xi10dmTRGg' +
'gebhZnroYYgIgK22ZgAAAABkAAAAAAAAAD9j4f77Xo2Ox5tVyrV2DUo=';
describe('backup/bubble messages', () => {
let contactA: ConversationModel;
@ -48,6 +58,7 @@ describe('backup/bubble messages', () => {
body: 'd',
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
editMessageTimestamp: 5,
editMessageReceivedAtMs: 5,
editHistory: [
@ -89,6 +100,7 @@ describe('backup/bubble messages', () => {
status: SendStatus.Delivered,
},
},
unidentifiedDeliveries: [CONTACT_A],
timestamp: 3,
editMessageTimestamp: 5,
editMessageReceivedAtMs: 5,
@ -131,4 +143,224 @@ describe('backup/bubble messages', () => {
},
]);
});
it.skip('roundtrips unopened gift badge', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
id: generateGuid(),
type: 'incoming',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
sourceServiceId: CONTACT_A,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
timestamp: 3,
giftBadge: {
id: undefined,
level: 100,
expiration: 1723248000000,
receiptCredentialPresentation: BADGE_RECEIPT,
state: GiftBadgeStates.Opened,
},
},
]);
});
it.skip('roundtrips opened gift badge', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
id: generateGuid(),
type: 'incoming',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
sourceServiceId: CONTACT_A,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
timestamp: 3,
giftBadge: {
id: undefined,
level: 100,
expiration: 1723248000000,
receiptCredentialPresentation: BADGE_RECEIPT,
state: GiftBadgeStates.Opened,
},
},
]);
});
it.skip('roundtrips gift badge quote', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
id: generateGuid(),
type: 'incoming',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
sourceServiceId: CONTACT_A,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
timestamp: 3,
giftBadge: {
id: undefined,
level: 100,
expiration: 1723248000000,
receiptCredentialPresentation: BADGE_RECEIPT,
state: GiftBadgeStates.Opened,
},
},
{
conversationId: contactA.id,
id: generateGuid(),
type: 'incoming',
received_at: 4,
received_at_ms: 4,
sent_at: 4,
sourceServiceId: CONTACT_A,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
timestamp: 4,
quote: {
authorAci: CONTACT_A,
attachments: [],
id: 3,
isViewOnce: false,
isGiftBadge: true,
messageId: '',
referencedMessageNotFound: false,
},
},
]);
});
it('roundtrips sealed/unsealed incoming message', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
id: generateGuid(),
type: 'incoming',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
sourceServiceId: CONTACT_A,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: false,
timestamp: 3,
body: 'unsealed',
},
{
conversationId: contactA.id,
id: generateGuid(),
type: 'incoming',
received_at: 4,
received_at_ms: 4,
sent_at: 4,
sourceServiceId: CONTACT_A,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
timestamp: 4,
body: 'sealed',
},
]);
});
it('roundtrips sealed/unsealed outgoing message', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
id: generateGuid(),
type: 'outgoing',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
sourceServiceId: OUR_ACI,
sendStateByConversationId: {
[contactA.id]: {
status: SendStatus.Delivered,
},
},
unidentifiedDeliveries: undefined,
timestamp: 3,
body: 'unsealed',
},
{
conversationId: contactA.id,
id: generateGuid(),
type: 'outgoing',
received_at: 4,
received_at_ms: 4,
sent_at: 4,
sourceServiceId: OUR_ACI,
sendStateByConversationId: {
[contactA.id]: {
status: SendStatus.Delivered,
},
},
unidentifiedDeliveries: [CONTACT_A],
timestamp: 4,
body: 'sealed',
},
]);
});
it('roundtrips messages with send errors', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
id: generateGuid(),
type: 'outgoing',
received_at: 3,
received_at_ms: 3,
sent_at: 3,
sourceServiceId: OUR_ACI,
sendStateByConversationId: {
[contactA.id]: {
status: SendStatus.Delivered,
},
},
errors: [
{
serviceId: CONTACT_A,
name: 'OutgoingIdentityKeyError',
message: `The identity of ${CONTACT_A} has changed.`,
},
],
timestamp: 3,
body: 'body',
},
{
conversationId: contactA.id,
id: generateGuid(),
type: 'outgoing',
received_at: 4,
received_at_ms: 4,
sent_at: 4,
sourceServiceId: OUR_ACI,
sendStateByConversationId: {
[contactA.id]: {
status: SendStatus.Delivered,
},
},
errors: [
{
serviceId: CONTACT_A,
name: 'OutgoingMessageError',
message: 'no http error',
},
],
timestamp: 4,
body: 'body',
},
]);
});
});

View file

@ -93,36 +93,39 @@ function sortAndNormalize(
return result;
}
return {
...rest,
conversationId: mapConvoId(conversationId),
reactions: reactions?.map(({ fromId, ...restOfReaction }) => {
return {
from: mapConvoId(fromId),
...restOfReaction,
};
}),
changedId: mapConvoId(changedId),
key_changed: mapConvoId(keyChanged),
verifiedChanged: mapConvoId(verifiedChanged),
sendStateByConverationId: mapSendState(sendStateByConversationId),
editHistory: editHistory?.map(history => {
const {
sendStateByConversationId: historySendState,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
received_at: _receivedAtHistory,
...restOfHistory
} = history;
// Get rid of unserializable `undefined` values.
return JSON.parse(
JSON.stringify({
...rest,
conversationId: mapConvoId(conversationId),
reactions: reactions?.map(({ fromId, ...restOfReaction }) => {
return {
from: mapConvoId(fromId),
...restOfReaction,
};
}),
changedId: mapConvoId(changedId),
key_changed: mapConvoId(keyChanged),
verifiedChanged: mapConvoId(verifiedChanged),
sendStateByConverationId: mapSendState(sendStateByConversationId),
editHistory: editHistory?.map(history => {
const {
sendStateByConversationId: historySendState,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
received_at: _receivedAtHistory,
...restOfHistory
} = history;
return {
...restOfHistory,
sendStateByConversationId: mapSendState(historySendState),
};
}),
return {
...restOfHistory,
sendStateByConversationId: mapSendState(historySendState),
};
}),
// Not an original property, but useful
isUnsupported: isUnsupportedMessage(message),
};
// Not an original property, but useful
isUnsupported: isUnsupportedMessage(message),
})
);
});
}

View file

@ -66,6 +66,7 @@ describe('backup/non-bubble messages', () => {
sourceDevice: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
flags: Proto.DataMessage.Flags.END_SESSION,
},
]);
@ -204,6 +205,7 @@ describe('backup/non-bubble messages', () => {
timestamp: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
},
]);
});
@ -224,12 +226,12 @@ describe('backup/non-bubble messages', () => {
timestamp: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
},
]);
});
// TODO: DESKTOP-7122
it.skip('roundtrips bare payments notification', async () => {
it('roundtrips bare payments notification', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
@ -243,6 +245,7 @@ describe('backup/non-bubble messages', () => {
sourceDevice: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
payment: {
kind: PaymentEventKind.Notification,
note: 'note with text',
@ -251,8 +254,7 @@ describe('backup/non-bubble messages', () => {
]);
});
// TODO: DESKTOP-7122
it.skip('roundtrips full payments notification', async () => {
it('roundtrips full payments notification', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
@ -266,6 +268,7 @@ describe('backup/non-bubble messages', () => {
sourceDevice: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
payment: {
kind: PaymentEventKind.Notification,
note: 'note with text',
@ -297,6 +300,7 @@ describe('backup/non-bubble messages', () => {
sourceDevice: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
contact: [
{
name: {
@ -339,6 +343,7 @@ describe('backup/non-bubble messages', () => {
sourceDevice: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
// TODO (DESKTOP-6845): properly handle data FilePointer
sticker: {
emoji: '👍',
@ -373,6 +378,7 @@ describe('backup/non-bubble messages', () => {
sourceDevice: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
unidentifiedDeliveryReceived: true,
isErased: true,
},
]);
@ -475,8 +481,7 @@ describe('backup/non-bubble messages', () => {
]);
});
// TODO: DESKTOP-7122
it.skip('roundtrips unsupported message', async () => {
it('roundtrips unsupported message', async () => {
await symmetricRoundtripHarness([
{
conversationId: contactA.id,
@ -490,8 +495,9 @@ describe('backup/non-bubble messages', () => {
timestamp: 1,
readStatus: ReadStatus.Unread,
seenStatus: SeenStatus.Unseen,
supportedVersionAtReceive: 1,
requiredProtocolVersion: 2,
unidentifiedDeliveryReceived: true,
supportedVersionAtReceive: 5,
requiredProtocolVersion: 6,
},
]);
});