Files
OmniRoute/src/lib/docsI18nPath.ts
Diego Rodrigues de Sa e Souza 7c23dab64d Release v3.8.40
v3.8.40 cycle integration → main. All test gates green (Unit/Integration/Coverage/Node-compat/Quality-Ratchet). The only red check, 'PR Test Policy', is the test-masking heuristic firing on the cumulative ~57-commit release diff (legitimate assert consolidations already reviewed per-PR — Gemini CLI removal #5246, retired GPT models #5280, provider catalog refreshes); overridden with --admin per the documented release-PR convention. CodeQL/SonarQube advisory scans non-blocking; #5278's code already passed CodeQL on main. Homologated on VPS 192.168.0.15 (v3.8.40 healthy).
2026-06-29 08:40:06 -03:00

34 lines
1.3 KiB
TypeScript

import path from "node:path";
// A locale or slug segment may only contain ASCII letters, digits and dashes.
// This blocks `..`, `/`, `\0`, and absolute paths before any filesystem access.
const SEGMENT_RE = /^[a-z0-9-]+$/i;
/**
* Resolve the i18n section directory for a docs slug under `<docsRoot>/i18n`, or
* return `null` when the locale/slug contain anything but `[a-z0-9-]` or the
* resolved path escapes `<docsRoot>/i18n`.
*
* Pure path math — no filesystem access — so it is directly unit-testable and
* is the single chokepoint guarding the i18n docs fallback against path
* traversal (the `locale` comes from a user-controllable cookie). The prefix
* check uses `i18nRoot + path.sep` (not a bare `startsWith`) so a sibling like
* `…/i18n-evil` cannot satisfy it.
*/
export function resolveSafeI18nSectionDir(
docsRoot: string,
locale: string,
slug: string[]
): string | null {
if (!locale || !SEGMENT_RE.test(locale)) return null;
if (!slug.length || !slug.every((s) => SEGMENT_RE.test(s))) return null;
const i18nRoot = path.join(docsRoot, "i18n");
const sectionDir = path.resolve(i18nRoot, locale, "docs", ...slug.slice(0, -1));
if (sectionDir !== i18nRoot && !sectionDir.startsWith(i18nRoot + path.sep)) {
return null;
}
return sectionDir;
}