Minimize processing of forwarded attachments

Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
automated-signal
2025-12-17 13:19:13 -06:00
committed by GitHub
parent 731213e83a
commit d63f89c134
3 changed files with 58 additions and 12 deletions

View File

@@ -4100,12 +4100,14 @@ export class ConversationModel {
},
{
dontClearDraft = false,
isForwarding = false,
sendHQImages,
storyId,
timestamp,
extraReduxActions,
}: {
dontClearDraft?: boolean;
isForwarding?: boolean;
sendHQImages?: boolean;
storyId?: string;
timestamp?: number;
@@ -4176,7 +4178,7 @@ export class ConversationModel {
// any attachments as well.
let attachmentsToSend = preview && preview.length ? [] : attachments;
if (preview && preview.length) {
if (preview && preview.length && !isForwarding) {
attachments.forEach(attachment => {
if (attachment.path) {
void deleteAttachmentData(attachment.path);
@@ -4197,7 +4199,7 @@ export class ConversationModel {
* All draft attachments (with a path or just in-memory) will be written to disk for
* real in `upgradeMessageSchema`.
*/
if (!sendHQImages) {
if (!sendHQImages && !isForwarding) {
attachmentsToSend = await Promise.all(
attachmentsToSend.map(async attachment => {
const downscaledAttachment =

View File

@@ -80,7 +80,7 @@ export async function maybeForwardMessages(
return false;
}
const sendMessageOptions = { dontClearDraft: true };
const sendMessageOptions = { dontClearDraft: true, isForwarding: true };
const baseTimestamp = Date.now();
let timestampOffset = 0;

View File

@@ -6,6 +6,8 @@ import type {
AttachmentWithHydratedData,
UploadedAttachmentType,
} from '../types/Attachment.std.js';
import * as Bytes from '../Bytes.std.js';
import { createLogger } from '../logging/log.std.js';
import { MIMETypeToString, supportsIncrementalMac } from '../types/MIME.std.js';
import { getRandomBytes } from '../Crypto.node.js';
import { backupsService } from '../services/backups/index.preload.js';
@@ -25,24 +27,66 @@ import {
} from '../AttachmentCrypto.node.js';
import { missingCaseError } from './missingCaseError.std.js';
import { uuidToBytes } from './uuidToBytes.std.js';
import { DAY } from './durations/index.std.js';
import { isVisualMedia } from './Attachment.std.js';
import { getAbsoluteAttachmentPath } from './migrations.preload.js';
import { isMoreRecentThan } from './timestamp.std.js';
const CDNS_SUPPORTING_TUS = new Set([3]);
const log = createLogger('uploadAttachment');
export async function uploadAttachment(
attachment: AttachmentWithHydratedData
): Promise<UploadedAttachmentType> {
const keys = getRandomBytes(64);
const needIncrementalMac = supportsIncrementalMac(attachment.contentType);
let keys: Uint8Array;
let cdnKey: string;
let cdnNumber: number;
let encrypted: Pick<
EncryptedAttachmentV2,
'digest' | 'plaintextHash' | 'incrementalMac' | 'chunkSize'
>;
let uploadTimestamp: number;
const uploadTimestamp = Date.now();
const { cdnKey, cdnNumber, encrypted } = await encryptAndUploadAttachment({
keys,
needIncrementalMac,
plaintext: { data: attachment.data },
uploadType: 'standard',
});
// Recently uploaded attachment
if (
attachment.cdnKey &&
attachment.cdnNumber &&
attachment.key &&
attachment.size != null &&
attachment.digest &&
attachment.contentType != null &&
attachment.plaintextHash != null &&
attachment.uploadTimestamp != null &&
isMoreRecentThan(attachment.uploadTimestamp, 3 * DAY)
) {
log.info('reusing attachment uploaded at', attachment.uploadTimestamp);
({ cdnKey, cdnNumber, uploadTimestamp } = attachment);
keys = Bytes.fromBase64(attachment.key);
encrypted = {
digest: Bytes.fromBase64(attachment.digest),
plaintextHash: attachment.plaintextHash,
incrementalMac: attachment.incrementalMac
? Bytes.fromBase64(attachment.incrementalMac)
: undefined,
chunkSize: attachment.chunkSize,
};
} else {
keys = getRandomBytes(64);
uploadTimestamp = Date.now();
const needIncrementalMac = supportsIncrementalMac(attachment.contentType);
({ cdnKey, cdnNumber, encrypted } = await encryptAndUploadAttachment({
keys,
needIncrementalMac,
plaintext: { data: attachment.data },
uploadType: 'standard',
}));
}
const { blurHash, caption, clientUuid, flags, height, width } = attachment;