<?php
/**
 * Security Functions
 * OBGYN Research & Collaboration Platform
 */

/**
 * Generate CSRF token
 */
function generateCSRFToken() {
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

/**
 * Verify CSRF token
 */
function verifyCSRFToken($token) {
    if (!isset($_SESSION['csrf_token'])) {
        return false;
    }
    return hash_equals($_SESSION['csrf_token'], $token);
}

/**
 * Get CSRF token input field
 */
function csrfField() {
    $token = generateCSRFToken();
    return '<input type="hidden" name="csrf_token" value="' . $token . '">';
}

/**
 * Validate CSRF token from POST
 */
function validateCSRF() {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        if (!isset($_POST['csrf_token']) || !verifyCSRFToken($_POST['csrf_token'])) {
            die('CSRF token validation failed.');
        }
    }
}

/**
 * Sanitize filename
 */
function sanitizeFilename($filename) {
    // Remove any path information
    $filename = basename($filename);
    
    // Remove special characters
    $filename = preg_replace('/[^a-zA-Z0-9._-]/', '_', $filename);
    
    return $filename;
}

/**
 * Check if file type is allowed
 */
function isAllowedFileType($filename, $allowedTypes = null) {
    $allowedTypes = $allowedTypes ?? ALLOWED_FILE_TYPES;
    $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return in_array($extension, $allowedTypes);
}

/**
 * Validate image file
 */
function isValidImage($file) {
    $allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
    $fileType = mime_content_type($file['tmp_name']);
    
    if (!in_array($fileType, $allowedTypes)) {
        return false;
    }
    
    // Additional check using getimagesize
    $imageInfo = @getimagesize($file['tmp_name']);
    if ($imageInfo === false) {
        return false;
    }
    
    return true;
}

/**
 * Prevent SQL injection (use prepared statements instead)
 */
function escapeSQL($string) {
    return htmlspecialchars(strip_tags($string), ENT_QUOTES, 'UTF-8');
}

/**
 * Prevent XSS attacks
 */
function preventXSS($data) {
    if (is_array($data)) {
        return array_map('preventXSS', $data);
    }
    return htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
}

/**
 * Check for SQL injection patterns
 */
function detectSQLInjection($input) {
    $patterns = [
        '/(\bUNION\b.*\bSELECT\b)/i',
        '/(\bSELECT\b.*\bFROM\b)/i',
        '/(\bINSERT\b.*\bINTO\b)/i',
        '/(\bUPDATE\b.*\bSET\b)/i',
        '/(\bDELETE\b.*\bFROM\b)/i',
        '/(\bDROP\b.*\bTABLE\b)/i',
        '/(\bEXEC\b|\bEXECUTE\b)/i',
        '/(--|#|\/\*|\*\/)/i'
    ];
    
    foreach ($patterns as $pattern) {
        if (preg_match($pattern, $input)) {
            return true;
        }
    }
    
    return false;
}

/**
 * Rate limiting for login attempts
 */
function checkLoginAttempts($email, $ipAddress) {
    try {
        $db = getDB();
        
        // Check attempts in last 15 minutes
        $stmt = $db->prepare("
            SELECT COUNT(*) as attempts 
            FROM login_attempts 
            WHERE (email = ? OR ip_address = ?) 
            AND success = 0 
            AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)
        ");
        $stmt->execute([$email, $ipAddress]);
        $result = $stmt->fetch();
        
        if ($result['attempts'] >= MAX_LOGIN_ATTEMPTS) {
            return false;
        }
        
        return true;
    } catch (Exception $e) {
        error_log("Error checking login attempts: " . $e->getMessage());
        return true; // Allow login if check fails
    }
}

/**
 * Log login attempt
 */
function logLoginAttempt($email, $ipAddress, $success) {
    try {
        $db = getDB();
        $stmt = $db->prepare("
            INSERT INTO login_attempts (email, ip_address, success)
            VALUES (?, ?, ?)
        ");
        $stmt->execute([$email, $ipAddress, $success ? 1 : 0]);
        
        // Clean old attempts (older than 24 hours)
        $db->exec("DELETE FROM login_attempts WHERE attempted_at < DATE_SUB(NOW(), INTERVAL 24 HOUR)");
        
        return true;
    } catch (Exception $e) {
        error_log("Error logging login attempt: " . $e->getMessage());
        return false;
    }
}

/**
 * Validate password strength
 */
function validatePasswordStrength($password) {
    $errors = [];
    
    if (strlen($password) < 8) {
        $errors[] = "Password must be at least 8 characters long.";
    }
    
    if (!preg_match('/[A-Z]/', $password)) {
        $errors[] = "Password must contain at least one uppercase letter.";
    }
    
    if (!preg_match('/[a-z]/', $password)) {
        $errors[] = "Password must contain at least one lowercase letter.";
    }
    
    if (!preg_match('/[0-9]/', $password)) {
        $errors[] = "Password must contain at least one number.";
    }
    
    if (!preg_match('/[^A-Za-z0-9]/', $password)) {
        $errors[] = "Password must contain at least one special character.";
    }
    
    return [
        'valid' => empty($errors),
        'errors' => $errors
    ];
}

/**
 * Secure session configuration
 */
function secureSession() {
    // Prevent session fixation
    if (!isset($_SESSION['initiated'])) {
        session_regenerate_id(true);
        $_SESSION['initiated'] = true;
    }
    
    // Check session timeout
    if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity'] > SESSION_LIFETIME)) {
        session_unset();
        session_destroy();
        session_start();
        return false;
    }
    
    $_SESSION['last_activity'] = time();
    
    // Validate session IP (optional - can cause issues with mobile users)
    // if (isset($_SESSION['ip_address']) && $_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
    //     session_unset();
    //     session_destroy();
    //     return false;
    // }
    
    // Store IP address
    if (!isset($_SESSION['ip_address'])) {
        $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
    }
    
    return true;
}

/**
 * Clean old sessions
 */
function cleanOldSessions() {
    // This should be called periodically (e.g., via cron job)
    $sessionPath = session_save_path();
    if (empty($sessionPath)) {
        $sessionPath = sys_get_temp_dir();
    }
    
    $files = glob($sessionPath . '/sess_*');
    $now = time();
    
    foreach ($files as $file) {
        if (is_file($file)) {
            if ($now - filemtime($file) >= SESSION_LIFETIME) {
                @unlink($file);
            }
        }
    }
}

/**
 * Encrypt data
 */
function encryptData($data, $key = null) {
    $key = $key ?? hash('sha256', 'your-secret-key-here', true);
    $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
    $encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
    return base64_encode($encrypted . '::' . $iv);
}

/**
 * Decrypt data
 */
function decryptData($data, $key = null) {
    $key = $key ?? hash('sha256', 'your-secret-key-here', true);
    list($encrypted, $iv) = explode('::', base64_decode($data), 2);
    return openssl_decrypt($encrypted, 'aes-256-cbc', $key, 0, $iv);
}

/**
 * Generate 2FA secret
 */
function generate2FASecret() {
    return base64_encode(random_bytes(32));
}

/**
 * Verify 2FA code (basic implementation - use Google Authenticator library for production)
 */
function verify2FACode($secret, $code) {
    // This is a simplified version
    // In production, use a proper TOTP library like RobThree/TwoFactorAuth
    $timeSlice = floor(time() / 30);
    $hash = hash_hmac('sha1', pack('N*', 0) . pack('N*', $timeSlice), base64_decode($secret), true);
    $offset = ord($hash[19]) & 0xf;
    $otp = (
        ((ord($hash[$offset + 0]) & 0x7f) << 24) |
        ((ord($hash[$offset + 1]) & 0xff) << 16) |
        ((ord($hash[$offset + 2]) & 0xff) << 8) |
        (ord($hash[$offset + 3]) & 0xff)
    ) % 1000000;
    
    return str_pad($otp, 6, '0', STR_PAD_LEFT) === $code;
}

/**
 * Sanitize URL
 */
function sanitizeURL($url) {
    return filter_var($url, FILTER_SANITIZE_URL);
}

/**
 * Validate URL
 */
function isValidURL($url) {
    return filter_var($url, FILTER_VALIDATE_URL) !== false;
}

/**
 * Check if request is from allowed origin (CORS)
 */
function checkOrigin($allowedOrigins = []) {
    $origin = $_SERVER['HTTP_ORIGIN'] ?? '';
    
    if (empty($allowedOrigins)) {
        $allowedOrigins = [SITE_URL];
    }
    
    if (in_array($origin, $allowedOrigins)) {
        header("Access-Control-Allow-Origin: $origin");
        header("Access-Control-Allow-Credentials: true");
        return true;
    }
    
    return false;
}

/**
 * Prevent clickjacking
 */
function preventClickjacking() {
    header('X-Frame-Options: SAMEORIGIN');
    header('X-Content-Type-Options: nosniff');
    header('X-XSS-Protection: 1; mode=block');
}

/**
 * Set security headers
 */
function setSecurityHeaders() {
    preventClickjacking();
    header('Referrer-Policy: strict-origin-when-cross-origin');
    header('Permissions-Policy: geolocation=(), microphone=(), camera=()');
    
    // Content Security Policy (allow Bootstrap, Font Awesome, jQuery, JSDelivr CDNs, unpkg.com)
    $csp = "default-src 'self'; " .
           "style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://unpkg.com; " .
           "script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://code.jquery.com https://unpkg.com; " .
           "font-src 'self' https://cdnjs.cloudflare.com; " .
           "img-src 'self' data: https:; " .
           "connect-src 'self' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com https://unpkg.com;";
    header("Content-Security-Policy: $csp");
}

/**
 * Validate file upload security
 */
function validateFileUpload($file) {
    $errors = [];
    
    // Check if file was uploaded
    if (!isset($file) || $file['error'] !== UPLOAD_ERR_OK) {
        $errors[] = "File upload error.";
        return ['valid' => false, 'errors' => $errors];
    }
    
    // Check file size
    if ($file['size'] > MAX_FILE_SIZE) {
        $errors[] = "File size exceeds maximum allowed size (" . formatFileSize(MAX_FILE_SIZE) . ").";
    }
    
    // Check file extension
    $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
    if (!in_array($extension, ALLOWED_FILE_TYPES)) {
        $errors[] = "File type not allowed. Allowed types: " . implode(', ', ALLOWED_FILE_TYPES);
    }
    
    // Check MIME type
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $file['tmp_name']);
    finfo_close($finfo);
    
    $allowedMimeTypes = [
        'application/pdf',
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'application/vnd.ms-excel',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'image/jpeg',
        'image/png',
        'image/gif'
    ];
    
    if (!in_array($mimeType, $allowedMimeTypes)) {
        $errors[] = "Invalid file type detected.";
    }
    
    // Check for malicious content in filename
    if (preg_match('/[^\w\s\d\-_~,;\[\]\(\).]/', $file['name'])) {
        $errors[] = "Invalid characters in filename.";
    }
    
    return [
        'valid' => empty($errors),
        'errors' => $errors
    ];
}

// Initialize security headers on every request
setSecurityHeaders();

// Secure session
secureSession();
?>
