<?php
// security.php

class Security {
    
    /**
     * Generiert ein CSRF-Token
     */
    public static function generateCSRFToken() {
        if (!isset($_SESSION[CSRF_TOKEN_NAME])) {
            $_SESSION[CSRF_TOKEN_NAME] = bin2hex(random_bytes(32));
        }
        return $_SESSION[CSRF_TOKEN_NAME];
    }
    
    /**
     * Validiert CSRF-Token
     */
    public static function validateCSRFToken($token) {
        if (!isset($_SESSION[CSRF_TOKEN_NAME])) {
            return false;
        }
        return hash_equals($_SESSION[CSRF_TOKEN_NAME], $token);
    }
    
    /**
     * Gibt CSRF-Token HTML-Input zurück
     */
    public static function getCSRFInput() {
        $token = self::generateCSRFToken();
        return '<input type="hidden" name="csrf_token" value="' . htmlspecialchars($token) . '">';
    }
    
    /**
     * Bereinigt Eingaben
     */
    public static function sanitizeInput($input) {
        if (is_array($input)) {
            return array_map([self::class, 'sanitizeInput'], $input);
        }
        return htmlspecialchars(trim($input), ENT_QUOTES, 'UTF-8');
    }
    
    /**
     * Validiert Datei-Upload
     */
    public static function validateFileUpload($file) {
        $errors = [];
        
        // Prüfe ob Datei hochgeladen wurde
        if ($file['error'] !== UPLOAD_ERR_OK) {
            $errors[] = 'Fehler beim Hochladen der Datei';
            return ['valid' => false, 'errors' => $errors];
        }
        
        // Prüfe Dateigröße
        if ($file['size'] > MAX_FILE_SIZE) {
            $errors[] = 'Datei ist zu groß. Maximum: ' . (MAX_FILE_SIZE / 1024 / 1024) . ' MB';
        }
        
        // Prüfe MIME-Type
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);
        
        if (!in_array($mimeType, ALLOWED_IMAGE_TYPES)) {
            $errors[] = 'Ungültiger Dateityp. Nur Bilder erlaubt.';
        }
        
        // Prüfe Dateiendung
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, ALLOWED_EXTENSIONS)) {
            $errors[] = 'Ungültige Dateiendung.';
        }
        
        // Prüfe ob es wirklich ein Bild ist
        $imageInfo = @getimagesize($file['tmp_name']);
        if ($imageInfo === false) {
            $errors[] = 'Datei ist kein gültiges Bild.';
        }
        
        if (!empty($errors)) {
            return ['valid' => false, 'errors' => $errors];
        }
        
        return ['valid' => true, 'mime' => $mimeType, 'extension' => $extension];
    }
    
    /**
     * Generiert sicheren Dateinamen
     */
    public static function generateSecureFilename($extension) {
        return bin2hex(random_bytes(16)) . '_' . time() . '.' . $extension;
    }
    
    /**
     * Prüft Login-Versuche (Rate Limiting)
     */
    public static function checkLoginAttempts($username) {
        if (!isset($_SESSION['login_attempts'])) {
            $_SESSION['login_attempts'] = [];
        }
        
        $attempts = &$_SESSION['login_attempts'];
        
        // Bereinige alte Einträge
        $currentTime = time();
        foreach ($attempts as $user => $data) {
            if ($currentTime - $data['time'] > LOGIN_LOCKOUT_TIME) {
                unset($attempts[$user]);
            }
        }
        
        // Prüfe ob Benutzer gesperrt ist
        if (isset($attempts[$username])) {
            if ($attempts[$username]['count'] >= MAX_LOGIN_ATTEMPTS) {
                if ($currentTime - $attempts[$username]['time'] < LOGIN_LOCKOUT_TIME) {
                    $remainingTime = LOGIN_LOCKOUT_TIME - ($currentTime - $attempts[$username]['time']);
                    return [
                        'allowed' => false, 
                        'message' => 'Zu viele Anmeldeversuche. Bitte warten Sie ' . ceil($remainingTime / 60) . ' Minuten.'
                    ];
                } else {
                    // Lockout abgelaufen, zurücksetzen
                    unset($attempts[$username]);
                }
            }
        }
        
        return ['allowed' => true];
    }
    
    /**
     * Registriert fehlgeschlagenen Login-Versuch
     */
    public static function registerFailedLogin($username) {
        if (!isset($_SESSION['login_attempts'])) {
            $_SESSION['login_attempts'] = [];
        }
        
        if (!isset($_SESSION['login_attempts'][$username])) {
            $_SESSION['login_attempts'][$username] = [
                'count' => 0,
                'time' => time()
            ];
        }
        
        $_SESSION['login_attempts'][$username]['count']++;
        $_SESSION['login_attempts'][$username]['time'] = time();
    }
    
    /**
     * Löscht Login-Versuche nach erfolgreichem Login
     */
    public static function clearLoginAttempts($username) {
        if (isset($_SESSION['login_attempts'][$username])) {
            unset($_SESSION['login_attempts'][$username]);
        }
    }
    
    /**
     * Hasht Passwort sicher
     */
    public static function hashPassword($password) {
        return password_hash($password, PASSWORD_ARGON2ID, [
            'memory_cost' => 65536,
            'time_cost' => 4,
            'threads' => 3
        ]);
    }
    
    /**
     * Verifiziert Passwort
     */
    public static function verifyPassword($password, $hash) {
        return password_verify($password, $hash);
    }
    
    /**
     * Regeneriert Session-ID (Session-Fixation-Schutz)
     */
    public static function regenerateSession() {
        // Alte Session-Daten sichern
        $oldSession = $_SESSION;
        
        // Session-ID regenerieren
        session_regenerate_id(true);
        
        // Daten wiederherstellen
        $_SESSION = $oldSession;
    }
    
    /**
     * Prüft Session-Timeout
     */
    public static function checkSessionTimeout() {
        if (isset($_SESSION['last_activity'])) {
            if (time() - $_SESSION['last_activity'] > SESSION_LIFETIME) {
                session_unset();
                session_destroy();
                return false;
            }
        }
        $_SESSION['last_activity'] = time();
        return true;
    }
    
    /**
     * Validiert E-Mail-Adresse
     */
    public static function validateEmail($email) {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }
    
    /**
     * Validiert Datum
     */
    public static function validateDate($date, $format = 'Y-m-d') {
        $d = DateTime::createFromFormat($format, $date);
        return $d && $d->format($format) === $date;
    }
    
    /**
     * Loggt Sicherheitsrelevante Events
     */
    public static function logSecurityEvent($event, $details = []) {
        $logFile = __DIR__ . '/logs/security.log';
        $logDir = dirname($logFile);
        
        if (!is_dir($logDir)) {
            mkdir($logDir, 0755, true);
        }
        
        $logEntry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'event' => $event,
            'user' => $_SESSION['username'] ?? 'anonymous',
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'details' => $details
        ];
        
        file_put_contents(
            $logFile, 
            json_encode($logEntry) . PHP_EOL, 
            FILE_APPEND | LOCK_EX
        );
    }
}

/**
 * Hilfsfunktion für Sicherheitslogging mit PDO-Connection
 */
function logSecurityEvent($conn, $event_type, $user_id, $description) {
    try {
        $stmt = $conn->prepare(
            "INSERT INTO security_log (event_type, user_id, description, ip_address) 
             VALUES (?, ?, ?, ?)"
        );
        $stmt->execute([
            $event_type,
            $user_id,
            $description,
            $_SERVER['REMOTE_ADDR'] ?? 'unknown'
        ]);
    } catch (PDOException $e) {
        // Fallback zu Datei-Logging wenn DB-Logging fehlschlägt
        Security::logSecurityEvent($event_type, [
            'user_id' => $user_id,
            'description' => $description
        ]);
    }
}
?>