diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..67bbd14 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +node_modules/ +dist/ +.env +__pycache__/ +*.log +.DS_Store +coverage/ +.nyc_output/ \ No newline at end of file diff --git a/src/config/__tests__/cdn.test.ts b/src/config/__tests__/cdn.test.ts new file mode 100644 index 0000000..57507e5 --- /dev/null +++ b/src/config/__tests__/cdn.test.ts @@ -0,0 +1,38 @@ +import { describe, it, expect } from 'vitest'; +import path from 'path'; +import { CDN_CONFIG } from '../cdn'; + +describe('CDN Configuration', () => { + const rootDir = CDN_CONFIG.ROOT_DIR; + + it('should have a valid root directory', () => { + expect(rootDir).toBeTruthy(); + expect(path.isAbsolute(rootDir)).toBe(true); + expect(path.basename(rootDir)).toBe('cdn_files'); + }); + + describe('isValidPath', () => { + it('should allow paths within the CDN directory', () => { + expect(CDN_CONFIG.isValidPath('file.txt')).toBe(true); + expect(CDN_CONFIG.isValidPath('subdir/file.txt')).toBe(true); + }); + + it('should prevent directory traversal', () => { + expect(CDN_CONFIG.isValidPath('../outside.txt')).toBe(false); + expect(CDN_CONFIG.isValidPath('/etc/passwd')).toBe(false); + expect(CDN_CONFIG.isValidPath('../../sensitive.txt')).toBe(false); + }); + }); + + describe('getFullPath', () => { + it('should return full path for valid relative paths', () => { + const fullPath = CDN_CONFIG.getFullPath('example.txt'); + expect(fullPath).toBe(path.resolve(rootDir, 'example.txt')); + }); + + it('should throw error for invalid paths', () => { + expect(() => CDN_CONFIG.getFullPath('../outside.txt')) + .toThrow('Invalid file path'); + }); + }); +}); \ No newline at end of file diff --git a/src/config/cdn.ts b/src/config/cdn.ts new file mode 100644 index 0000000..aa58ee9 --- /dev/null +++ b/src/config/cdn.ts @@ -0,0 +1,35 @@ +import path from 'path'; + +/** + * Configuration for CDN file storage + */ +export const CDN_CONFIG = { + /** + * Root directory for CDN files + * Uses an absolute path resolved from the project root + */ + ROOT_DIR: path.resolve(process.cwd(), 'cdn_files'), + + /** + * Validate if the provided path is within the CDN directory + * @param filePath - Path to validate + * @returns boolean indicating if the path is valid + */ + isValidPath(filePath: string): boolean { + const normalizedPath = path.normalize(filePath); + const resolvedPath = path.resolve(this.ROOT_DIR, normalizedPath); + return resolvedPath.startsWith(this.ROOT_DIR); + }, + + /** + * Get the full path for a file in the CDN + * @param relativePath - Relative path within the CDN directory + * @returns Full absolute path to the file + */ + getFullPath(relativePath: string): string { + if (!this.isValidPath(relativePath)) { + throw new Error('Invalid file path'); + } + return path.resolve(this.ROOT_DIR, relativePath); + } +}; \ No newline at end of file