Files
suaveplan/packages/persistence/storage/storage-cdn-rackspace/src/key-sanitizer/key-sanitizer.md
2026-05-27 23:47:53 +01:00

3.3 KiB

key-sanitizer

(no submodules)

Purpose

Validates and normalises caller-supplied storage keys before any fetch is issued against Rackspace Cloud Files, and provides the per-segment URL encoder used to build absolute object URLs. Keys must be POSIX-form relative paths — no .., no leading /, no Windows drive prefixes, no control characters, no values longer than MAX_KEY_LENGTH (2048 chars). Rejections throw StorageCdnRackspaceError with code STORAGE_CDN_RACKSPACE.INVALID_OPTIONS.

Unlike @suaveplan/storage-http's key sanitiser, this one collapses key-length and key-content errors into a single code because operators monitoring Rackspace traffic don't distinguish between "key too long" and "key has a control char" — both are caller bugs caught at the boundary.

Features

  • Strict validation: empty, non-string, control char, leading /, drive-letter prefix, .. traversal, overlong (>2048).
  • Normalisation: Windows \ → POSIX / (idempotent on already-POSIX input).
  • Per-segment URL encoder (encodeKey) applies encodeURIComponent to each /-separated segment, preserving slashes.
  • All rejections share one canonical error code for uniform operator alerting.

Usage: Basic

import { encodeKey, sanitizeKey } from "@suaveplan/storage-cdn-rackspace";

const safe = sanitizeKey("a/b/file name.txt");
const encoded = encodeKey(safe); // → "a/b/file%20name.txt"

Usage: Advanced

import { encodeKey, sanitizeKey, StorageCdnRackspaceError } from "@suaveplan/storage-cdn-rackspace";

function compose(storageEndpoint: string, container: string, key: string): string {
    const safe = sanitizeKey(key);
    return `${storageEndpoint}${encodeURIComponent(container)}/${encodeKey(safe)}`;
}

try {
    compose(endpoint, "myc", "../etc/passwd");
} catch (err) {
    if (err instanceof StorageCdnRackspaceError) operatorLog.warn({ err }, "Caller bug — bad key");
}

API Reference

sanitizeKey(key: string): string

Throws StorageCdnRackspaceError(STORAGE_CDN_RACKSPACE.INVALID_OPTIONS) for any rejection reason. Returns the input with Windows \ replaced by /.

encodeKey(key: string): string

Splits on /, applies encodeURIComponent per segment, re-joins. Preserves path hierarchy while encoding spaces, ?, #, &, and non-ASCII characters.

Implementation Notes

  • Combining key-length and key-content rejections into one code is a deliberate UX choice — Rackspace operators report on a single rule, and the details field on the error preserves the message text for diagnostic logs.
  • The traversal check runs after \ → / normalisation so a\..\b is rejected (post-normalisation it has a .. segment).
  • Control-character detection is a single O(n) pass scanning every code unit; it costs negligible time relative to the subsequent fetch.
  • encodeKey is separate from sanitizeKey because URL encoding is a transport concern — callers that compose paths for non-fetch destinations (TempURL signature paths, log messages) want the sanitised but unencoded form.
  • The MAX_KEY_LENGTH = 2048 cap matches @suaveplan/storage-http's default — Rackspace's documented limit is 1024, so this is conservatively wider; the sibling storage-cdn-rackspace.ops layer prepends the container name which keeps the total path under documented limits.