This commit is contained in:
Javier Casares 2026-08-14 16:26:36 +00:00
commit 1f7343cd9d
5 changed files with 55 additions and 68 deletions

View file

@ -1,5 +1,25 @@
== Changelog ==
= 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_

View file

@ -97,6 +97,14 @@ class Frontend_Profile {
* @return string
*/
public function render_shortcode( $atts ): string {
// Content filters (including shortcodes) also run on REST requests,
// e.g. when the editor autosaves a post that mentions the shortcode
// in its text. Rendering there is useless and has side effects
// (such as generating an OTP secret), so bail out early.
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
return '';
}
if ( ! is_user_logged_in() ) {
return '';
}
@ -123,6 +131,17 @@ class Frontend_Profile {
return '';
}
// settings_errors() and submit_button() are defined in wp-admin
// includes that are not loaded on frontend or REST requests (the
// shortcode also renders when content filters run on REST autosaves).
// Load them on demand.
if ( ! function_exists( 'settings_errors' ) ) {
require_once ABSPATH . 'wp-admin/includes/misc.php';
}
if ( ! function_exists( 'submit_button' ) ) {
require_once ABSPATH . 'wp-admin/includes/template.php';
}
ob_start();
/**

View file

@ -4,7 +4,7 @@ Tags: security, two-factor authentication, login, otp
Requires at least: 6.4
Tested up to: 7.0
Requires PHP: 8.0
Stable tag: 1.6.0
Stable tag: 1.6.1
License: GPLv3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@ -59,6 +59,14 @@ Yes. Activate the plugin at the network level. Network administrators can set an
== Changelog ==
= 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 the wp-admin render helpers are not loaded, causing a fatal error. The shortcode now bails out early on REST requests and loads the required wp-admin includes on demand elsewhere.
= 1.6.0 =
_Release date: 2026-08-07_
@ -90,66 +98,6 @@ _Release date: 2026-08-07_
* Security: the "Require 2FA to create Application Passwords" check could be bypassed via the `/wp/v2/users/me/application-passwords` REST route. The route matcher now accepts the `me` alias.
= 1.5.2 =
_Release date: 2026-06-06_
**Added**
* OTP secret import tool (2FA > Import) — detects authenticator app secrets from three supported plugins and lets administrators import them with one click, without users needing to reconfigure their authenticator app:
* **Two Factor** (community plugin) — reads `_two_factor_totp_key` user meta (plain Base32, direct import).
* **WP 2FA** (Melapress) — reads `wp_2fa_totp_key` user meta; decrypts if WP 2FA is still active, imports plain-text secrets otherwise.
* **Wordfence Login Security** — reads from the `wfls_2fa_secrets` database table (raw binary, Base32-encoded on import).
* Import skips users who already have OTP actively configured in our plugin.
* Admin notice banner when importable secrets are detected — shows count and link to import tool; dismissible per-admin for 7 days or permanently via a setting on the Import page.
**Fixed**
* Deactivating the Authenticator App from the profile no longer immediately pre-generates a new OTP secret. The secret is now deleted cleanly, and a fresh QR code is generated lazily on the next profile view.
= 1.5.1 =
_Release date: 2026-06-06_
**Security**
* CSV exports (dashboard and WP-CLI) now use RFC 4180 encoding instead of `addslashes()` — fields with commas, double-quotes, or newlines are correctly quoted.
* GeoIP database path validated at read time with `is_file()` and `! is_link()` to prevent symlink traversal.
* `robotstxt_2fa_app_password_verification_window` filter return value validated as a positive integer before use.
**Fixed**
* Export CSV button is now only rendered to users with `manage_options` capability.
= 1.5.0 =
_Release date: 2026-06-05_
**Added**
* Full audit user table — WP_List_Table with sortable columns (user, last verified), role and status filters, and one-click CSV export.
* GeoIP country restrictions — optional MaxMind GeoLite2 integration: per-country allow list (bypass 2FA), deny list (block login), always-challenge list (override frequency). Disabled when no database file is configured.
* Require 2FA before creating Application Passwords — REST endpoint rejects requests unless 2FA was completed within the last 15 minutes (configurable via `robotstxt_2fa_app_password_verification_window` filter).
* WP-CLI `wp 2fa export` — outputs a full CSV report.
* New developer filter `robotstxt_2fa_force_challenge` — override frequency-based skip and always require a fresh challenge.
**Fixed**
* Email digest cron now correctly reschedules when the frequency is changed between weekly and monthly.
= 1.4.0 =
_Release date: 2026-06-05_
**Added**
* Audit Dashboard — top-level admin page with three summary cards (total users, 2FA-enabled count, recent failed attempts), a recent failed attempts table, and a 2FA status column in the Users list.
* Email notifications — four configurable event types: admin-enabled 2FA, login from unrecognised browser/IP, recovery code used (with optional admin copy), and a weekly or monthly activity digest for administrators.
* Application Passwords exemption — REST API and WP-CLI clients authenticated via Application Passwords skip the 2FA browser challenge by default. Configurable in Settings → Access control.
* IP allow list — IPs and CIDR ranges that bypass the 2FA challenge entirely (e.g. office networks).
* IP deny list — IPs and CIDR ranges that are blocked from logging in altogether.
* All IP matching supports both IPv4 and IPv6 CIDR notation.
= Previous versions =
For the full changelog see the [changelog.txt](https://git.robotstxt.es/ROBOTSTXT/robotstxt-2fa/raw/branch/main/changelog.txt) file.

View file

@ -3,7 +3,7 @@
* Plugin Name: 2FA (by ROBOTSTXT)
* Plugin URI: https://www.robotstxt.es/plugins/robotstxt-2fa/
* Description: Adds two-factor authentication to the WordPress login flow.
* Version: 1.6.0
* Version: 1.6.1
* Author: ROBOTSTXT
* Author URI: https://www.robotstxt.es/
* Text Domain: robotstxt-2fa
@ -23,7 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
if ( ! defined( 'ROBOTSTXT_2FA_VERSION' ) ) {
define( 'ROBOTSTXT_2FA_VERSION', '1.6.0' );
define( 'ROBOTSTXT_2FA_VERSION', '1.6.1' );
}
if ( ! defined( 'ROBOTSTXT_2FA_FILE' ) ) {

View file

@ -1,20 +1,20 @@
{
"name": "2FA (by ROBOTSTXT)",
"slug": "robotstxt-2fa",
"version": "1.6.0",
"download_url": "https://git.robotstxt.es/ROBOTSTXT/robotstxt-2fa/releases/download/1.6.0/robotstxt-2fa-1.6.0.zip",
"version": "1.6.1",
"download_url": "https://git.robotstxt.es/ROBOTSTXT/robotstxt-2fa/releases/download/1.6.1/robotstxt-2fa-1.6.1.zip",
"requires": "6.4",
"requires_php": "8.0",
"tested": "7.1",
"last_updated": "2026-08-07",
"last_updated": "2026-08-14",
"author": "ROBOTSTXT",
"author_profile": "https://www.robotstxt.es/",
"homepage": "https://www.robotstxt.es/plugins/robotstxt-2fa/",
"description": "Adds per-role two-factor authentication to the WordPress login flow. Supports email codes, authenticator apps (TOTP), and recovery codes.",
"changelog": "<h3>1.6.0 - 2026-08-07</h3><ul><li><strong>Added:</strong> Admin-only REST API (robotstxt-2fa/v1) — <code>GET/PUT /settings</code> to read/update configuration and <code>GET /users</code> to list users with their 2FA status, configured methods, required methods, and more.</li><li><strong>Changed:</strong> <code>wp 2fa list</code> now shows Enabled, Methods, and Required columns plus a <code>--required</code> filter.</li></ul>",
"changelog": "<h3>1.6.1 - 2026-08-14</h3><ul><li><strong>Fixed:</strong> Fatal error during editor autosaves — the <code>[robotstxt_2fa_profile]</code> shortcode expanded when WordPress applied content filters to a post revision via REST (e.g. an article that merely mentions the shortcode). The shortcode now bails out early on REST requests and loads the required wp-admin includes on demand elsewhere.</li></ul>",
"sections": {
"description": "Adds per-role two-factor authentication to the WordPress login flow. Supports email codes, authenticator apps (TOTP), and recovery codes.",
"changelog": "<h3>1.6.0 - 2026-08-07</h3><ul><li><strong>Added:</strong> Admin-only REST API (robotstxt-2fa/v1) — <code>GET/PUT /settings</code> to read/update configuration and <code>GET /users</code> to list users with their 2FA status, configured methods, required methods, and more.</li><li><strong>Changed:</strong> <code>wp 2fa list</code> now shows Enabled, Methods, and Required columns plus a <code>--required</code> filter.</li></ul>"
"changelog": "<h3>1.6.1 - 2026-08-14</h3><ul><li><strong>Fixed:</strong> Fatal error during editor autosaves — the <code>[robotstxt_2fa_profile]</code> shortcode expanded when WordPress applied content filters to a post revision via REST (e.g. an article that merely mentions the shortcode). The shortcode now bails out early on REST requests and loads the required wp-admin includes on demand elsewhere.</li></ul>"
},
"banners": { "low": "", "high": "" },
"icons": { "1x": "", "2x": "" }