diff --git a/ts/services/backups/export.ts b/ts/services/backups/export.ts index 92211c0cb9..e1f257500d 100644 --- a/ts/services/backups/export.ts +++ b/ts/services/backups/export.ts @@ -38,7 +38,6 @@ import type { ConversationAttributesType, MessageAttributesType, QuotedAttachmentType, - QuotedMessageType, } from '../../model-types.d'; import { drop } from '../../util/drop'; import { isNotNil } from '../../util/isNotNil'; @@ -2195,14 +2194,13 @@ export class BackupExportStream extends Readable { } async #toQuote({ - quote, + message, backupLevel, - messageReceivedAt, }: { - quote?: QuotedMessageType; + message: Pick; backupLevel: BackupLevel; - messageReceivedAt: number; }): Promise { + const { quote } = message; if (!quote) { return null; } @@ -2259,7 +2257,7 @@ export class BackupExportStream extends Readable { ? await this.#processMessageAttachment({ attachment: attachment.thumbnail, backupLevel, - messageReceivedAt, + message, }) : undefined, }; @@ -2287,11 +2285,17 @@ export class BackupExportStream extends Readable { } #getMessageAttachmentFlag( + message: Pick, attachment: AttachmentType ): Backups.MessageAttachment.Flag { const flag = SignalService.AttachmentPointer.Flags.VOICE_MESSAGE; // eslint-disable-next-line no-bitwise if (((attachment.flags || 0) & flag) === flag) { + // Legacy data support for iOS + if (message.body) { + return Backups.MessageAttachment.Flag.NONE; + } + return Backups.MessageAttachment.Flag.VOICE_MESSAGE; } if (isGIF([attachment])) { @@ -2311,22 +2315,22 @@ export class BackupExportStream extends Readable { async #processMessageAttachment({ attachment, backupLevel, - messageReceivedAt, + message, }: { attachment: AttachmentType; backupLevel: BackupLevel; - messageReceivedAt: number; + message: Pick; }): Promise { const { clientUuid } = attachment; const filePointer = await this.#processAttachment({ attachment, backupLevel, - messageReceivedAt, + messageReceivedAt: message.received_at, }); return new Backups.MessageAttachment({ pointer: filePointer, - flag: this.#getMessageAttachmentFlag(attachment), + flag: this.#getMessageAttachmentFlag(message, attachment), wasDownloaded: isDownloaded(attachment), clientUuid: clientUuid ? uuidToBytes(clientUuid) : undefined, }); @@ -2550,9 +2554,8 @@ export class BackupExportStream extends Readable { }): Promise { return { quote: await this.#toQuote({ - quote: message.quote, + message, backupLevel, - messageReceivedAt: message.received_at, }), attachments: message.attachments?.length ? await Promise.all( @@ -2560,7 +2563,7 @@ export class BackupExportStream extends Readable { return this.#processMessageAttachment({ attachment, backupLevel, - messageReceivedAt: message.received_at, + message, }); }) ) @@ -2667,7 +2670,7 @@ export class BackupExportStream extends Readable { : await this.#processMessageAttachment({ attachment, backupLevel, - messageReceivedAt: message.received_at, + message, }), reactions: this.#getMessageReactions(message), }; diff --git a/ts/test-electron/backup/attachments_test.ts b/ts/test-electron/backup/attachments_test.ts index afb1b2826d..440c1ecd33 100644 --- a/ts/test-electron/backup/attachments_test.ts +++ b/ts/test-electron/backup/attachments_test.ts @@ -355,6 +355,39 @@ describe('backup/attachments', () => { { backupLevel: BackupLevel.Paid } ); }); + it('drops voice message flag when body is present', async () => { + const attachment = composeAttachment(1); + attachment.contentType = AUDIO_MP3; + attachment.flags = SignalService.AttachmentPointer.Flags.VOICE_MESSAGE; + + strictAssert(isVoiceMessage(attachment), 'it is a voice attachment'); + strictAssert(attachment.digest, 'digest exists'); + + await asymmetricRoundtripHarness( + [ + composeMessage(1, { + body: 'hello', + attachments: [attachment], + }), + ], + [ + composeMessage(1, { + body: 'hello', + hasAttachments: true, + attachments: [ + { + ...omit(attachment, NON_ROUNDTRIPPED_BACKUP_LOCATOR_FIELDS), + flags: undefined, + backupLocator: { + mediaName: digestToMediaName(attachment.digest), + }, + }, + ], + }), + ], + { backupLevel: BackupLevel.Paid } + ); + }); }); describe('Preview attachments', () => {