(name: string)
| 406 | * @param {string} name The file name to sanitize |
| 407 | */ |
| 408 | export const sanitizeFileName = (name: string): string => { |
| 409 | if (!name || typeof name !== 'string') { |
| 410 | throw new Error('Invalid file name: name is required') |
| 411 | } |
| 412 | // Strip the FILE-STORAGE:: prefix if present |
| 413 | let stripped = name.replace(/^FILE-STORAGE::/, '') |
| 414 | // Decode percent-encoded traversal sequences before basename extraction |
| 415 | try { |
| 416 | stripped = decodeURIComponent(stripped) |
| 417 | } catch (_) { |
| 418 | // If decoding fails the raw string is fine — basename will still strip dirs |
| 419 | } |
| 420 | // Normalize backslashes to forward slashes so path.basename works on all |
| 421 | // platforms (on Linux, path.basename does not treat \ as a separator) |
| 422 | stripped = stripped.replace(/\\/g, '/') |
| 423 | // Extract only the base filename — removes all directory components |
| 424 | let baseName = path.basename(stripped) |
| 425 | // Run through sanitize-filename to strip OS-reserved chars, control chars, etc. |
| 426 | baseName = sanitize(baseName) |
| 427 | // Remove leading dots to prevent hidden files or relative path references |
| 428 | baseName = baseName.replace(/^\.+/, '') |
| 429 | if (!baseName || isUnsafeFilePath(baseName)) { |
| 430 | throw new Error(`Invalid or unsafe file name: ${name}`) |
| 431 | } |
| 432 | return baseName |
| 433 | } |
| 434 | |
| 435 | /** |
| 436 | * Safely resolve an untrusted relative key/filename to an absolute path inside a |
no test coverage detected