Files
skills/docs/persistence/storage/storage-file/src/key-sanitizer/key-sanitizer.md
2026-05-29 08:20:56 +01:00

3.0 KiB
Raw Blame History

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 as STORAGE_FILE.KEY_TOO_LONG (a distinct code from INVALID_KEY so 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 StorageFileError with code STORAGE_FILE.INVALID_KEY on empty input, control chars, absolute paths, drive-letter prefix, or .. traversal.
  • Throws StorageFileError with code STORAGE_FILE.KEY_TOO_LONG when input length exceeds MAX_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 noControlCharactersInRegex lint happy without a suppression comment and is also marginally faster on short keys.
  • .. is rejected segment-by-segment after \\ normalisation, so both foo\\..\\bar and foo/../bar are 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:fs accepts them and most modern filesystems do too.