(name: string)
| 366 | * @param {string} name The file name to sanitize |
| 367 | */ |
| 368 | export const sanitizeFileName = (name: string): string => { |
| 369 | if (!name || typeof name !== 'string') { |
| 370 | throw new Error('Invalid file name: name is required') |
| 371 | } |
| 372 | // Strip the FILE-STORAGE:: prefix if present |
| 373 | let stripped = name.replace(/^FILE-STORAGE::/, '') |
| 374 | // Decode percent-encoded traversal sequences before basename extraction |
| 375 | try { |
| 376 | stripped = decodeURIComponent(stripped) |
| 377 | } catch (_) { |
| 378 | // If decoding fails the raw string is fine — basename will still strip dirs |
| 379 | } |
| 380 | // Normalize backslashes to forward slashes so path.basename works on all |
| 381 | // platforms (on Linux, path.basename does not treat \ as a separator) |
| 382 | stripped = stripped.replace(/\\/g, '/') |
| 383 | // Extract only the base filename — removes all directory components |
| 384 | let baseName = path.basename(stripped) |
| 385 | // Run through sanitize-filename to strip OS-reserved chars, control chars, etc. |
| 386 | baseName = sanitize(baseName) |
| 387 | // Remove leading dots to prevent hidden files or relative path references |
| 388 | baseName = baseName.replace(/^\.+/, '') |
| 389 | if (!baseName || isUnsafeFilePath(baseName)) { |
| 390 | throw new Error(`Invalid or unsafe file name: ${name}`) |
| 391 | } |
| 392 | return baseName |
| 393 | } |
| 394 | |
| 395 | /** |
| 396 | * Safely resolve an untrusted relative key/filename to an absolute path inside a |
no test coverage detected