diff --git a/changelog.txt b/changelog.txt index 19aae42..1e0e2bf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,26 @@ == Changelog == += 1.6.5 = + +_Release date: 2026-09-17_ + +**Fixed** + +* Fatal error on the login screen with newer WordPress versions: the `login_message` filter can deliver null when no message is set (observed on WordPress 7.x with PHP 8.4, TypeError on a plain visit to wp-login.php). The message callback now accepts `string|null` and coalesces null to an empty string. +* Hardened all externally-fed filter callbacks against null payloads: the four `authenticate` callbacks now accept `string|null` credentials (custom REST/SSO endpoints are known to apply the filter with null), and the `wp_redirect` filter callback coalesces a null location. Verified safe as-is: shortcode callback, Settings API sanitizer, activation hooks, and admin-hook parameters. + +**Compatibility** + +* WordPress: 5.6 – 7.1 +* PHP: 8.0 – 8.5 + +**Tests** + +* PHP Coding Standards: PHP_CodeSniffer 3.13.6 / WPCS 3.4.1 — 0 errors +* PHPStan: level 9 — 0 errors +* PHPCompatibility: 8.0–8.5 — 0 issues +* PHPUnit: 9.6.36 — 87 tests, 180 assertions + = 1.6.4 = _Release date: 2026-09-11_ diff --git a/includes/class-geo-restrictions.php b/includes/class-geo-restrictions.php index e6a10dc..7ce090e 100644 --- a/includes/class-geo-restrictions.php +++ b/includes/class-geo-restrictions.php @@ -85,13 +85,13 @@ class Geo_Restrictions { * * @since 1.5.0 * - * @param mixed $user Previously authenticated user or null. - * @param string $username Submitted username. - * @param string $password Submitted password. + * @param mixed $user Previously authenticated user or null. + * @param string|null $username Submitted username. + * @param string|null $password Submitted password. * * @return mixed */ - public function maybe_block_denied_country( mixed $user, string $username, string $password ): mixed { + public function maybe_block_denied_country( mixed $user, ?string $username, ?string $password ): mixed { unset( $username, $password ); $deny_list = $this->config->get_geoip_country_deny(); diff --git a/includes/class-ip-restrictions.php b/includes/class-ip-restrictions.php index 91b5c5e..1d28c19 100644 --- a/includes/class-ip-restrictions.php +++ b/includes/class-ip-restrictions.php @@ -82,13 +82,13 @@ class IP_Restrictions { * * @since 1.3.0 * - * @param mixed $user Previously authenticated user or error. - * @param string $username Submitted username. - * @param string $password Submitted password. + * @param mixed $user Previously authenticated user or error. + * @param string|null $username Submitted username. + * @param string|null $password Submitted password. * * @return mixed */ - public function maybe_block_denied_ip( mixed $user, string $username, string $password ): mixed { + public function maybe_block_denied_ip( mixed $user, ?string $username, ?string $password ): mixed { unset( $username, $password ); $deny_list = $this->config->get_ip_deny(); diff --git a/includes/login/class-login-form-manager.php b/includes/login/class-login-form-manager.php index fb10f05..3f00773 100644 --- a/includes/login/class-login-form-manager.php +++ b/includes/login/class-login-form-manager.php @@ -463,16 +463,21 @@ class Login_Form_Manager { is_verification_stage() ) { return $message; } @@ -619,12 +624,12 @@ class Login_Form_Manager { * Attempt to finish the verification stage during authentication. * * @param \WP_User|\WP_Error|null $user Previously authenticated user or error. - * @param string $username Submitted username. - * @param string $password Submitted password. + * @param string|null $username Submitted username. + * @param string|null $password Submitted password. * * @return \WP_User|\WP_Error|null */ - public function maybe_complete_verification( $user, string $username, string $password ) { + public function maybe_complete_verification( $user, ?string $username, ?string $password ) { if ( ! $this->is_verification_submission() ) { return $user; } @@ -785,12 +790,12 @@ class Login_Form_Manager { * Enforce the verification step for eligible users. * * @param \WP_User|\WP_Error|null $user Previously authenticated user or error. - * @param string $username Submitted username. - * @param string $password Submitted password. + * @param string|null $username Submitted username. + * @param string|null $password Submitted password. * * @return \WP_User|\WP_Error|null */ - public function enforce_verification_challenge( $user, string $username, string $password ) { + public function enforce_verification_challenge( $user, ?string $username, ?string $password ) { unset( $username, $password ); if ( $this->is_verification_stage() || $this->is_verification_submission() ) { diff --git a/includes/user/class-profile-settings.php b/includes/user/class-profile-settings.php index 6e7751d..ff2ceb8 100644 --- a/includes/user/class-profile-settings.php +++ b/includes/user/class-profile-settings.php @@ -1113,14 +1113,16 @@ class Profile_Settings { /** * Append the 2FA section anchor to redirects when requested. * - * @param string $location Redirect destination. - * @param int $status HTTP status code. + * @param string|null $location Redirect destination (null from sloppy wp_redirect() callers). + * @param int|null $status HTTP status code. * * @return string */ - public function maybe_append_section_anchor( string $location, int $status ): string { + public function maybe_append_section_anchor( ?string $location, ?int $status = null ): string { unset( $status ); + $location = $location ?? ''; + if ( ! $this->focus_section ) { return $location; } diff --git a/readme.txt b/readme.txt index b214d6b..9526647 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: security, two-factor authentication, login, otp Requires at least: 5.6 Tested up to: 7.0 Requires PHP: 8.0 -Stable tag: 1.6.4 +Stable tag: 1.6.5 License: GPLv3 or later License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -59,6 +59,15 @@ Yes. Activate the plugin at the network level. Network administrators can set an == Changelog == += 1.6.5 = + +_Release date: 2026-09-17_ + +**Fixed** + +* Fatal error on the login screen with newer WordPress versions: the `login_message` filter can deliver null when no message is set (observed on WordPress 7.x with PHP 8.4, TypeError on a plain visit to wp-login.php). The message callback now accepts `string|null` and coalesces null to an empty string. +* Hardened all externally-fed filter callbacks against null payloads: the four `authenticate` callbacks now accept `string|null` credentials (custom REST/SSO endpoints are known to apply the filter with null), and the `wp_redirect` filter callback coalesces a null location. + = 1.6.4 = _Release date: 2026-09-11_ @@ -79,20 +88,6 @@ _Release date: 2026-08-24_ * Compatibility with the ALTCHA Spam Protection plugin: when "Protect login" was enabled, submitting the 2FA verification code failed with "[ALTCHA] Sorry, your request could not be processed.". The ALTCHA interceptor is now disabled while the verification screen is shown; the first login step keeps its ALTCHA check. -= 1.6.2 = - -_Release date: 2026-08-17_ - -**Added** - -* Recommendation notice for the Manager (by ROBOTSTXT) plugin: when it is not installed and active, a dismissible notice appears on the Plugins screen and a permanent notice is shown on the plugin settings page, since updates are delivered through the Manager plugin. - -**Changed** - -* Updates are now handled by the Manager (by ROBOTSTXT) plugin. The bundled self-updater (`robotstxt-updater.php` and `update.json`) has been removed. -* Plugin and update URLs moved to `robotstxt.software`. -* Minimum WordPress version lowered from 6.4 to 5.6 after a full compatibility review (the code only requires WordPress 5.3+ functions, and WordPress 5.6 is the first release that runs on the required PHP 8.0). - = Previous versions = For the full changelog see the [changelog](https://www.robotstxt.software/plugins/robotstxt-2fa/) page. diff --git a/robotstxt-2fa.php b/robotstxt-2fa.php index 36847c7..3c1d9a4 100644 --- a/robotstxt-2fa.php +++ b/robotstxt-2fa.php @@ -4,7 +4,7 @@ * Plugin URI: https://www.robotstxt.software/plugins/robotstxt-2fa/ * Update URI: https://www.robotstxt.software/plugins/robotstxt-2fa/ * Description: Adds two-factor authentication to the WordPress login flow. - * Version: 1.6.4 + * Version: 1.6.5 * Author: ROBOTSTXT * Author URI: https://www.robotstxt.software/ * Text Domain: robotstxt-2fa @@ -25,7 +25,7 @@ if ( ! defined( 'ABSPATH' ) ) { } if ( ! defined( 'ROBOTSTXT_2FA_VERSION' ) ) { - define( 'ROBOTSTXT_2FA_VERSION', '1.6.4' ); + define( 'ROBOTSTXT_2FA_VERSION', '1.6.5' ); } if ( ! defined( 'ROBOTSTXT_2FA_FILE' ) ) { diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index e32404a..292a775 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'robotstxt/robotstxt-2fa', 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => '54a0dd9b62465320c6e7045c568aa258925b208e', + 'reference' => 'ed617610896f05f9dc90a3b0f53b19c9dacd59a5', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -40,7 +40,7 @@ 'robotstxt/robotstxt-2fa' => array( 'pretty_version' => 'dev-main', 'version' => 'dev-main', - 'reference' => '54a0dd9b62465320c6e7045c568aa258925b208e', + 'reference' => 'ed617610896f05f9dc90a3b0f53b19c9dacd59a5', 'type' => 'wordpress-plugin', 'install_path' => __DIR__ . '/../../', 'aliases' => array(),