Plugin Directory

Changeset 3481753


Ignore:
Timestamp:
03/13/2026 08:12:48 AM (3 weeks ago)
Author:
jerryscg
Message:

Release 2.0.7

Location:
vulntitan
Files:
8 edited
1 copied

Legend:

Unmodified
Added
Removed
  • vulntitan/tags/2.0.7/CHANGELOG.md

    r3481425 r3481753  
    55The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
    66and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
     7
     8## [2.0.7] - 2026-03-13
     9### Fixed
     10- Fixed custom login logout requests on some Nginx-backed WordPress sites so `/?action=logout` flows no longer fail with upstream `502 Bad Gateway` responses.
     11- Stabilized hidden login bootstrapping by priming the `wp-login.php` request context earlier and normalizing canonical custom login route handling.
    712
    813## [2.0.6] - 2026-03-12
  • vulntitan/tags/2.0.7/includes/Services/LoginAccessService.php

    r3481425 r3481753  
    1414    protected static bool $booted = false;
    1515    protected static bool $customLoginRequest = false;
     16    protected static bool $customLoginContextPrimed = false;
    1617
    1718    public static function boot(): void
     
    2223
    2324        self::$booted = true;
     25        self::primeCustomLoginRequestContext();
    2426
    2527        add_action('init', [__CLASS__, 'interceptRequests'], 0);
     
    5153
    5254        if (self::isCustomLoginPath($requestPath)) {
    53             self::$customLoginRequest = true;
     55            self::markCustomLoginRequest();
    5456            return;
    5557        }
     
    7880        }
    7981
     82        self::maybeRedirectCanonicalCustomLoginPath();
     83        self::primeCustomLoginContext();
     84
    8085        global $pagenow, $action, $error, $interim_login, $user_login;
    8186
     
    8590        $interim_login = $interim_login ?? false;
    8691        $user_login = is_string($user_login ?? null) ? $user_login : '';
    87 
    88         $scriptPath = (string) wp_parse_url(site_url('wp-login.php', 'login'), PHP_URL_PATH);
    89         if ($scriptPath !== '') {
    90             $_SERVER['SCRIPT_NAME'] = $scriptPath;
    91             $_SERVER['PHP_SELF'] = $scriptPath;
    92         }
    9392
    9493        require_once ABSPATH . 'wp-login.php';
     
    222221    }
    223222
     223    protected static function primeCustomLoginRequestContext(): void
     224    {
     225        if (!FirewallService::isCustomLoginEnabled()) {
     226            return;
     227        }
     228
     229        if ((defined('WP_CLI') && WP_CLI) || (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST)) {
     230            return;
     231        }
     232
     233        $requestPath = self::getCurrentRequestPath();
     234        if ($requestPath === '' || !self::isCustomLoginPath($requestPath)) {
     235            return;
     236        }
     237
     238        self::markCustomLoginRequest();
     239    }
     240
     241    protected static function markCustomLoginRequest(): void
     242    {
     243        self::$customLoginRequest = true;
     244        self::primeCustomLoginContext();
     245    }
     246
     247    protected static function primeCustomLoginContext(): void
     248    {
     249        if (self::$customLoginContextPrimed) {
     250            return;
     251        }
     252
     253        self::$customLoginContextPrimed = true;
     254
     255        global $pagenow;
     256
     257        $pagenow = 'wp-login.php';
     258
     259        $scriptPath = self::getWpLoginScriptPath();
     260        if ($scriptPath !== '') {
     261            $_SERVER['SCRIPT_NAME'] = $scriptPath;
     262            $_SERVER['PHP_SELF'] = $scriptPath;
     263        }
     264    }
     265
     266    protected static function maybeRedirectCanonicalCustomLoginPath(): void
     267    {
     268        if (!get_option('permalink_structure')) {
     269            return;
     270        }
     271
     272        if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') {
     273            return;
     274        }
     275
     276        $requestPath = self::getCurrentRequestPath();
     277        $canonicalPath = self::stripSiteBasePath((string) wp_parse_url(FirewallService::getCustomLoginUrl(), PHP_URL_PATH));
     278        if ($requestPath === '' || $canonicalPath === '') {
     279            return;
     280        }
     281
     282        if ($requestPath === $canonicalPath || untrailingslashit($requestPath) !== untrailingslashit($canonicalPath)) {
     283            return;
     284        }
     285
     286        $redirectUrl = FirewallService::getCustomLoginUrl();
     287        $queryString = (string) ($_SERVER['QUERY_STRING'] ?? '');
     288        if ($queryString !== '') {
     289            $redirectUrl .= '?' . $queryString;
     290        }
     291
     292        wp_safe_redirect($redirectUrl);
     293        exit;
     294    }
     295
    224296    protected static function getRelativeLoginUrlPattern(): string
    225297    {
     
    324396
    325397        return '/' . ltrim($normalizedPath, '/');
     398    }
     399
     400    protected static function getWpLoginScriptPath(): string
     401    {
     402        $sitePath = (string) wp_parse_url(site_url('/'), PHP_URL_PATH);
     403        $sitePath = '/' . trim($sitePath, '/');
     404        $sitePath = $sitePath === '//' ? '/' : $sitePath;
     405
     406        if ($sitePath === '/') {
     407            return '/wp-login.php';
     408        }
     409
     410        return rtrim($sitePath, '/') . '/wp-login.php';
    326411    }
    327412
  • vulntitan/tags/2.0.7/readme.txt

    r3481430 r3481753  
    44Tested up to: 6.9
    55Requires PHP: 7.4
    6 Stable tag: 2.0.6
     6Stable tag: 2.0.7
    77License: GPLv2
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    133133== Changelog ==
    134134
     135= v2.0.7 - 13 Mar, 2026 =
     136* Fixed custom login logout requests on some Nginx-backed WordPress sites so hidden login logout no longer triggers `502 Bad Gateway` responses.
     137* Stabilized hidden login request bootstrapping and canonical custom login route handling for logout/login flows.
     138
    135139= v2.0.6 - 12 Mar, 2026 =
    136140* Added configurable custom login slug support so administrators can use a private login URL instead of the default `wp-login.php` path.
  • vulntitan/tags/2.0.7/vulntitan.php

    r3481425 r3481753  
    44 * Plugin URI: https://vulntitan.com/vulntitan/
    55 * Description: VulnTitan is a lightweight WordPress security plugin with vulnerability scanning, malware detection, file integrity monitoring, and a built-in firewall with WAF payload rules and login protection.
    6  * Version: 2.0.6
     6 * Version: 2.0.7
    77 * Author: Jaroslav Svetlik
    88 * Author URI: https://vulntitan.com
     
    3030
    3131// Define plugin constants
    32 define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0.6');
     32define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0.7');
    3333define('VULNTITAN_PLUGIN_BASENAME', plugin_basename(__FILE__));
    3434define('VULNTITAN_PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__)));
  • vulntitan/trunk/CHANGELOG.md

    r3481425 r3481753  
    55The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
    66and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
     7
     8## [2.0.7] - 2026-03-13
     9### Fixed
     10- Fixed custom login logout requests on some Nginx-backed WordPress sites so `/?action=logout` flows no longer fail with upstream `502 Bad Gateway` responses.
     11- Stabilized hidden login bootstrapping by priming the `wp-login.php` request context earlier and normalizing canonical custom login route handling.
    712
    813## [2.0.6] - 2026-03-12
  • vulntitan/trunk/includes/Services/LoginAccessService.php

    r3481425 r3481753  
    1414    protected static bool $booted = false;
    1515    protected static bool $customLoginRequest = false;
     16    protected static bool $customLoginContextPrimed = false;
    1617
    1718    public static function boot(): void
     
    2223
    2324        self::$booted = true;
     25        self::primeCustomLoginRequestContext();
    2426
    2527        add_action('init', [__CLASS__, 'interceptRequests'], 0);
     
    5153
    5254        if (self::isCustomLoginPath($requestPath)) {
    53             self::$customLoginRequest = true;
     55            self::markCustomLoginRequest();
    5456            return;
    5557        }
     
    7880        }
    7981
     82        self::maybeRedirectCanonicalCustomLoginPath();
     83        self::primeCustomLoginContext();
     84
    8085        global $pagenow, $action, $error, $interim_login, $user_login;
    8186
     
    8590        $interim_login = $interim_login ?? false;
    8691        $user_login = is_string($user_login ?? null) ? $user_login : '';
    87 
    88         $scriptPath = (string) wp_parse_url(site_url('wp-login.php', 'login'), PHP_URL_PATH);
    89         if ($scriptPath !== '') {
    90             $_SERVER['SCRIPT_NAME'] = $scriptPath;
    91             $_SERVER['PHP_SELF'] = $scriptPath;
    92         }
    9392
    9493        require_once ABSPATH . 'wp-login.php';
     
    222221    }
    223222
     223    protected static function primeCustomLoginRequestContext(): void
     224    {
     225        if (!FirewallService::isCustomLoginEnabled()) {
     226            return;
     227        }
     228
     229        if ((defined('WP_CLI') && WP_CLI) || (defined('XMLRPC_REQUEST') && XMLRPC_REQUEST)) {
     230            return;
     231        }
     232
     233        $requestPath = self::getCurrentRequestPath();
     234        if ($requestPath === '' || !self::isCustomLoginPath($requestPath)) {
     235            return;
     236        }
     237
     238        self::markCustomLoginRequest();
     239    }
     240
     241    protected static function markCustomLoginRequest(): void
     242    {
     243        self::$customLoginRequest = true;
     244        self::primeCustomLoginContext();
     245    }
     246
     247    protected static function primeCustomLoginContext(): void
     248    {
     249        if (self::$customLoginContextPrimed) {
     250            return;
     251        }
     252
     253        self::$customLoginContextPrimed = true;
     254
     255        global $pagenow;
     256
     257        $pagenow = 'wp-login.php';
     258
     259        $scriptPath = self::getWpLoginScriptPath();
     260        if ($scriptPath !== '') {
     261            $_SERVER['SCRIPT_NAME'] = $scriptPath;
     262            $_SERVER['PHP_SELF'] = $scriptPath;
     263        }
     264    }
     265
     266    protected static function maybeRedirectCanonicalCustomLoginPath(): void
     267    {
     268        if (!get_option('permalink_structure')) {
     269            return;
     270        }
     271
     272        if (strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')) !== 'GET') {
     273            return;
     274        }
     275
     276        $requestPath = self::getCurrentRequestPath();
     277        $canonicalPath = self::stripSiteBasePath((string) wp_parse_url(FirewallService::getCustomLoginUrl(), PHP_URL_PATH));
     278        if ($requestPath === '' || $canonicalPath === '') {
     279            return;
     280        }
     281
     282        if ($requestPath === $canonicalPath || untrailingslashit($requestPath) !== untrailingslashit($canonicalPath)) {
     283            return;
     284        }
     285
     286        $redirectUrl = FirewallService::getCustomLoginUrl();
     287        $queryString = (string) ($_SERVER['QUERY_STRING'] ?? '');
     288        if ($queryString !== '') {
     289            $redirectUrl .= '?' . $queryString;
     290        }
     291
     292        wp_safe_redirect($redirectUrl);
     293        exit;
     294    }
     295
    224296    protected static function getRelativeLoginUrlPattern(): string
    225297    {
     
    324396
    325397        return '/' . ltrim($normalizedPath, '/');
     398    }
     399
     400    protected static function getWpLoginScriptPath(): string
     401    {
     402        $sitePath = (string) wp_parse_url(site_url('/'), PHP_URL_PATH);
     403        $sitePath = '/' . trim($sitePath, '/');
     404        $sitePath = $sitePath === '//' ? '/' : $sitePath;
     405
     406        if ($sitePath === '/') {
     407            return '/wp-login.php';
     408        }
     409
     410        return rtrim($sitePath, '/') . '/wp-login.php';
    326411    }
    327412
  • vulntitan/trunk/readme.txt

    r3481430 r3481753  
    44Tested up to: 6.9
    55Requires PHP: 7.4
    6 Stable tag: 2.0.6
     6Stable tag: 2.0.7
    77License: GPLv2
    88License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    133133== Changelog ==
    134134
     135= v2.0.7 - 13 Mar, 2026 =
     136* Fixed custom login logout requests on some Nginx-backed WordPress sites so hidden login logout no longer triggers `502 Bad Gateway` responses.
     137* Stabilized hidden login request bootstrapping and canonical custom login route handling for logout/login flows.
     138
    135139= v2.0.6 - 12 Mar, 2026 =
    136140* Added configurable custom login slug support so administrators can use a private login URL instead of the default `wp-login.php` path.
  • vulntitan/trunk/vulntitan.php

    r3481425 r3481753  
    44 * Plugin URI: https://vulntitan.com/vulntitan/
    55 * Description: VulnTitan is a lightweight WordPress security plugin with vulnerability scanning, malware detection, file integrity monitoring, and a built-in firewall with WAF payload rules and login protection.
    6  * Version: 2.0.6
     6 * Version: 2.0.7
    77 * Author: Jaroslav Svetlik
    88 * Author URI: https://vulntitan.com
     
    3030
    3131// Define plugin constants
    32 define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0.6');
     32define('VULNTITAN_PLUGIN_VERSION', VULNTITAN_DEVELOPMENT ? uniqid() : '2.0.7');
    3333define('VULNTITAN_PLUGIN_BASENAME', plugin_basename(__FILE__));
    3434define('VULNTITAN_PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__)));
Note: See TracChangeset for help on using the changeset viewer.