| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- import { AllLang } from '@growi/core';
- import path from 'pathe';
- export { AllLang as SUPPORTED_LOCALES };
- /**
- * Validates that the given file path is within the base directory.
- * This prevents path traversal attacks where an attacker could use sequences
- * like '../' to access files outside the intended directory.
- *
- * @param filePath - The file path to validate
- * @param baseDir - The base directory that the file path should be within
- * @returns true if the path is valid, false otherwise
- */
- export function isPathWithinBase(filePath: string, baseDir: string): boolean {
- const resolvedBaseDir = path.resolve(baseDir);
- const resolvedFilePath = path.resolve(filePath);
- // Check if the resolved path starts with the base directory
- // We add path.sep to ensure we're checking a directory boundary
- // (e.g., /tmp/foo should not match /tmp/foobar)
- return (
- resolvedFilePath.startsWith(resolvedBaseDir + path.sep) ||
- resolvedFilePath === resolvedBaseDir
- );
- }
- /**
- * Validates that joining baseDir with fileName results in a path within baseDir.
- * This is useful for validating user-provided file names before using them.
- *
- * @param fileName - The file name to validate
- * @param baseDir - The base directory
- * @returns true if the resulting path is valid, false otherwise
- * @throws Error if path traversal is detected
- */
- export function assertFileNameSafeForBaseDir(
- fileName: string,
- baseDir: string,
- ): void {
- const resolvedBaseDir = path.resolve(baseDir);
- const resolvedFilePath = path.resolve(baseDir, fileName);
- const isValid =
- resolvedFilePath.startsWith(resolvedBaseDir + path.sep) ||
- resolvedFilePath === resolvedBaseDir;
- if (!isValid) {
- throw new Error('Invalid file path: path traversal detected');
- }
- }
- /**
- * Resolves a locale-specific template path safely, preventing path traversal attacks.
- * Falls back to 'en_US' if the locale is not in the supported list.
- *
- * @param locale - The locale string (e.g. 'en_US')
- * @param baseDir - The base directory for locale files
- * @param templateSubPath - The sub-path within the locale directory (e.g. 'notifications/event.ejs')
- * @returns The template path
- * @throws Error if path traversal is detected
- */
- export function resolveLocalePath(
- locale: string,
- baseDir: string,
- templateSubPath: string,
- ): string {
- const safeLocale = (AllLang as string[]).includes(locale) ? locale : 'en_US';
- return path.join(baseDir, safeLocale, templateSubPath);
- }
- /**
- * Validates that joining baseDir with fileName results in a path within baseDir.
- * This is useful for validating user-provided file names before using them.
- *
- * @param fileName - The file name to validate
- * @param baseDir - The base directory
- * @returns true if the resulting path is valid, false otherwise
- */
- export function isFileNameSafeForBaseDir(
- fileName: string,
- baseDir: string,
- ): boolean {
- const resolvedBaseDir = path.resolve(baseDir);
- const resolvedFilePath = path.resolve(baseDir, fileName);
- return (
- resolvedFilePath.startsWith(resolvedBaseDir + path.sep) ||
- resolvedFilePath === resolvedBaseDir
- );
- }
|