T.ME/BIBIL_0DAY
CasperSecurity


Server : Apache/2
System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64
User : gositeme ( 1004)
PHP Version : 8.2.29
Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname
Directory :  /home/gositeme/domains/lavocat.quebec/private_html/src/utils/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.quebec/private_html/src/utils/fileValidation.ts
import { File } from 'formidable';
import { createHash } from 'crypto';
import { promises as fs } from 'fs';
import path from 'path';

// Constants for validation
export const MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
export const ALLOWED_FILE_TYPES = [
  'application/pdf',
  'image/jpeg',
  'image/png',
  'image/gif',
  'video/mp4',
  'video/mpeg',
  'video/x-mpeg',
  'video/x-mpeg4',
  'video/webm',
  'video/quicktime', // mov
  'video/x-msvideo', // avi
  'video/x-m4v', // m4v
  'video/3gpp', // 3gp
  'video/x-flv', // flv
  'video/x-matroska', // mkv
  'video/x-ms-wmv' // wmv
];

// File type signatures (magic numbers)
const FILE_SIGNATURES: { [key: string]: number[][] } = {
  'application/pdf': [[0x25, 0x50, 0x44, 0x46]], // %PDF
  'image/jpeg': [[0xFF, 0xD8, 0xFF]], // JPEG
  'image/png': [[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]], // PNG
  'image/gif': [[0x47, 0x49, 0x46, 0x38]] // GIF
  // No signature check for video for now
};

export interface FileValidationResult {
  isValid: boolean;
  error?: string;
  sanitizedFilename?: string;
}

export async function validateFile(file: File): Promise<FileValidationResult> {
  try {
    // Check file size
    if (file.size > MAX_FILE_SIZE) {
      return {
        isValid: false,
        error: `File size exceeds maximum limit of ${MAX_FILE_SIZE / (1024 * 1024)}MB
      };
    }

    // Check if file type is allowed
    if (!file.mimetype || !ALLOWED_FILE_TYPES.includes(file.mimetype)) {
      return {
        isValid: false,
        error: 'File type not allowed'
      };
    }

    // Only check signature for non-video files
    if (!file.mimetype.startsWith('video/')) {
      const buffer = await fs.readFile(file.filepath);
      const signature = Array.from(buffer.slice(0, 8));
      const expectedSignature = FILE_SIGNATURES[file.mimetype];
      if (!expectedSignature) {
        return {
          isValid: false,
          error: 'Unknown file type'
        };
      }
      const isValidSignature = expectedSignature.some(sig => 
        sig.every((byte, index) => signature[index] === byte)
      );
      if (!isValidSignature) {
        return {
          isValid: false,
          error: 'File signature does not match declared type'
        };
      }
    }

    // Generate safe filename
    const sanitizedFilename = generateSafeFilename(file.originalFilename || '');

    return {
      isValid: true,
      sanitizedFilename
    };
  } catch (error) {
    return {
      isValid: false,
      error: 'Error validating file'
    };
  }
}

function generateSafeFilename(originalFilename: string): string {
  // Remove any directory traversal attempts
  const basename = path.basename(originalFilename);
  
  // Remove any non-alphanumeric characters except for . and -
  const sanitized = basename.replace(/[^a-zA-Z0-9.-]/g, '_');
  
  // Generate a unique hash
  const hash = createHash('md5')
    .update(originalFilename + Date.now().toString())
    .digest('hex')
    .slice(0, 8);
  
  // Get the file extension
  const ext = path.extname(sanitized);
  
  // Combine sanitized name with hash and extension
  return `${sanitized.slice(0, -ext.length)}_${hash}${ext}
}

export async function cleanupFile(filepath: string): Promise<void> {
  try {
    await fs.unlink(filepath);
  } catch (error) {
    throw new Error('Failed to cleanup file');
  }
} 

CasperSecurity Mini