3.0 KiB
3.0 KiB
key-sanitizer
(no submodules)
Purpose
Validates and normalises every caller-supplied storage key before any filesystem call. The sanitiser is the security boundary that prevents a caller-controlled key (../../etc/passwd) from escaping the configured rootDir. Every public method on NodeFsStorage passes its key through sanitizeKey before resolving any path or issuing any node:fs call. Failing the sanitiser is unrecoverable from the caller's perspective — it always reflects a programming error or a malicious input.
Features
- Rejects empty strings,
..traversal segments, POSIX absolute paths (/foo), Windows drive-letter prefixed paths (C:\foo,c:/foo). - Rejects null bytes (
\x00) and any control char in the C0 range (0x00–0x1F) plus DEL (0x7F). - Enforces a maximum length of
MAX_KEY_LENGTH(1024) characters; over-length keys surface asSTORAGE_FILE.KEY_TOO_LONG(a distinct code fromINVALID_KEYso callers can hint at the truncation). - Normalises Windows
\separators to POSIX/so the same key resolves identically on every platform. - Pure function — no allocation beyond the normalised string return; safe to call on every operation.
Usage: Basic Example
import { sanitizeKey } from "@suaveplan/storage-file";
const safe = sanitizeKey("orders/2026/05/12.json");
// → "orders/2026/05/12.json"
Usage: Advanced Example
import { sanitizeKey, StorageFileError, STORAGE_FILE_CODES } from "@suaveplan/storage-file";
function safeKey(input: string): string | null {
try {
return sanitizeKey(input);
} catch (err) {
if (err instanceof StorageFileError && (err.code === STORAGE_FILE_CODES.INVALID_KEY || err.code === STORAGE_FILE_CODES.KEY_TOO_LONG)) {
return null;
}
throw err;
}
}
const normalised = sanitizeKey("orders\\2026\\05\\12.json");
// → "orders/2026/05/12.json"
API Reference
sanitizeKey(key: string): string— returns the normalised POSIX-separator form on success.- Throws
StorageFileErrorwith codeSTORAGE_FILE.INVALID_KEYon empty input, control chars, absolute paths, drive-letter prefix, or..traversal. - Throws
StorageFileErrorwith codeSTORAGE_FILE.KEY_TOO_LONGwhen input length exceedsMAX_KEY_LENGTH(1024).
Implementation Notes
- The control-char check iterates the string code unit by code unit rather than using a regex with a control-char range. This keeps biome's
noControlCharactersInRegexlint happy without a suppression comment and is also marginally faster on short keys. ..is rejected segment-by-segment after\\normalisation, so bothfoo\\..\\barandfoo/../barare caught.- Empty segments produced by consecutive separators (
foo//bar) are NOT rejected — they are allowed for caller convenience and resolve to the same path. The host filesystem normalises them internally. - The key argument is not constrained beyond the rules above; arbitrary Unicode (including emoji and CJK) is permitted because
node:fsaccepts them and most modern filesystems do too.