/** * Input sanitization utilities for the Project Wizard. * * All user-supplied strings pass through these before use. */ const CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/g; const PATH_TRAVERSAL_RE = /\.\.\//; const GIT_URL_RE = /^(https?:\/\/|git@|ssh:\/\/|git:\/\/).+/; const GITHUB_REPO_RE = /^[\w][\w.-]*\/[\w][\w.-]*$/; /** * General string sanitizer: trim, strip control characters, reject path traversal. * Returns null if the input is rejected (contains `../`). */ export function sanitize(str: string): string | null { const trimmed = str.trim().replace(CONTROL_CHAR_RE, ''); if (PATH_TRAVERSAL_RE.test(trimmed)) return null; return trimmed; } /** * Sanitize a URL string. Returns null if the URL is malformed or contains traversal. */ export function sanitizeUrl(url: string): string | null { const clean = sanitize(url); if (!clean) return null; try { // Allow git@ SSH URLs and standard HTTP(S) if (GIT_URL_RE.test(clean)) return clean; new URL(clean); return clean; } catch { return null; } } /** * Sanitize a filesystem path. Rejects `../` traversal attempts. * Allows `~` prefix for home directory expansion (done server-side). */ export function sanitizePath(path: string): string | null { const clean = sanitize(path); if (!clean) return null; // Reject null bytes (extra safety) if (clean.includes('\0')) return null; return clean; } /** * Validate a GitHub `owner/repo` string. */ export function isValidGithubRepo(input: string): boolean { return GITHUB_REPO_RE.test(input.trim()); } /** * Validate a Git clone URL (http(s), git@, ssh://, git://). */ export function isValidGitUrl(input: string): boolean { return GIT_URL_RE.test(input.trim()); }