<?php
/**
 * HTTP Security Headers — one-stop OWASP-recommended response headers.
 *
 * Setzt eine kuratierte Auswahl an Security-Headers für alle Frontend-Responses:
 * - X-Frame-Options: SAMEORIGIN  (Clickjacking-Schutz)
 * - X-Content-Type-Options: nosniff  (MIME-Sniffing-Schutz)
 * - Referrer-Policy: strict-origin-when-cross-origin  (Referrer-Privacy)
 * - Permissions-Policy: deny camera/microphone/geolocation by default
 * - Strict-Transport-Security: max-age=31536000  (HSTS, nur wenn HTTPS)
 * - Content-Security-Policy: report-only (Default sicher, kann nach Test enforced werden)
 * - Cross-Origin-Opener-Policy: same-origin
 * - Cross-Origin-Resource-Policy: same-site
 *
 * Alle einzeln togglebar — Default = alle an.
 *
 * @package Brainwerk Security Suite
 */

if ( ! defined( 'ABSPATH' ) ) exit;

class Shieldforge_Headers {

    public static function register( Shieldforge_Loader $loader ) {
        if ( ! Shieldforge_Settings::get( 'headers_enabled', false ) ) return;
        $loader->add_action( 'send_headers', __CLASS__, 'emit', 99 );
    }

    public static function emit() {
        if ( is_admin() || wp_doing_ajax() || wp_doing_cron() ) return;

        $s = function ( $key, $default = true ) { return (bool) Shieldforge_Settings::get( 'headers_' . $key, $default ); };

        if ( $s( 'x_frame' ) ) {
            $val = Shieldforge_Settings::get( 'headers_x_frame_value', 'SAMEORIGIN' );
            header( 'X-Frame-Options: ' . sanitize_text_field( $val ) );
        }
        if ( $s( 'x_content_type' ) ) {
            header( 'X-Content-Type-Options: nosniff' );
        }
        if ( $s( 'referrer_policy' ) ) {
            $val = Shieldforge_Settings::get( 'headers_referrer_policy_value', 'strict-origin-when-cross-origin' );
            header( 'Referrer-Policy: ' . sanitize_text_field( $val ) );
        }
        if ( $s( 'permissions_policy' ) ) {
            $default = 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), accelerometer=(), gyroscope=()';
            $val = Shieldforge_Settings::get( 'headers_permissions_policy_value', $default );
            header( 'Permissions-Policy: ' . sanitize_text_field( $val ) );
        }
        if ( $s( 'hsts' ) && is_ssl() ) {
            $max_age   = (int) Shieldforge_Settings::get( 'headers_hsts_max_age', 31536000 );
            $subdomains = (bool) Shieldforge_Settings::get( 'headers_hsts_subdomains', false );
            $preload    = (bool) Shieldforge_Settings::get( 'headers_hsts_preload', false );
            $line = 'Strict-Transport-Security: max-age=' . $max_age;
            if ( $subdomains ) $line .= '; includeSubDomains';
            if ( $preload )    $line .= '; preload';
            header( $line );
        }
        if ( $s( 'csp', false ) ) {
            $mode = Shieldforge_Settings::get( 'headers_csp_mode', 'report-only' ); // report-only|enforce
            $default_csp = "default-src 'self' https:; img-src 'self' https: data:; style-src 'self' 'unsafe-inline' https:; script-src 'self' 'unsafe-inline' https:; font-src 'self' https: data:; frame-ancestors 'self'";
            $val = Shieldforge_Settings::get( 'headers_csp_value', $default_csp );
            $header_name = ( 'enforce' === $mode ) ? 'Content-Security-Policy' : 'Content-Security-Policy-Report-Only';
            header( $header_name . ': ' . $val );
        }
        if ( $s( 'coop' ) ) {
            header( 'Cross-Origin-Opener-Policy: same-origin' );
        }
        if ( $s( 'corp' ) ) {
            header( 'Cross-Origin-Resource-Policy: same-site' );
        }
        // Server-Header verstecken (defensiv — verrät weniger Stack-Info)
        if ( $s( 'hide_server', false ) ) {
            header_remove( 'X-Powered-By' );
            header_remove( 'Server' );
        }
    }
}
