2.5 KiB
2.5 KiB
file-system.ts
Purpose
Production-grade UploadStorage adapter backed by node:fs/promises. Stores bytes as flat files under a configurable rootDir. Every key is validated for path-traversal escape attempts BEFORE touching disk, so a malicious ../etc/passwd key never reaches the filesystem syscall layer — it raises FileUploadError(UPLOAD.STORAGE_FAILURE) from the resolver.
Features
- Path-traversal hardening: rejects keys containing
/,\, or NUL bytes; resolves keys viapath.resolveand verifies the result is insiderootDir. - Lazy
mkdir -p rootDiron firstputso callers can construct the adapter before the directory exists. - Atomic
writeFileon POSIX so partial writes never leave half-files visible to a parallel reader. deleteusesrm({ force: true })so absent files do not raise — matching the abort route's idempotent semantics.existsswallowsstaterrors and returnsfalserather than leaking the underlying syscall error code.
Usage: Basic
import { FileSystemUploadStorage } from "@suaveplan/api-plugin-file-upload/storage/file-system";
const storage = new FileSystemUploadStorage({
rootDir: "/var/lib/suaveplan/uploads",
});
await storage.put("upload-001", new Uint8Array([0xff]));
Usage: Advanced
import { FileSystemUploadStorage, FileUploadError } from "@suaveplan/api-plugin-file-upload";
const storage = new FileSystemUploadStorage({ rootDir: "/tmp/uploads" });
try {
await storage.put("../etc/passwd", new Uint8Array([0]));
} catch (err) {
if (err instanceof FileUploadError && err.uploadCode === "UPLOAD.STORAGE_FAILURE") {
console.warn("path-traversal rejected:", err.message);
}
}
API Reference
FileSystemUploadStorageOptions—{ rootDir: string }.class FileSystemUploadStorage implements UploadStorage— constructor(options: FileSystemUploadStorageOptions).put(key, bytes)/get(key)/delete(key)/exists(key)— same shape asUploadStorage.
Implementation Notes
- The path-traversal check rejects ANY separator in the raw key, then resolves and re-verifies the resolved path is inside
rootDir. The double check defends against both crafted strings AND quirky platform path normalisation. readFilereturns aBuffer; the wrapper re-wraps asUint8Arrayso callers see a tier-neutral byte view.- Storage failures preserve the underlying
causeso operators can trace EACCES / ENOSPC at the OTel log layer without losing context.