Merge pull request #705 from guisea/fix/forward-as-attachment-filename-privacy
fix: strip from/to names from forward-as-attachment filenames
This commit is contained in:
@@ -1,7 +1,21 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
||||
import { buildForwardAsAttachmentPayload } from '@/lib/forward-as-attachment';
|
||||
import type { Email } from '@/lib/jmap/types';
|
||||
|
||||
// Pin TZ so the local-time date rendering in the filename test is deterministic,
|
||||
// restoring it after so this doesn't leak into other test files in the same worker.
|
||||
let originalTZ: string | undefined;
|
||||
beforeAll(() => {
|
||||
originalTZ = process.env.TZ;
|
||||
process.env.TZ = 'UTC';
|
||||
});
|
||||
afterAll(() => {
|
||||
// process.env coerces to strings, so `= undefined` would leave the literal
|
||||
// string "undefined" behind when TZ was originally unset - delete instead.
|
||||
if (originalTZ === undefined) delete process.env.TZ;
|
||||
else process.env.TZ = originalTZ;
|
||||
});
|
||||
|
||||
function makeEmail(overrides: Partial<Email> = {}): Email {
|
||||
return {
|
||||
id: 'e1',
|
||||
@@ -52,13 +66,30 @@ describe('buildForwardAsAttachmentPayload', () => {
|
||||
expect(payload?.subject).toBe('');
|
||||
});
|
||||
|
||||
it('honors a custom filename template, matching "Export as .eml" naming instead of always using the default', () => {
|
||||
it('applies user space/case transforms but ignores a custom filename template, unlike "Export as .eml"', () => {
|
||||
const email = makeEmail({ subject: 'Missed spam example' });
|
||||
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:', {
|
||||
template: 'custom-{subject}',
|
||||
lowercase: true,
|
||||
spaceReplacement: 'dash',
|
||||
});
|
||||
expect(payload?.attachment.name).toBe('custom-missed-spam-example.eml');
|
||||
expect(payload?.attachment.name).toBe('2026-07-26-22.25.22-missed-spam-example.eml');
|
||||
});
|
||||
|
||||
it('uses a dash between date and subject by default', () => {
|
||||
const email = makeEmail({ subject: 'Missed spam example' });
|
||||
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
|
||||
expect(payload?.attachment.name).toBe('2026-07-26 22.25.22-Missed spam example.eml');
|
||||
});
|
||||
|
||||
it('never includes from/to in the filename, even with the default template, to avoid leaking names to the recipient', () => {
|
||||
const email = makeEmail({
|
||||
subject: 'Missed spam example',
|
||||
from: [{ name: 'Alice Sender', email: 'alice@example.com' }],
|
||||
to: [{ name: "'Bobby'", email: 'bob@example.com' }],
|
||||
});
|
||||
const payload = buildForwardAsAttachmentPayload(email, 'Fwd:');
|
||||
expect(payload?.attachment.name).not.toContain('Alice');
|
||||
expect(payload?.attachment.name).not.toContain('Bobby');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,12 +24,14 @@ export interface ForwardAsAttachmentPayload {
|
||||
* not per-email, so the same blobId a message already has can be attached
|
||||
* to a brand new outgoing email directly.
|
||||
*
|
||||
* `filenameOptions`, when passed, should be the same options the caller
|
||||
* uses for "Export as .eml" / drag-out (the user's configured filename
|
||||
* template, space/case/diacritics transforms - see
|
||||
* useSettingsStore's emailDownloadTemplate and friends), so the two
|
||||
* actions produce consistent filenames for the same message. Falls back
|
||||
* to emailExportFilename's own default template when omitted.
|
||||
* `filenameOptions`, when passed, carries the user's configured space/case/
|
||||
* diacritics transforms (see useSettingsStore's filenameSpaceReplacement
|
||||
* and friends) for consistency with "Export as .eml" / drag-out. Its
|
||||
* `template`, if any, is ignored: this attachment goes out to a possibly
|
||||
* external recipient (spam gateway, another person), so the filename is
|
||||
* always just "{date}-{subject}.eml" - never the user's own from/to naming
|
||||
* template, which could otherwise leak sender/recipient names into an
|
||||
* attachment filename visible to that recipient.
|
||||
*
|
||||
* Returns null when the email has no blobId (nothing to reference).
|
||||
*/
|
||||
@@ -48,7 +50,7 @@ export function buildForwardAsAttachmentPayload(
|
||||
subject: email.subject ? buildForwardSubject(email.subject, forwardPrefix) : "",
|
||||
attachment: {
|
||||
blobId: email.blobId,
|
||||
name: emailExportFilename(email, filenameOptions),
|
||||
name: emailExportFilename(email, { ...filenameOptions, template: "{date}-{subject}" }),
|
||||
type: "message/rfc822",
|
||||
size: email.size,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user