robotstxt-2fa/changelog.txt
2026-09-17 10:58:22 +00:00

489 lines
18 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

== Changelog ==
= 1.6.6 =
_Release date: 2026-09-17_
**Added**
* Forced-enrollment warning on the profile 2FA section: when a user's role enforces 2FA but they have no verification method configured yet, the 2FA section of their profile (wp-admin and the frontend shortcode) opens with a warning notice asking them to activate at least one method. While a grace period is active, the notice appends the remaining days.
**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.08.5 — 0 issues
* PHPUnit: 9.6.36 — 93 tests, 189 assertions
= 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.08.5 — 0 issues
* PHPUnit: 9.6.36 — 87 tests, 180 assertions
= 1.6.4 =
_Release date: 2026-09-11_
**Fixed**
* Compatibility with Restrict Content Pro's "Hijack Login URL" option: RCP's `login_url` filter made every `wp_login_url()` call return a membership page, so the 2FA verification redirect landed on a restricted page where the verification form cannot render, and the visitor was bounced to the registration page. Verification-stage URLs are now built from the canonical `wp-login.php`, mirroring WordPress core's URL construction before the filterable output. The "Back to login" link keeps the site-configured login URL.
**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.08.5 — 0 issues
* PHPUnit: 9.6.36 — 78 tests, 171 assertions
= 1.6.3 =
_Release date: 2026-08-24_
**Changed**
* Manager detection now uses the ecosystem presence constant (`ROBOTSTXT_MANAGER_NOTICED`, defined by Manager 1.6.2+) with a fallback to the plugin-list scan for older Manager versions, so a stale plugin list can no longer produce false "Manager missing" notices.
**Fixed**
* 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.
**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.08.5 — 0 issues
* PHPUnit: 9.6.36 — 73 tests, 163 assertions
= 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).
**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.08.5 — 0 issues
* PHPUnit: 9.6.36 — 59 tests, 148 assertions
= 1.6.1 =
_Release date: 2026-08-14_
**Fixed**
* Fatal error during editor autosaves: the `[robotstxt_2fa_profile]` shortcode expanded when WordPress applied content filters to a post revision via REST (for example, an article that merely mentions the shortcode in its text). In that context `settings_errors()` and `submit_button()` are not defined, causing a fatal error and a failed autosave. The shortcode now bails out early on REST requests (avoiding side effects such as OTP secret generation) and loads the required wp-admin includes on demand elsewhere.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer / WPCS — 0 errors
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 59 tests, 148 assertions
= 1.6.0 =
_Release date: 2026-08-07_
**Added**
* REST API (namespace `robotstxt-2fa/v1`, admin-only): `GET/PUT /settings` to read and update the full configuration; `GET /users?role=&status=` to list users with their 2FA status (enabled, configured methods, required methods, forced, frequency, preferred method, OTP configured, unused recovery codes). No secrets exposed.
**Changed**
* `wp 2fa list` — separate Enabled, Methods, and Required columns; new `--required` filter.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer / WPCS — 0 errors
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 55 tests, 140 assertions
= 1.5.3 =
_Release date: 2026-08-07_
**Added**
* Per-user preferred sign-in method — "Preferred method" dropdown on the user profile (shown when two or more methods are enabled) lets each user pick which verification method is requested first at login.
* Failed attempts are now cleared for the user on any successful 2FA login (email, OTP, or recovery), so no errors remain queued once they authenticate correctly.
* GeoIP auto-download — optional "Use the free ROBOTSTXT GeoIP database" checkbox in 2FA > Settings downloads the country database from ip.robotstxt.es into the uploads directory and refreshes it daily via WordPress cron. Includes a manual "Update now" button.
**Fixed**
* Security: the "Require 2FA to create Application Passwords" guard could be bypassed by requesting `/wp/v2/users/me/application-passwords` (the regex only matched numeric user IDs). Now accepts the `me` alias.
**Changed**
* Role enforcement is now a floor, not a ceiling. Required methods are still forced on the profile (enforced setup), but at login users may authenticate with any method they have configured — not only the role-required ones. Fixes users who only saw email despite configuring OTP/recovery.
* "Remember this browser" duration now follows each user's verification frequency (daily/weekly/monthly) instead of a fixed global value, so the checkbox always complies with the profile setting.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer / WPCS — 0 errors
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 50 tests, 121 assertions
= 1.5.2 =
_Release date: 2026-06-06_
**Added**
* OTP import tool (2FA > Import) — import authenticator secrets from third-party 2FA plugins without requiring users to reconfigure their app:
* Two Factor (community) — plain Base32 from `_two_factor_totp_key` user meta.
* WP 2FA (Melapress) — plain or encrypted Base32 from `wp_2fa_totp_key` user meta; decrypted if WP 2FA is active.
* Wordfence Login Security — raw binary from `wfls_2fa_secrets` table, Base32-encoded on import.
* Admin notice banner when importable secrets are detected; dismissible per-admin for 7 days or permanently via Import page preference.
* Import correctly skips users who already have OTP actively configured in our plugin; only imports for users who have not yet activated OTP here.
**Fixed**
* Deactivating the Authenticator App method from the profile no longer pre-generates a new OTP secret immediately. The secret is deleted cleanly and a fresh QR code is generated lazily the next time the user views their profile. This ensures the import tool can correctly detect these users as candidates.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.5.1 =
_Release date: 2026-06-06_
**Security**
* CSV exports use RFC 4180 encoding — fields with commas, double-quotes, or line breaks are correctly quoted. Replaces `addslashes()`.
* GeoIP database path validated with `is_file()` and `!is_link()` at read time to block symlink traversal.
* `robotstxt_2fa_app_password_verification_window` filter return validated as a positive integer; falls back to 900 for invalid values.
**Fixed**
* Export CSV button now only rendered to users with `manage_options` capability.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.5.0 =
_Release date: 2026-06-05_
**Added**
* Full audit user table (WP_List_Table) with sortable columns, role/status filters, and CSV export.
* GeoIP country restrictions via optional MaxMind GeoLite2 database: per-country allow list, deny list, always-challenge list.
* Require recent 2FA verification before creating Application Passwords (REST endpoint, 15-min window, filterable).
* WP-CLI `wp 2fa export` — CSV report via stdout.
* `robotstxt_2fa_force_challenge` filter — override frequency skip; used by GeoIP always-challenge.
* `maxmind-db/reader` added as optional production Composer dependency.
**Fixed**
* Email digest cron now reschedules correctly when frequency changes (weekly ↔ monthly).
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.4.0 =
_Release date: 2026-06-05_
**Added**
* Audit Dashboard — top-level admin page with summary cards (total users, 2FA-enabled, recent failed attempts), failed attempts table, and 2FA status column in Users list.
* Failed attempts log — `robotstxt_2fa_failed_log` ring buffer (max 100 entries) populated on every failed verification; IPs anonymized.
* Email notifications (each independently configurable):
* Admin-enabled 2FA: user is notified when an administrator activates 2FA for them.
* New location login: user is notified on first successful login from an unrecognised context.
* Recovery code used: user (and optionally site admin) notified when a recovery code is consumed.
* Activity digest: WP-Cron weekly or monthly summary sent to administrators.
* Application Passwords exemption: REST API clients skip the 2FA browser challenge by default.
* IP allow list: IPs/CIDR ranges that bypass 2FA (via `robotstxt_2fa_skip_challenge`).
* IP deny list: IPs/CIDR ranges blocked from login entirely (via `authenticate` at priority 1).
* IPv4 + IPv6 CIDR matching (pure PHP, no external dependency).
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.3.0 =
_Release date: 2026-06-05_
**Security**
* TOTP replay prevention: accepted counter step stored in a 90-second transient; same code rejected on second submission within the ±1 window.
* Login username removed from 2FA redirect URLs: `robotstxt-2fa-login` query parameter replaced with an opaque 32-character token resolved server-side. Username never appears in browser history, logs, or referrer headers.
**Added**
* WP-CLI command family `wp 2fa` (loaded only when `WP_CLI` is defined):
* `wp 2fa status <user_id>` — show 2FA configuration.
* `wp 2fa enable <user_id> [--method=<method>]` — enable 2FA.
* `wp 2fa disable <user_id>` — disable 2FA, preserving secrets and codes.
* `wp 2fa reset-recovery <user_id>` — regenerate and display recovery codes.
* `wp 2fa list [--role=<role>] [--without-2fa] [--format=table|csv|json]` — list users with 2FA status.
* `wp 2fa force-setup [<user_id>] [--role=<role>] [--method=<method>]` — enforce 2FA.
* `wp 2fa bypass <user_id> [--days=<n>]` — grant temporary bypass (max 30 days).
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.2.1 =
_Release date: 2026-06-05_
**Fixed**
* Recovery code confirmation without the method checkbox now correctly activates the method.
* Fatal error on admin profile pages (add_settings_error not available at init in multisite).
* OTP and recovery text inputs no longer disabled by JS when Enable toggle is off.
* Regenerate codes now requires re-confirmation before the method reactivates.
* Entering a valid OTP or recovery code activates the method even without checking the checkbox.
* Recovery regeneration field validated with strict value check.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.1.0 =
_Release date: 2026-06-05_
**Added**
* Developer filter/action hooks: `robotstxt_2fa_skip_challenge`, `robotstxt_2fa_verification_success`, `robotstxt_2fa_verification_failed`, `robotstxt_2fa_method_enabled`, `robotstxt_2fa_method_disabled`, `robotstxt_2fa_code_length`, `robotstxt_2fa_code_ttl`, `robotstxt_2fa_resend_interval`, `robotstxt_2fa_email_subject`, `robotstxt_2fa_email_message`, `robotstxt_2fa_before_send_email`.
* `robotstxt_2fa_required_methods_for_user` filter to override per-user method requirements.
* `robotstxt_2fa_profile_wrapper_class` filter for the frontend shortcode container.
* `[robotstxt_2fa_profile]` shortcode — renders the full 2FA settings section on any WordPress page without requiring wp-admin access. Supports `user_id` and `redirect` attributes.
* `top_up_codes_for_user()` method on `Recovery_Codes` — generates only the missing codes to fill the batch back to 10, preserving existing unused codes.
* "Regenerate codes" button on the profile when recovery codes are active, without needing to disable and re-enable the method.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 1.0.0 =
_Release date: 2026-06-05_
**Fixed**
* Enable 2FA checkbox now defaults to email and pre-checks it in the UI on first activation.
* QR code for authenticator apps now displays correctly in the user profile.
* "Send the code again" link is disabled for 60 seconds after delivery with a live countdown.
**Changed**
* Recovery codes section redesigned: plain list with code chips, no coloured notification box.
* 2FA login screen links now in a vertical list for better readability.
**Removed**
* "Generate new secret" button from the OTP section.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 0.3.0 =
_Release date: 2026-06-05_
**Added**
* Delete-on-uninstall option (disabled by default — all plugin data is preserved on removal).
**Security**
* Email verification codes now use `random_int()` (CSPRNG).
* Recovery code preview transient TTL reduced from indefinite to 5 minutes.
**Fixed**
* Network admin settings now save correctly via a dedicated handler writing to `wp_sitemeta`.
* Settings option registered with `autoload=false`.
* `update.json` corrected to reference the 2FA plugin instead of the SMTP plugin.
**Compatibility**
* WordPress: 6.4 7.1
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPCompatibility: 8.08.5 — 0 issues
* PHPUnit: 9.6.34 — 42 tests, 109 assertions
= 0.2.0 =
_Release date: 2026-06-05_
**Added**
* Per-role 2FA method matrix with select-all row/column controls.
* Authenticator app (TOTP) support with QR provisioning and manual setup key.
* Recovery codes: 10 single-use 8-digit codes with confirmation workflow.
* Email-based verification codes with 60-second resend throttle and 10-minute expiry.
* Configurable verification frequency (every login, daily, weekly, monthly) per device.
* Dedicated stage token (WP nonce) securing the 2FA screen.
* Network-wide multisite support.
* Admin settings page with top-level menu.
**Changed**
* Profile method checkboxes require explicit confirmation before activation.
**Fixed**
* QR generation errors caught; recovery-code preview persists until acknowledged.
**Compatibility**
* WordPress: 6.4 7.0
* PHP: 8.0 8.5
**Tests**
* PHP Coding Standards: PHP_CodeSniffer 3.13.5 / WPCS 3.3.0
* PHPStan: level 9 — 0 errors
* PHPUnit: 9.6.34
= 0.1.0 =
_Release date: 2024-04-08_
**Added**
* Initial plugin skeleton.
* Documentation files.
* Placeholder classes for login handling, profile integration, and admin settings.