Import/export view-once messages
This commit is contained in:
parent
2f6270c585
commit
ce090a8a3c
4 changed files with 66 additions and 3 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -194,7 +194,7 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: 'signalapp/Signal-Message-Backup-Tests'
|
repository: 'signalapp/Signal-Message-Backup-Tests'
|
||||||
ref: '996daf691d4162ce854845dc883c62adb1a3fe55'
|
ref: 'c84390838f65c6c0927c9bbcc3a240f986fc4a80'
|
||||||
path: 'backup-integration-tests'
|
path: 'backup-integration-tests'
|
||||||
|
|
||||||
- run: xvfb-run --auto-servernum npm run test-electron
|
- run: xvfb-run --auto-servernum npm run test-electron
|
||||||
|
|
|
@ -342,6 +342,7 @@ message ChatItem {
|
||||||
ChatUpdateMessage updateMessage = 15;
|
ChatUpdateMessage updateMessage = 15;
|
||||||
PaymentNotification paymentNotification = 16;
|
PaymentNotification paymentNotification = 16;
|
||||||
GiftBadge giftBadge = 17;
|
GiftBadge giftBadge = 17;
|
||||||
|
ViewOnceMessage viewOnceMessage = 18;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -470,6 +471,12 @@ message GiftBadge {
|
||||||
State state = 2;
|
State state = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ViewOnceMessage {
|
||||||
|
// Will be null for viewed messages
|
||||||
|
MessageAttachment attachment = 1;
|
||||||
|
repeated Reaction reactions = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message ContactAttachment {
|
message ContactAttachment {
|
||||||
message Name {
|
message Name {
|
||||||
optional string givenName = 1;
|
optional string givenName = 1;
|
||||||
|
|
|
@ -77,6 +77,7 @@ import {
|
||||||
isNormalBubble,
|
isNormalBubble,
|
||||||
isPhoneNumberDiscovery,
|
isPhoneNumberDiscovery,
|
||||||
isProfileChange,
|
isProfileChange,
|
||||||
|
isTapToView,
|
||||||
isUniversalTimerNotification,
|
isUniversalTimerNotification,
|
||||||
isUnsupportedMessage,
|
isUnsupportedMessage,
|
||||||
isVerifiedChange,
|
isVerifiedChange,
|
||||||
|
@ -1060,7 +1061,12 @@ export class BackupExportStream extends Readable {
|
||||||
}
|
}
|
||||||
|
|
||||||
const { contact, sticker } = message;
|
const { contact, sticker } = message;
|
||||||
if (message.isErased) {
|
if (isTapToView(message)) {
|
||||||
|
result.viewOnceMessage = await this.toViewOnceMessage({
|
||||||
|
message,
|
||||||
|
backupLevel,
|
||||||
|
});
|
||||||
|
} else if (message.isErased) {
|
||||||
result.remoteDeletedMessage = {};
|
result.remoteDeletedMessage = {};
|
||||||
} else if (messageHasPaymentEvent(message)) {
|
} else if (messageHasPaymentEvent(message)) {
|
||||||
const { payment } = message;
|
const { payment } = message;
|
||||||
|
@ -2265,7 +2271,7 @@ export class BackupExportStream extends Readable {
|
||||||
serverTimestamp != null
|
serverTimestamp != null
|
||||||
? getSafeLongFromTimestamp(serverTimestamp)
|
? getSafeLongFromTimestamp(serverTimestamp)
|
||||||
: null,
|
: null,
|
||||||
read: readStatus === ReadStatus.Read,
|
read: readStatus === ReadStatus.Read || readStatus === ReadStatus.Viewed,
|
||||||
sealedSender: unidentifiedDeliveryReceived === true,
|
sealedSender: unidentifiedDeliveryReceived === true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -2443,6 +2449,30 @@ export class BackupExportStream extends Readable {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async toViewOnceMessage({
|
||||||
|
message,
|
||||||
|
backupLevel,
|
||||||
|
}: {
|
||||||
|
message: Pick<
|
||||||
|
MessageAttributesType,
|
||||||
|
'attachments' | 'received_at' | 'reactions'
|
||||||
|
>;
|
||||||
|
backupLevel: BackupLevel;
|
||||||
|
}): Promise<Backups.IViewOnceMessage> {
|
||||||
|
const attachment = message.attachments?.at(0);
|
||||||
|
return {
|
||||||
|
attachment:
|
||||||
|
attachment == null
|
||||||
|
? null
|
||||||
|
: await this.processMessageAttachment({
|
||||||
|
attachment,
|
||||||
|
backupLevel,
|
||||||
|
messageReceivedAt: message.received_at,
|
||||||
|
}),
|
||||||
|
reactions: this.getMessageReactions(message),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private async toChatItemRevisions(
|
private async toChatItemRevisions(
|
||||||
parent: Backups.IChatItem,
|
parent: Backups.IChatItem,
|
||||||
message: MessageAttributesType,
|
message: MessageAttributesType,
|
||||||
|
|
|
@ -1303,6 +1303,11 @@ export class BackupImportStream extends Writable {
|
||||||
...attributes,
|
...attributes,
|
||||||
...(await this.fromStandardMessage(item.standardMessage, chatConvo.id)),
|
...(await this.fromStandardMessage(item.standardMessage, chatConvo.id)),
|
||||||
};
|
};
|
||||||
|
} else if (item.viewOnceMessage) {
|
||||||
|
attributes = {
|
||||||
|
...attributes,
|
||||||
|
...(await this.fromViewOnceMessage(item.viewOnceMessage)),
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
const result = await this.fromNonBubbleChatItem(item, {
|
const result = await this.fromNonBubbleChatItem(item, {
|
||||||
aboutMe,
|
aboutMe,
|
||||||
|
@ -1566,6 +1571,27 @@ export class BackupImportStream extends Writable {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async fromViewOnceMessage({
|
||||||
|
attachment,
|
||||||
|
reactions,
|
||||||
|
}: Backups.IViewOnceMessage): Promise<Partial<MessageAttributesType>> {
|
||||||
|
return {
|
||||||
|
...(attachment
|
||||||
|
? {
|
||||||
|
attachments: [
|
||||||
|
convertBackupMessageAttachmentToAttachment(attachment),
|
||||||
|
].filter(isNotNil),
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
attachments: undefined,
|
||||||
|
readStatus: ReadStatus.Viewed,
|
||||||
|
isErased: true,
|
||||||
|
}),
|
||||||
|
reactions: this.fromReactions(reactions),
|
||||||
|
isViewOnce: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private async fromRevisions(
|
private async fromRevisions(
|
||||||
mainMessage: MessageAttributesType,
|
mainMessage: MessageAttributesType,
|
||||||
revisions: ReadonlyArray<Backups.IChatItem>
|
revisions: ReadonlyArray<Backups.IChatItem>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue