updateSchema: Be resilient to invalid images
This commit is contained in:
parent
5fcf97b43b
commit
064f3dd0e0
|
@ -28,6 +28,7 @@ import { scaleImageToLevel } from '../util/scaleImageToLevel';
|
||||||
import * as GoogleChrome from '../util/GoogleChrome';
|
import * as GoogleChrome from '../util/GoogleChrome';
|
||||||
import { parseIntOrThrow } from '../util/parseIntOrThrow';
|
import { parseIntOrThrow } from '../util/parseIntOrThrow';
|
||||||
import { getValue } from '../RemoteConfig';
|
import { getValue } from '../RemoteConfig';
|
||||||
|
import { isRecord } from '../util/isRecord';
|
||||||
|
|
||||||
const MAX_WIDTH = 300;
|
const MAX_WIDTH = 300;
|
||||||
const MAX_HEIGHT = MAX_WIDTH * 1.5;
|
const MAX_HEIGHT = MAX_WIDTH * 1.5;
|
||||||
|
@ -251,7 +252,7 @@ export function isValid(
|
||||||
// part of re-encoding the image:
|
// part of re-encoding the image:
|
||||||
export async function autoOrientJPEG(
|
export async function autoOrientJPEG(
|
||||||
attachment: AttachmentType,
|
attachment: AttachmentType,
|
||||||
_: unknown,
|
{ logger }: { logger: LoggerType },
|
||||||
{
|
{
|
||||||
sendHQImages = false,
|
sendHQImages = false,
|
||||||
isIncoming = false,
|
isIncoming = false,
|
||||||
|
@ -280,26 +281,37 @@ export async function autoOrientJPEG(
|
||||||
const dataBlob = new Blob([attachment.data], {
|
const dataBlob = new Blob([attachment.data], {
|
||||||
type: attachment.contentType,
|
type: attachment.contentType,
|
||||||
});
|
});
|
||||||
const { blob: xcodedDataBlob } = await scaleImageToLevel(
|
try {
|
||||||
dataBlob,
|
const { blob: xcodedDataBlob } = await scaleImageToLevel(
|
||||||
attachment.contentType,
|
dataBlob,
|
||||||
isIncoming
|
attachment.contentType,
|
||||||
);
|
isIncoming
|
||||||
const xcodedDataArrayBuffer = await blobToArrayBuffer(xcodedDataBlob);
|
);
|
||||||
|
const xcodedDataArrayBuffer = await blobToArrayBuffer(xcodedDataBlob);
|
||||||
|
|
||||||
// IMPORTANT: We overwrite the existing `data` `Uint8Array` losing the original
|
// IMPORTANT: We overwrite the existing `data` `Uint8Array` losing the original
|
||||||
// image data. Ideally, we’d preserve the original image data for users who want to
|
// image data. Ideally, we’d preserve the original image data for users who want to
|
||||||
// retain it but due to reports of data loss, we don’t want to overburden IndexedDB
|
// retain it but due to reports of data loss, we don’t want to overburden IndexedDB
|
||||||
// by potentially doubling stored image data.
|
// by potentially doubling stored image data.
|
||||||
// See: https://github.com/signalapp/Signal-Desktop/issues/1589
|
// See: https://github.com/signalapp/Signal-Desktop/issues/1589
|
||||||
const xcodedAttachment = {
|
const xcodedAttachment = {
|
||||||
// `digest` is no longer valid for auto-oriented image data, so we discard it:
|
// `digest` is no longer valid for auto-oriented image data, so we discard it:
|
||||||
...omit(attachment, 'digest'),
|
...omit(attachment, 'digest'),
|
||||||
data: new Uint8Array(xcodedDataArrayBuffer),
|
data: new Uint8Array(xcodedDataArrayBuffer),
|
||||||
size: xcodedDataArrayBuffer.byteLength,
|
size: xcodedDataArrayBuffer.byteLength,
|
||||||
};
|
};
|
||||||
|
|
||||||
return xcodedAttachment;
|
return xcodedAttachment;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const errorString =
|
||||||
|
isRecord(error) && 'stack' in error ? error.stack : error;
|
||||||
|
logger.error(
|
||||||
|
'autoOrientJPEG: Failed to rotate/scale attachment',
|
||||||
|
errorString
|
||||||
|
);
|
||||||
|
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const UNICODE_LEFT_TO_RIGHT_OVERRIDE = '\u202D';
|
const UNICODE_LEFT_TO_RIGHT_OVERRIDE = '\u202D';
|
||||||
|
|
|
@ -580,9 +580,13 @@ export const processNewAttachment = async (
|
||||||
throw new TypeError('context.logger is required');
|
throw new TypeError('context.logger is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
const rotatedAttachment = await autoOrientJPEG(attachment, undefined, {
|
const rotatedAttachment = await autoOrientJPEG(
|
||||||
isIncoming: true,
|
attachment,
|
||||||
});
|
{ logger },
|
||||||
|
{
|
||||||
|
isIncoming: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
const onDiskAttachment = await migrateDataToFileSystem(rotatedAttachment, {
|
const onDiskAttachment = await migrateDataToFileSystem(rotatedAttachment, {
|
||||||
writeNewAttachmentData,
|
writeNewAttachmentData,
|
||||||
});
|
});
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { IMAGE_JPEG } from '../types/MIME';
|
||||||
import { canvasToBlob } from './canvasToBlob';
|
import { canvasToBlob } from './canvasToBlob';
|
||||||
import { getValue } from '../RemoteConfig';
|
import { getValue } from '../RemoteConfig';
|
||||||
import { parseNumber } from './libphonenumberUtil';
|
import { parseNumber } from './libphonenumberUtil';
|
||||||
|
import { isRecord } from './isRecord';
|
||||||
|
|
||||||
enum MediaQualityLevels {
|
enum MediaQualityLevels {
|
||||||
One = 1,
|
One = 1,
|
||||||
|
@ -126,7 +127,11 @@ export async function scaleImageToLevel(
|
||||||
}
|
}
|
||||||
({ image } = data);
|
({ image } = data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const error = new Error('scaleImageToLevel: Failed to process image');
|
const errorString = isRecord(err) && 'stack' in err ? err.stack : err;
|
||||||
|
const error = new Error(
|
||||||
|
'scaleImageToLevel: Failed to process image',
|
||||||
|
errorString
|
||||||
|
);
|
||||||
error.originalError = err;
|
error.originalError = err;
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue