2021-10-27 17:54:16 +00:00
|
|
|
|
// Copyright 2021 Signal Messenger, LLC
|
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
|
2022-10-24 20:46:36 +00:00
|
|
|
|
import { blobToArrayBuffer } from 'blob-util';
|
2021-10-27 17:54:16 +00:00
|
|
|
|
|
2024-03-06 21:49:21 +00:00
|
|
|
|
import * as log from '../logging/log';
|
2022-10-24 20:46:36 +00:00
|
|
|
|
import { scaleImageToLevel } from './scaleImageToLevel';
|
2023-10-04 00:09:31 +00:00
|
|
|
|
import { dropNull } from './dropNull';
|
|
|
|
|
import type {
|
|
|
|
|
AttachmentType,
|
|
|
|
|
UploadedAttachmentType,
|
|
|
|
|
} from '../types/Attachment';
|
2022-10-24 20:46:36 +00:00
|
|
|
|
import { canBeTranscoded } from '../types/Attachment';
|
2022-11-22 18:43:43 +00:00
|
|
|
|
import * as Errors from '../types/errors';
|
2023-10-04 00:09:31 +00:00
|
|
|
|
import * as Bytes from '../Bytes';
|
2021-10-27 17:54:16 +00:00
|
|
|
|
|
2024-03-06 21:49:21 +00:00
|
|
|
|
// All outgoing images go through handleImageAttachment before being sent and thus have
|
|
|
|
|
// already been scaled to high-quality level, stripped of exif data, and saved. This
|
|
|
|
|
// should be called just before message send to downscale the attachment further if
|
|
|
|
|
// needed.
|
|
|
|
|
export const downscaleOutgoingAttachment = async (
|
|
|
|
|
attachment: AttachmentType
|
|
|
|
|
): Promise<AttachmentType> => {
|
2022-10-24 20:46:36 +00:00
|
|
|
|
if (!canBeTranscoded(attachment)) {
|
|
|
|
|
return attachment;
|
|
|
|
|
}
|
2023-10-30 16:24:28 +00:00
|
|
|
|
|
|
|
|
|
let scaleTarget: string | Blob;
|
2024-03-06 21:49:21 +00:00
|
|
|
|
const { data, path, size } = attachment;
|
|
|
|
|
|
2024-01-03 01:37:01 +00:00
|
|
|
|
if (data) {
|
2023-10-30 16:24:28 +00:00
|
|
|
|
scaleTarget = new Blob([data], {
|
|
|
|
|
type: attachment.contentType,
|
|
|
|
|
});
|
2024-01-03 01:37:01 +00:00
|
|
|
|
} else {
|
|
|
|
|
if (!path) {
|
|
|
|
|
return attachment;
|
|
|
|
|
}
|
|
|
|
|
scaleTarget = window.Signal.Migrations.getAbsoluteAttachmentPath(path);
|
2023-10-30 16:24:28 +00:00
|
|
|
|
}
|
2022-04-27 18:40:58 +00:00
|
|
|
|
|
2022-10-24 20:46:36 +00:00
|
|
|
|
try {
|
2024-03-06 21:49:21 +00:00
|
|
|
|
const { blob: xcodedDataBlob } = await scaleImageToLevel({
|
|
|
|
|
fileOrBlobOrURL: scaleTarget,
|
|
|
|
|
contentType: attachment.contentType,
|
2023-10-30 16:24:28 +00:00
|
|
|
|
size,
|
2024-03-06 21:49:21 +00:00
|
|
|
|
highQuality: false,
|
|
|
|
|
});
|
2022-10-24 20:46:36 +00:00
|
|
|
|
const xcodedDataArrayBuffer = await blobToArrayBuffer(xcodedDataBlob);
|
2022-04-27 18:40:58 +00:00
|
|
|
|
|
2022-10-24 20:46:36 +00:00
|
|
|
|
// 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
|
|
|
|
|
// retain it but due to reports of data loss, we don’t want to overburden IndexedDB
|
|
|
|
|
// by potentially doubling stored image data.
|
|
|
|
|
// See: https://github.com/signalapp/Signal-Desktop/issues/1589
|
2024-01-04 19:34:53 +00:00
|
|
|
|
// We also clear out the attachment path because we're changing
|
|
|
|
|
// the attachment data so it no longer matches the old path.
|
|
|
|
|
// Path and data should always be in agreement.
|
2022-10-24 20:46:36 +00:00
|
|
|
|
const xcodedAttachment = {
|
2023-03-27 23:48:57 +00:00
|
|
|
|
...attachment,
|
2022-10-24 20:46:36 +00:00
|
|
|
|
data: new Uint8Array(xcodedDataArrayBuffer),
|
|
|
|
|
size: xcodedDataArrayBuffer.byteLength,
|
2024-01-04 19:34:53 +00:00
|
|
|
|
path: undefined,
|
2022-10-24 20:46:36 +00:00
|
|
|
|
};
|
2021-10-27 17:54:16 +00:00
|
|
|
|
|
2022-10-24 20:46:36 +00:00
|
|
|
|
return xcodedAttachment;
|
|
|
|
|
} catch (error: unknown) {
|
2022-11-22 18:43:43 +00:00
|
|
|
|
const errorString = Errors.toLogFormat(error);
|
2024-03-06 21:49:21 +00:00
|
|
|
|
log.error(
|
|
|
|
|
'downscaleOutgoingAttachment: Failed to scale attachment',
|
2022-10-24 20:46:36 +00:00
|
|
|
|
errorString
|
|
|
|
|
);
|
2021-10-27 17:54:16 +00:00
|
|
|
|
|
2022-10-24 20:46:36 +00:00
|
|
|
|
return attachment;
|
2021-10-27 17:54:16 +00:00
|
|
|
|
}
|
2024-03-06 21:49:21 +00:00
|
|
|
|
};
|
2023-10-04 00:09:31 +00:00
|
|
|
|
|
|
|
|
|
export type CdnFieldsType = Pick<
|
|
|
|
|
AttachmentType,
|
2024-05-29 01:12:14 +00:00
|
|
|
|
'cdnId' | 'cdnKey' | 'cdnNumber' | 'key' | 'digest' | 'iv' | 'plaintextHash'
|
2023-10-04 00:09:31 +00:00
|
|
|
|
>;
|
|
|
|
|
|
|
|
|
|
export function copyCdnFields(
|
|
|
|
|
uploaded?: UploadedAttachmentType
|
|
|
|
|
): CdnFieldsType {
|
|
|
|
|
if (!uploaded) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
return {
|
|
|
|
|
cdnId: dropNull(uploaded.cdnId)?.toString(),
|
|
|
|
|
cdnKey: uploaded.cdnKey,
|
|
|
|
|
cdnNumber: dropNull(uploaded.cdnNumber),
|
|
|
|
|
key: Bytes.toBase64(uploaded.key),
|
2024-05-29 01:12:14 +00:00
|
|
|
|
iv: Bytes.toBase64(uploaded.iv),
|
2023-10-04 00:09:31 +00:00
|
|
|
|
digest: Bytes.toBase64(uploaded.digest),
|
2023-11-17 20:02:02 +00:00
|
|
|
|
plaintextHash: uploaded.plaintextHash,
|
2023-10-04 00:09:31 +00:00
|
|
|
|
};
|
|
|
|
|
}
|