Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,4 +157,4 @@ Tests `Two_Factor_Dummy_Secure` (a fixture that always _fails_ authentication, u
## Test Helpers

- **`tests/bootstrap.php`** — Locates the WordPress test library (via `WP_TESTS_DIR` env var, relative path, or `/tmp/wordpress-tests-lib`), loads the plugin via `muplugins_loaded`, then boots the WP test environment.
- **`tests/class-secure-dummy.php`** — Defines `Two_Factor_Dummy_Secure`, a test-only provider class that spoofs the key of `Two_Factor_Dummy` but always fails `validate_authentication`. Used by `Tests_Two_Factor_Dummy_Secure` and some core tests.
- **`tests/class-two-factor-secure-dummy.php`** — Defines `Two_Factor_Dummy_Secure`, a test-only provider class that spoofs the key of `Two_Factor_Dummy` but always fails `validate_authentication`. Used by `Tests_Two_Factor_Dummy_Secure` and some core tests.
104 changes: 50 additions & 54 deletions class-two-factor-core.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,8 +209,7 @@ public static function uninstall() {
$user_meta_keys,
call_user_func( array( $provider_class, 'uninstall_user_meta_keys' ) )
);
} catch ( Exception $e ) {
// Do nothing.
} catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch -- Intentionally empty, provider may not implement this method.
}
}

Expand All @@ -221,8 +220,7 @@ public static function uninstall() {
$option_keys,
call_user_func( array( $provider_class, 'uninstall_options' ) )
);
} catch ( Exception $e ) {
// Do nothing.
} catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch -- Intentionally empty, provider may not implement this method.
}
}
}
Expand Down Expand Up @@ -1144,32 +1142,32 @@ public static function login_html( $user, $login_nonce, $redirect_to, $error_msg
</form>

<?php
$links = array();
$links = array();

if ( $backup_providers ) {
$backup_link_args = array(
'action' => $action,
'wp-auth-id' => $user->ID,
'wp-auth-nonce' => $login_nonce,
);
if ( $rememberme ) {
$backup_link_args['rememberme'] = $rememberme;
}
if ( $redirect_to ) {
$backup_link_args['redirect_to'] = $redirect_to;
}
if ( $interim_login ) {
$backup_link_args['interim-login'] = 1;
}
if ( $backup_providers ) {
$backup_link_args = array(
'action' => $action,
'wp-auth-id' => $user->ID,
'wp-auth-nonce' => $login_nonce,
);
if ( $rememberme ) {
$backup_link_args['rememberme'] = $rememberme;
}
if ( $redirect_to ) {
$backup_link_args['redirect_to'] = $redirect_to;
}
if ( $interim_login ) {
$backup_link_args['interim-login'] = 1;
}

foreach ( $backup_providers as $backup_provider_key => $backup_provider ) {
$backup_link_args['provider'] = $backup_provider_key;
$links[] = array(
'url' => self::login_url( $backup_link_args ),
'label' => $backup_provider->get_alternative_provider_label(),
);
}
foreach ( $backup_providers as $backup_provider_key => $backup_provider ) {
$backup_link_args['provider'] = $backup_provider_key;
$links[] = array(
'url' => self::login_url( $backup_link_args ),
'label' => $backup_provider->get_alternative_provider_label(),
);
}
}

/**
* Filters the links displayed on the two-factor login form.
Expand All @@ -1191,9 +1189,9 @@ public static function login_html( $user, $login_nonce, $redirect_to, $error_msg
</p>
<ul>
<?php
foreach ( $links as $link ) {
echo '<li><a href="' . esc_url( $link['url'] ) . '">' . esc_html( $link['label'] ) . '</a></li>';
}
foreach ( $links as $link ) {
echo '<li><a href="' . esc_url( $link['url'] ) . '">' . esc_html( $link['label'] ) . '</a></li>';
}
?>
</ul>
</div>
Expand Down Expand Up @@ -1507,7 +1505,7 @@ public static function current_user_can_update_two_factor_options( $context = 'd
*/
$two_factor_revalidate_time = apply_filters( 'two_factor_revalidate_time', 10 * MINUTE_IN_SECONDS, $user_id, $context );

if ( $context === 'save' ) {
if ( 'save' === $context ) {
$two_factor_revalidate_time *= 2;
}

Expand Down Expand Up @@ -1961,15 +1959,14 @@ public static function send_password_reset_emails( $user ) {
public static function notify_user_password_reset( $user ) {
$user_message = sprintf(
/* translators: 1: username, 2: site URL, 3: URL to password best-practices article, 4: URL to reset password */
__( 'Hello %1$s, an unusually high number of failed login attempts have been detected on your account at %2$s.

These attempts successfully entered your password, and were only blocked because they failed to enter your second authentication factor. Despite not being able to access your account, this behavior indicates that the attackers have compromised your password. The most common reasons for this are that your password was easy to guess, or was reused on another site which has been compromised.

To protect your account, your password has been reset, and you will need to create a new one. For advice on setting a strong password, please read %3$s

To pick a new password, please visit %4$s

This is an automated notification. If you would like to speak to a site administrator, please contact them directly.', 'two-factor' ),
__(
'Hello %1$s, an unusually high number of failed login attempts have been detected on your account at %2$s.
These attempts successfully entered your password, and were only blocked because they failed to enter your second authentication factor. Despite not being able to access your account, this behavior indicates that the attackers have compromised your password. The most common reasons for this are that your password was easy to guess, or was reused on another site which has been compromised.
To protect your account, your password has been reset, and you will need to create a new one. For advice on setting a strong password, please read %3$s
To pick a new password, please visit %4$s
This is an automated notification. If you would like to speak to a site administrator, please contact them directly.',
'two-factor'
),
esc_html( $user->user_login ),
home_url(),
'https://wordpress.org/documentation/article/password-best-practices/',
Expand Down Expand Up @@ -1999,15 +1996,14 @@ public static function notify_admin_user_password_reset( $user ) {

$message = sprintf(
/* translators: 1: username, 2: user ID, 3: URL to developer docs */
__( 'Hello, this is a notice from the Two Factor plugin to inform you that an unusually high number of failed login attempts have been detected on the %1$s account (ID %2$d).

Those attempts successfully entered the user\'s password, and were only blocked because they entered invalid second authentication factors.

To protect their account, the password has automatically been reset, and they have been notified that they will need to create a new one.

If you do not wish to receive these notifications, you can disable them with the `two_factor_notify_admin_user_password_reset` filter. See %3$s for more information.

Thank you', 'two-factor' ),
__(
'Hello, this is a notice from the Two Factor plugin to inform you that an unusually high number of failed login attempts have been detected on the %1$s account (ID %2$d).
Those attempts successfully entered the user\'s password, and were only blocked because they entered invalid second authentication factors.
To protect their account, the password has automatically been reset, and they have been notified that they will need to create a new one.
If you do not wish to receive these notifications, you can disable them with the `two_factor_notify_admin_user_password_reset` filter. See %3$s for more information.
Thank you',
'two-factor'
),
esc_html( $user->user_login ),
$user->ID,
'https://developer.wordpress.org/plugins/hooks/'
Expand Down Expand Up @@ -2458,7 +2454,7 @@ public static function user_two_factor_options_update( $user_id ) {
}

// Have we changed the two-factor settings for the current user? Alter their session metadata.
if ( $user_id === get_current_user_id() ) {
if ( get_current_user_id() === $user_id ) {

if ( $enabled_providers && ! $existing_providers && ! self::is_current_user_session_two_factor() ) {
// We've enabled two-factor from a non-two-factor session, set the key but not the provider, as no provider has been used yet.
Expand All @@ -2479,14 +2475,14 @@ public static function user_two_factor_options_update( $user_id ) {
}
}

// Destroy other sessions if setup 2FA for the first time, or deactivated a provider
// Destroy other sessions if setup 2FA for the first time, or deactivated a provider.
if (
// No providers, enabling one (or more)
// No providers, enabling one (or more).
( ! $existing_providers && $enabled_providers ) ||
// Has providers, and is disabling one (or more), but remaining with 2FA.
( $existing_providers && $enabled_providers && array_diff( $existing_providers, array_keys( $enabled_providers ) ) )
) {
if ( $user_id === get_current_user_id() ) {
if ( get_current_user_id() === $user_id ) {
// Keep the current session, destroy others sessions for this user.
wp_destroy_other_sessions();
} else {
Expand Down Expand Up @@ -2585,7 +2581,7 @@ public static function rememberme() {
* @return array
*/
public static function filter_session_information( $session, $user_id ) {
if ( $user_id !== get_current_user_id() ) {
if ( get_current_user_id() !== $user_id ) {
return $session;
}

Expand Down
12 changes: 6 additions & 6 deletions providers/class-two-factor-totp.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ protected function __construct() {
* @return int
*/
private static function time() {
return self::$now ?: time();
return self::$now ? self::$now : time();
}

/**
Expand Down Expand Up @@ -428,7 +428,7 @@ public function user_two_factor_options( $user ) {
'two-factor-totp-qrcode',
'twoFactorTotpQrcode',
array(
'totpUrl' => $totp_url,
'totpUrl' => $totp_url,
'qrCodeLabel' => __( 'Authenticator App QR Code', 'two-factor' ),
)
);
Expand Down Expand Up @@ -806,18 +806,18 @@ public function authentication_page( $user ) {
*
* @since 0.2.0
*
* @param string $string String to be encoded using base32.
* @param string $input String to be encoded using base32.
*
* @return string base32 encoded string without padding.
*/
public static function base32_encode( $string ) {
if ( empty( $string ) ) {
public static function base32_encode( $input ) {
if ( empty( $input ) ) {
return '';
}

$binary_string = '';

foreach ( str_split( $string ) as $character ) {
foreach ( str_split( $input ) as $character ) {
$binary_string .= str_pad( base_convert( ord( $character ), 10, 2 ), 8, '0', STR_PAD_LEFT );
}

Expand Down
3 changes: 1 addition & 2 deletions settings/class-two-factor-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public static function render_settings_page() {

// Default to all providers enabled when the option has never been saved.
$all_provider_keys = array_keys( $provider_instances );
$saved_enabled = get_option( 'two_factor_enabled_providers', $all_provider_keys );
$saved_enabled = get_option( 'two_factor_enabled_providers', $all_provider_keys );

echo '<div class="wrap two-factor-settings">';
echo '<h1>' . esc_html__( 'Two-Factor Settings', 'two-factor' ) . '</h1>';
Expand Down Expand Up @@ -94,5 +94,4 @@ public static function render_settings_page() {

echo '</div>';
}

}
File renamed without changes.
2 changes: 1 addition & 1 deletion tests/providers/class-two-factor-provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public function test_get_key_returns_class_name() {
/**
* Verify is_supported_for_user() returns true when the provider is globally registered.
*
* is_supported_for_user() checks Two_Factor_Core::get_supported_providers_for_user(),
* The method checks Two_Factor_Core::get_supported_providers_for_user(),
* which reflects global registration (the two_factor_providers filter), not per-user
* enabled state. Two_Factor_Dummy is registered globally when WP_DEBUG is true.
*
Expand Down
7 changes: 7 additions & 0 deletions two-factor.php
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@ function two_factor_get_enabled_providers_option() {
* This filter receives providers in core format: classname => path.
*
* @since 0.16
*
* @param array $providers Registered providers in classname => path format.
* @return array Filtered list of enabled providers.
*/
function two_factor_filter_enabled_providers( $providers ) {
$site_enabled = two_factor_get_enabled_providers_option();
Expand Down Expand Up @@ -170,6 +173,10 @@ function two_factor_filter_enabled_providers( $providers ) {
* Filter enabled providers for a user (classnames array) to enforce the site-enabled list.
*
* @since 0.16
*
* @param array $enabled Enabled provider classnames for the user.
* @param int $user_id ID of the user being filtered.
* @return array Filtered list of provider classnames allowed by the site.
*/
function two_factor_filter_enabled_providers_for_user( $enabled, $user_id ) {
$site_enabled = two_factor_get_enabled_providers_option();
Expand Down
Loading