File "class-session-guard.php"

Full Path: /home/pylifeesyu/www/wp-content/plugins/admin-wp/includes/class-session-guard.php
File size: 2.89 KB
MIME-type: text/x-php
Charset: utf-8

<?php
if ( ! defined( 'ABSPATH' ) ) exit;

class AWG_Session_Guard {

    const COOKIE_SEAL = 'awg_seal';

    public static function init(): void {
        add_filter( 'attach_session_information', [ __CLASS__, 'attach_info' ], 10, 2 );
        add_action( 'init',                       [ __CLASS__, 'validate_session' ], 0 );
        add_action( 'set_auth_cookie',             [ __CLASS__, 'set_seal_cookie' ], 10, 6 );
        add_action( 'clear_auth_cookie',           [ __CLASS__, 'clear_seal_cookie' ] );
    }

    /* ---- fingerprint of the client ---- */

    private static function client_fingerprint(): string {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
        return AWG_Crypto::hmac_hex( "{$ip}|{$ua}" );
    }

    /* ---- attach fingerprint to session token ---- */

    public static function attach_info( array $info, int $user_id ): array {
        $info['awg_fp'] = self::client_fingerprint();
        return $info;
    }

    /* ---- validate on every request ---- */

    public static function validate_session(): void {
        if ( ! is_user_logged_in() ) return;

        $user_id = get_current_user_id();
        $token   = wp_get_session_token();
        if ( ! $token ) return;

        $manager = WP_Session_Tokens::get_instance( $user_id );
        $session = $manager->get( $token );
        if ( ! $session || empty( $session['awg_fp'] ) ) return;

        if ( ! hash_equals( $session['awg_fp'], self::client_fingerprint() ) ) {
            $manager->destroy( $token );

            if ( AWG_Admin_Guardian::is_whitelisted( $user_id ) ) {
                AWG_Admin_Guardian::log_incident( 'session_fp_mismatch', [
                    'user_id' => $user_id,
                    'ip'      => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
                ] );
                AWG_Secure_Comm::send_breach( 'session_hijack_attempt', [
                    'user_id' => $user_id,
                    'ip'      => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
                ] );
            }

            wp_logout();
            wp_safe_redirect( wp_login_url() );
            exit;
        }
    }

    /* ---- additional seal cookie (HMAC of session token) ---- */

    public static function set_seal_cookie( $auth_cookie, $expire, $expiration, $user_id, $scheme, $token ): void {
        if ( ! AWG_Admin_Guardian::is_whitelisted( $user_id ) ) return;

        $seal = AWG_Crypto::hmac_hex( "seal|{$token}|{$user_id}" );
        $secure = is_ssl();

        setcookie(
            self::COOKIE_SEAL,
            $seal,
            $expire,
            COOKIEPATH,
            COOKIE_DOMAIN,
            $secure,
            true
        );
    }

    public static function clear_seal_cookie(): void {
        setcookie( self::COOKIE_SEAL, '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN );
    }
}