signal-desktop/ts/util/attachments.ts

99 lines
3 KiB
TypeScript
Raw Normal View History

2021-10-27 17:54:16 +00:00
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { blobToArrayBuffer } from 'blob-util';
2021-10-27 17:54:16 +00:00
import * as log from '../logging/log';
import { scaleImageToLevel } from './scaleImageToLevel';
2023-10-04 00:09:31 +00:00
import { dropNull } from './dropNull';
import type {
AttachmentType,
UploadedAttachmentType,
} from '../types/Attachment';
import { canBeTranscoded } from '../types/Attachment';
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
// 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> => {
if (!canBeTranscoded(attachment)) {
return attachment;
}
let scaleTarget: string | Blob;
const { data, path, size } = attachment;
if (data) {
scaleTarget = new Blob([data], {
type: attachment.contentType,
});
} else {
if (!path) {
return attachment;
}
scaleTarget = window.Signal.Migrations.getAbsoluteAttachmentPath(path);
}
try {
const { blob: xcodedDataBlob } = await scaleImageToLevel({
fileOrBlobOrURL: scaleTarget,
contentType: attachment.contentType,
size,
highQuality: false,
});
const xcodedDataArrayBuffer = await blobToArrayBuffer(xcodedDataBlob);
// IMPORTANT: We overwrite the existing `data` `Uint8Array` losing the original
// image data. Ideally, wed preserve the original image data for users who want to
// retain it but due to reports of data loss, we dont 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.
const xcodedAttachment = {
2023-03-27 23:48:57 +00:00
...attachment,
data: new Uint8Array(xcodedDataArrayBuffer),
size: xcodedDataArrayBuffer.byteLength,
2024-01-04 19:34:53 +00:00
path: undefined,
};
2021-10-27 17:54:16 +00:00
return xcodedAttachment;
} catch (error: unknown) {
const errorString = Errors.toLogFormat(error);
log.error(
'downscaleOutgoingAttachment: Failed to scale attachment',
errorString
);
2021-10-27 17:54:16 +00:00
return attachment;
2021-10-27 17:54:16 +00:00
}
};
2023-10-04 00:09:31 +00:00
export type CdnFieldsType = Pick<
AttachmentType,
'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),
iv: Bytes.toBase64(uploaded.iv),
2023-10-04 00:09:31 +00:00
digest: Bytes.toBase64(uploaded.digest),
plaintextHash: uploaded.plaintextHash,
2023-10-04 00:09:31 +00:00
};
}