Files
webmail/lib/__tests__/file-name-rules.test.ts
T
Linus Rath 4d3a3db90b fix: handle the file names and types Stalwart refuses
From 0.16.6 Stalwart refuses FileNode names with `/<>:"\|?*` or a
reserved name such as `CON` ("Name contains a forbidden character."),
and publishes the rules as `forbiddenNameChars` / `forbiddenNodeNames`.
Bulwark did not read them: the error showed up only after an upload had
started, and it aborted the rest of a multi-file or folder upload.

- new folder, new text file and rename now say which characters or
  names the server does not allow, before sending anything
- uploads store an accepted variant instead: forbidden characters
  become `_` and a reserved name gets `_` appended

MIME types over 30 characters (most Office formats) were always stored
as `application/octet-stream`, because Stalwart before 0.16.6 refuses
them. From 0.16.6 the limit is 255, so the real type is kept there.
2026-09-22 20:54:01 +02:00

31 lines
1.3 KiB
TypeScript

import { describe, it, expect } from 'vitest';
import { acceptedFileName, fileNameProblem, fileNameRulesFrom } from '../file-name-rules';
// The filenode capability Stalwart 0.16.23 publishes.
const STALWART = fileNameRulesFrom({
maxSizeFileNodeName: 255,
forbiddenNameChars: '/<>:"\\|?*',
forbiddenNodeNames: ['.', '..', 'CON', 'PRN', 'AUX', 'NUL', 'COM1', 'LPT1'],
});
describe('file name rules', () => {
it('has no rules for servers that publish none (Stalwart before 0.16.6)', () => {
expect(fileNameRulesFrom({ maxSizeFileNodeName: 255 })).toBeNull();
expect(fileNameProblem('a:b', null)).toBeNull();
expect(acceptedFileName('a:b', null)).toBe('a:b');
});
it('reports forbidden characters and reserved names', () => {
expect(fileNameProblem('bad:name?.txt', STALWART)).toEqual({ kind: 'chars', chars: ': ?' });
expect(fileNameProblem('con', STALWART)).toEqual({ kind: 'reserved' });
expect(fileNameProblem('CON.txt', STALWART)).toBeNull();
expect(fileNameProblem('report.pdf', STALWART)).toBeNull();
});
it('turns an uploaded name into one the server accepts', () => {
expect(acceptedFileName('bad:name?.txt', STALWART)).toBe('bad_name_.txt');
expect(acceptedFileName('NUL', STALWART)).toBe('NUL_');
expect(acceptedFileName('fine.txt', STALWART)).toBe('fine.txt');
});
});