Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules/
dist/
.env
__pycache__/
*.log
.DS_Store
coverage/
.nyc_output/
38 changes: 38 additions & 0 deletions src/config/__tests__/cdn.test.ts
Original file line number Diff line number Diff line change
@@ -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');
});
});
});
35 changes: 35 additions & 0 deletions src/config/cdn.ts
Original file line number Diff line number Diff line change
@@ -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);
}
};