feat(preview): render XLSX spreadsheets in the file-preview overlay

xlsx files were download-only. Add a read-only, virtualized preview (sheet
tabs, number formats, merges, theme colours) parsed entirely in a browser
Web Worker with exceljs and fflate, loaded only when a spreadsheet is
opened. The workbook is checked against ZIP-bomb, entry and cell limits
before exceljs loads; cell text is written with textContent, formulas are
never evaluated and nothing referenced by the workbook is fetched. On the
server xlsx only joins the existing allowlist and classification, with a
10 MB cap on ?preview=true. xls and ods stay download-only.
This commit is contained in:
Aamer Akhter
2026-09-26 23:13:21 -04:00
parent 45ea2e1d32
commit 0b122e2c76
27 changed files with 3765 additions and 13 deletions
+13 -2
View File
@@ -46,10 +46,17 @@ function lockedVersions(lock: PackageLock, packageName: string): string[] {
return [...versions].sort();
}
function expectEveryLockedVersionAtLeast(lock: PackageLock, packageName: string, minimum: string): void {
function expectEveryLockedVersionAtLeast(
lock: PackageLock,
packageName: string,
minimum: string,
/** Exact versions deliberately outside this policy; each call site says why. */
exempt: string[] = []
): void {
const versions = lockedVersions(lock, packageName);
expect(versions, `${packageName} should be present in package-lock.json`).not.toHaveLength(0);
for (const version of versions) {
if (exempt.includes(version)) continue;
expect(
compareVersions(version, minimum),
`${packageName}@${version} should be >= ${minimum}`
@@ -136,7 +143,11 @@ describe('dependency security policy', () => {
// <=10.1.1, so every 9.x is affected and the fix is only on the 10.x line.
expectEveryLockedVersionAtLeast(lock, '@fastify/static', '10.1.2');
expectEveryLockedVersionAtLeast(lock, 'ip-address', '10.2.0');
expectEveryLockedVersionAtLeast(lock, 'uuid', '14.0.0');
// Our own uuid stays >= 14. exceljs@4.4.0 (devDependency, vendored into the
// XLSX preview worker at build time) pins uuid@8.3.2 and only calls v4();
// GHSA-w5hq-g745-h8pq is MODERATE and covers v3/v5/v6 with a caller buffer,
// so it is outside this CRITICAL/HIGH policy and unreachable from exceljs.
expectEveryLockedVersionAtLeast(lock, 'uuid', '14.0.0', ['8.3.2']);
// ⚠️ Floor stays 8.20.1, NOT 8.21.0. Production ws is already 8.21.0 and clear of
// GHSA-96hv-2xvq-fx4p, but @remotion/renderer bundles its own ws@8.20.1 and remotion
// is pinned to 4.0.473 on purpose (the compositor refuses to start on a version