More lenient attachment v2 migration

This commit is contained in:
Fedor Indutny 2024-07-15 14:27:54 -07:00 committed by GitHub
parent 12b57601ac
commit 3f9032035f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 72 additions and 43 deletions

View file

@ -466,21 +466,26 @@ const toVersion12 = _withSchemaVersion({
const result = { ...message }; const result = { ...message };
const logId = `Message2.toVersion12(${message.sent_at})`;
if (attachments?.length) { if (attachments?.length) {
result.attachments = await Promise.all( result.attachments = await Promise.all(
attachments.map(async attachment => { attachments.map(async (attachment, i) => {
const copy = await encryptLegacyAttachment(attachment, context); const copy = await encryptLegacyAttachment(attachment, {
...context,
logId: `${logId}.attachments[${i}]`,
});
if (copy.thumbnail) { if (copy.thumbnail) {
copy.thumbnail = await encryptLegacyAttachment( copy.thumbnail = await encryptLegacyAttachment(copy.thumbnail, {
copy.thumbnail, ...context,
context logId: `${logId}.attachments[${i}].thumbnail`,
); });
} }
if (copy.screenshot) { if (copy.screenshot) {
copy.screenshot = await encryptLegacyAttachment( copy.screenshot = await encryptLegacyAttachment(copy.screenshot, {
copy.screenshot, ...context,
context logId: `${logId}.attachments[${i}].screenshot`,
); });
} }
return copy; return copy;
}) })
@ -488,31 +493,27 @@ const toVersion12 = _withSchemaVersion({
} }
if (quote && quote.attachments?.length) { if (quote && quote.attachments?.length) {
try { result.quote = {
result.quote = { ...quote,
...quote, attachments: await Promise.all(
attachments: await Promise.all( quote.attachments.map(async (quoteAttachment, i) => {
quote.attachments.map(async quoteAttachment => { return {
return { ...quoteAttachment,
...quoteAttachment, thumbnail:
thumbnail: quoteAttachment.thumbnail &&
quoteAttachment.thumbnail && (await encryptLegacyAttachment(quoteAttachment.thumbnail, {
(await encryptLegacyAttachment( ...context,
quoteAttachment.thumbnail, logId: `${logId}.quote[${i}].thumbnail`,
context })),
)), };
}; })
}) ),
), };
};
} catch (error) {
context.logger.error(`Failed to migrate quote for ${message.id}`);
}
} }
if (contact?.length) { if (contact?.length) {
result.contact = await Promise.all( result.contact = await Promise.all(
contact.map(async c => { contact.map(async (c, i) => {
if (!c.avatar?.avatar) { if (!c.avatar?.avatar) {
return c; return c;
} }
@ -521,7 +522,10 @@ const toVersion12 = _withSchemaVersion({
...c, ...c,
avatar: { avatar: {
...c.avatar, ...c.avatar,
avatar: await encryptLegacyAttachment(c.avatar.avatar, context), avatar: await encryptLegacyAttachment(c.avatar.avatar, {
...context,
logId: `${logId}.contact[${i}].avatar`,
}),
}, },
}; };
}) })
@ -530,14 +534,17 @@ const toVersion12 = _withSchemaVersion({
if (preview?.length) { if (preview?.length) {
result.preview = await Promise.all( result.preview = await Promise.all(
preview.map(async p => { preview.map(async (p, i) => {
if (!p.image) { if (!p.image) {
return p; return p;
} }
return { return {
...p, ...p,
image: await encryptLegacyAttachment(p.image, context), image: await encryptLegacyAttachment(p.image, {
...context,
logId: `${logId}.preview[${i}].image`,
}),
}; };
}) })
); );
@ -547,10 +554,16 @@ const toVersion12 = _withSchemaVersion({
result.sticker = { result.sticker = {
...sticker, ...sticker,
data: sticker.data && { data: sticker.data && {
...(await encryptLegacyAttachment(sticker.data, context)), ...(await encryptLegacyAttachment(sticker.data, {
...context,
logId: `${logId}.sticker.data`,
})),
thumbnail: thumbnail:
sticker.data.thumbnail && sticker.data.thumbnail &&
(await encryptLegacyAttachment(sticker.data.thumbnail, context)), (await encryptLegacyAttachment(sticker.data.thumbnail, {
...context,
logId: `${logId}.sticker.thumbnail`,
})),
}, },
}; };
} }

View file

@ -1009,6 +1009,7 @@ async function encryptLegacySticker(
window.Signal.Migrations; window.Signal.Migrations;
const updated = await encryptLegacyAttachment(sticker, { const updated = await encryptLegacyAttachment(sticker, {
logId: 'sticker',
readAttachmentData: readStickerData, readAttachmentData: readStickerData,
writeNewAttachmentData: writeNewStickerData, writeNewAttachmentData: writeNewStickerData,
disposition: AttachmentDisposition.Sticker, disposition: AttachmentDisposition.Sticker,

View file

@ -10,6 +10,7 @@ import { encryptLegacyAttachment } from './encryptLegacyAttachment';
import { AttachmentDisposition } from './getLocalAttachmentUrl'; import { AttachmentDisposition } from './getLocalAttachmentUrl';
import { isNotNil } from './isNotNil'; import { isNotNil } from './isNotNil';
import { isSignalConversation } from './isSignalConversation'; import { isSignalConversation } from './isSignalConversation';
import { getConversationIdForLogging } from './idForLogging';
const CONCURRENCY = 32; const CONCURRENCY = 32;
@ -66,6 +67,7 @@ async function encryptOne(attributes: ConversationAttributesType): Promise<
return undefined; return undefined;
} }
const logId = getConversationIdForLogging(attributes);
const result = { ...attributes }; const result = { ...attributes };
const { const {
@ -86,6 +88,7 @@ async function encryptOne(attributes: ConversationAttributesType): Promise<
result.profileAvatar = await encryptLegacyAttachment( result.profileAvatar = await encryptLegacyAttachment(
attributes.profileAvatar, attributes.profileAvatar,
{ {
logId: `${logId}.profileAvatar`,
readAttachmentData, readAttachmentData,
writeNewAttachmentData, writeNewAttachmentData,
disposition: AttachmentDisposition.Attachment, disposition: AttachmentDisposition.Attachment,
@ -99,6 +102,7 @@ async function encryptOne(attributes: ConversationAttributesType): Promise<
if (attributes.avatar?.path) { if (attributes.avatar?.path) {
result.avatar = await encryptLegacyAttachment(attributes.avatar, { result.avatar = await encryptLegacyAttachment(attributes.avatar, {
logId: `${logId}.avatar`,
readAttachmentData, readAttachmentData,
writeNewAttachmentData, writeNewAttachmentData,
disposition: AttachmentDisposition.Attachment, disposition: AttachmentDisposition.Attachment,
@ -111,7 +115,7 @@ async function encryptOne(attributes: ConversationAttributesType): Promise<
if (attributes.avatars?.length) { if (attributes.avatars?.length) {
result.avatars = await Promise.all( result.avatars = await Promise.all(
attributes.avatars.map(async avatar => { attributes.avatars.map(async (avatar, i) => {
if (avatar.version === 2 || !avatar.imagePath) { if (avatar.version === 2 || !avatar.imagePath) {
return avatar; return avatar;
} }
@ -121,6 +125,7 @@ async function encryptOne(attributes: ConversationAttributesType): Promise<
path: avatar.imagePath, path: avatar.imagePath,
}, },
{ {
logId: `${logId}.avatars[${i}]`,
readAttachmentData: readAvatarData, readAttachmentData: readAvatarData,
writeNewAttachmentData: writeNewAvatarData, writeNewAttachmentData: writeNewAvatarData,
disposition: AttachmentDisposition.AvatarData, disposition: AttachmentDisposition.AvatarData,
@ -141,8 +146,9 @@ async function encryptOne(attributes: ConversationAttributesType): Promise<
if (attributes.draftAttachments?.length) { if (attributes.draftAttachments?.length) {
result.draftAttachments = await Promise.all( result.draftAttachments = await Promise.all(
attributes.draftAttachments.map(async draft => { attributes.draftAttachments.map(async (draft, i) => {
const updated = await encryptLegacyAttachment(draft, { const updated = await encryptLegacyAttachment(draft, {
logId: `${logId}.draft[${i}]`,
readAttachmentData: readDraftData, readAttachmentData: readDraftData,
writeNewAttachmentData: writeNewDraftData, writeNewAttachmentData: writeNewDraftData,
disposition: AttachmentDisposition.Draft, disposition: AttachmentDisposition.Draft,

View file

@ -2,10 +2,12 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
import LRU from 'lru-cache'; import LRU from 'lru-cache';
import type { import type {
AddressableAttachmentType, AddressableAttachmentType,
LocalAttachmentV2Type, LocalAttachmentV2Type,
} from '../types/Attachment'; } from '../types/Attachment';
import * as log from '../logging/log';
import { AttachmentDisposition } from './getLocalAttachmentUrl'; import { AttachmentDisposition } from './getLocalAttachmentUrl';
let setCheck = false; let setCheck = false;
@ -15,6 +17,7 @@ const lru = new LRU<string, Promise<LocalAttachmentV2Type>>({
}); });
export type EncryptLegacyAttachmentOptionsType = Readonly<{ export type EncryptLegacyAttachmentOptionsType = Readonly<{
logId: string;
disposition?: AttachmentDisposition; disposition?: AttachmentDisposition;
readAttachmentData: ( readAttachmentData: (
attachment: Partial<AddressableAttachmentType> attachment: Partial<AddressableAttachmentType>
@ -43,12 +46,18 @@ export async function encryptLegacyAttachment<
promise = doEncrypt(attachment, options); promise = doEncrypt(attachment, options);
lru.set(cacheKey, promise); lru.set(cacheKey, promise);
} }
const modern = await promise; try {
const modern = await promise;
return { return {
...attachment, ...attachment,
...modern, ...modern,
}; };
} catch (error) {
const { logId } = options;
log.error(`${logId}: migration failed, falling back to original`, error);
return attachment;
}
} }
async function doEncrypt<T extends Partial<AddressableAttachmentType>>( async function doEncrypt<T extends Partial<AddressableAttachmentType>>(