updated plugin Two Factor version 0.13.0

This commit is contained in:
2025-04-29 21:20:04 +00:00
committed by Gitium
parent c950632407
commit a212704ec2
16 changed files with 547 additions and 231 deletions

View File

@ -40,7 +40,7 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
add_action( 'two_factor_user_options_' . __CLASS__, array( $this, 'user_options' ) );
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
return parent::__construct();
parent::__construct();
}
/**
@ -214,6 +214,25 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
<?php
}
/**
* Get the backup code length for a user.
*
* @param WP_User $user User object.
*
* @return int Number of characters.
*/
private function get_backup_code_length( $user ) {
/**
* Customize the character count of the backup codes.
*
* @var int $code_length Length of the backup code.
* @var WP_User $user User object.
*/
$code_length = (int) apply_filters( 'two_factor_backup_code_length', 8, $user );
return $code_length;
}
/**
* Generates backup codes & updates the user meta.
*
@ -239,8 +258,10 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
$codes_hashed = (array) get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true );
}
$code_length = $this->get_backup_code_length( $user );
for ( $i = 0; $i < $num_codes; $i++ ) {
$code = $this->get_code();
$code = $this->get_code( $code_length );
$codes_hashed[] = wp_hash_password( $code );
$codes[] = $code;
unset( $code );
@ -326,11 +347,15 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
*/
public function authentication_page( $user ) {
require_once ABSPATH . '/wp-admin/includes/template.php';
$code_length = $this->get_backup_code_length( $user );
$code_placeholder = str_repeat( 'X', $code_length );
?>
<p class="two-factor-prompt"><?php esc_html_e( 'Enter a recovery code.', 'two-factor' ); ?></p><br/>
<p class="two-factor-prompt"><?php esc_html_e( 'Enter a recovery code.', 'two-factor' ); ?></p>
<p>
<label for="authcode"><?php esc_html_e( 'Recovery Code:', 'two-factor' ); ?></label>
<input type="text" inputmode="numeric" name="two-factor-backup-code" id="authcode" class="input authcode" value="" size="20" pattern="[0-9 ]*" placeholder="1234 5678" data-digits="8" />
<input type="text" inputmode="numeric" name="two-factor-backup-code" id="authcode" class="input authcode" value="" size="20" pattern="[0-9 ]*" placeholder="<?php echo esc_attr( $code_placeholder ); ?>" data-digits="<?php echo esc_attr( $code_length ); ?>" />
</p>
<?php
submit_button( __( 'Submit', 'two-factor' ) );
@ -399,4 +424,15 @@ class Two_Factor_Backup_Codes extends Two_Factor_Provider {
// Update the backup code master list.
update_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, $backup_codes );
}
/**
* Return user meta keys to delete during plugin uninstall.
*
* @return array
*/
public static function uninstall_user_meta_keys() {
return array(
self::BACKUP_CODES_META_KEY,
);
}
}

View File

@ -21,7 +21,7 @@ class Two_Factor_Dummy extends Two_Factor_Provider {
*/
protected function __construct() {
add_action( 'two_factor_user_options_' . __CLASS__, array( $this, 'user_options' ) );
return parent::__construct();
parent::__construct();
}
/**

View File

@ -42,7 +42,7 @@ class Two_Factor_Email extends Two_Factor_Provider {
*/
protected function __construct() {
add_action( 'two_factor_user_options_' . __CLASS__, array( $this, 'user_options' ) );
return parent::__construct();
parent::__construct();
}
/**
@ -63,6 +63,22 @@ class Two_Factor_Email extends Two_Factor_Provider {
return __( 'Send a code to your email', 'two-factor' );
}
/**
* Get the email token length.
*
* @return int Email token string length.
*/
private function get_token_length() {
/**
* Number of characters in the email token.
*
* @param int $token_length Number of characters in the email token.
*/
$token_length = (int) apply_filters( 'two_factor_email_token_length', 8 );
return $token_length;
}
/**
* Generate the user token.
*
@ -72,7 +88,7 @@ class Two_Factor_Email extends Two_Factor_Provider {
* @return string
*/
public function generate_token( $user_id ) {
$token = $this->get_code();
$token = $this->get_code( $this->get_token_length() );
update_user_meta( $user_id, self::TOKEN_META_KEY_TIMESTAMP, time() );
update_user_meta( $user_id, self::TOKEN_META_KEY, wp_hash( $token ) );
@ -146,10 +162,21 @@ class Two_Factor_Email extends Two_Factor_Provider {
* Number of seconds the token is considered valid
* after the generation.
*
* @deprecated 0.11.0 Use {@see 'two_factor_email_token_ttl'} instead.
*
* @param integer $token_ttl Token time-to-live in seconds.
* @param integer $user_id User ID.
*/
return (int) apply_filters( 'two_factor_token_ttl', $token_ttl, $user_id );
$token_ttl = (int) apply_filters_deprecated( 'two_factor_token_ttl', array( $token_ttl, $user_id ), '0.11.0', 'two_factor_email_token_ttl' );
/**
* Number of seconds the token is considered valid
* after the generation.
*
* @param integer $token_ttl Token time-to-live in seconds.
* @param integer $user_id User ID.
*/
return (int) apply_filters( 'two_factor_email_token_ttl', $token_ttl, $user_id );
}
/**
@ -259,12 +286,15 @@ class Two_Factor_Email extends Two_Factor_Provider {
$this->generate_and_email_token( $user );
}
$token_length = $this->get_token_length();
$token_placeholder = str_repeat( 'X', $token_length );
require_once ABSPATH . '/wp-admin/includes/template.php';
?>
<p class="two-factor-prompt"><?php esc_html_e( 'A verification code has been sent to the email address associated with your account.', 'two-factor' ); ?></p>
<p>
<label for="authcode"><?php esc_html_e( 'Verification Code:', 'two-factor' ); ?></label>
<input type="text" inputmode="numeric" name="two-factor-email-code" id="authcode" class="input authcode" value="" size="20" pattern="[0-9 ]*" placeholder="1234 5678" data-digits="8" />
<input type="text" inputmode="numeric" name="two-factor-email-code" id="authcode" class="input authcode" value="" size="20" pattern="[0-9 ]*" autocomplete="one-time-code" placeholder="<?php echo esc_attr( $token_placeholder ); ?>" data-digits="<?php echo esc_attr( $token_length ); ?>" />
<?php submit_button( __( 'Log In', 'two-factor' ) ); ?>
</p>
<p class="two-factor-email-resend">
@ -287,7 +317,7 @@ class Two_Factor_Email extends Two_Factor_Provider {
* Send the email code if missing or requested. Stop the authentication
* validation if a new token has been generated and sent.
*
* @param WP_USer $user WP_User object of the logged-in user.
* @param WP_User $user WP_User object of the logged-in user.
* @return boolean
*/
public function pre_process_authentication( $user ) {
@ -351,4 +381,16 @@ class Two_Factor_Email extends Two_Factor_Provider {
</div>
<?php
}
/**
* Return user meta keys to delete during plugin uninstall.
*
* @return array
*/
public static function uninstall_user_meta_keys() {
return array(
self::TOKEN_META_KEY,
self::TOKEN_META_KEY_TIMESTAMP,
);
}
}

View File

@ -164,6 +164,10 @@ class Two_Factor_FIDO_U2F_Admin {
* @param WP_User $user WP_User object of the logged-in user.
*/
public static function show_user_profile( $user ) {
if ( ! Two_Factor_FIDO_U2F::is_supported_for_user( $user ) ) {
return;
}
wp_nonce_field( "user_security_keys-{$user->ID}", '_nonce_user_security_keys' );
$new_key = false;
@ -230,7 +234,7 @@ class Two_Factor_FIDO_U2F_Admin {
* @static
*
* @param int $user_id User ID.
* @return false
* @return void|never
*/
public static function catch_submission( $user_id ) {
if ( ! empty( $_REQUEST['do_new_security_key'] ) ) {
@ -243,7 +247,7 @@ class Two_Factor_FIDO_U2F_Admin {
Two_Factor_FIDO_U2F::add_security_key( $user_id, $reg );
} catch ( Exception $e ) {
return false;
return;
}
delete_user_meta( $user_id, self::REGISTER_DATA_USER_META_KEY );

View File

@ -65,7 +65,7 @@ class Two_Factor_FIDO_U2F extends Two_Factor_Provider {
add_action( 'two_factor_user_options_' . __CLASS__, array( $this, 'user_options' ) );
return parent::__construct();
parent::__construct();
}
/**
@ -143,7 +143,7 @@ class Two_Factor_FIDO_U2F extends Two_Factor_Provider {
* @since 0.1-dev
*
* @param WP_User $user WP_User object of the logged-in user.
* @return null
* @return void
*/
public function authentication_page( $user ) {
require_once ABSPATH . '/wp-admin/includes/template.php';
@ -165,7 +165,7 @@ class Two_Factor_FIDO_U2F extends Two_Factor_Provider {
?>
<p><?php esc_html_e( 'An error occurred while creating authentication data.', 'two-factor' ); ?></p>
<?php
return null;
return;
}
wp_localize_script(
@ -388,4 +388,17 @@ class Two_Factor_FIDO_U2F extends Two_Factor_Provider {
return true;
}
/**
* Return user meta keys to delete during plugin uninstall.
*
* @return array
*/
public static function uninstall_user_meta_keys() {
return array(
self::REGISTERED_KEY_USER_META_KEY,
self::AUTH_DATA_USER_META_KEY,
'_two_factor_fido_u2f_register_request', // From Two_Factor_FIDO_U2F_Admin which is not loaded during uninstall.
);
}
}

View File

@ -123,6 +123,19 @@ abstract class Two_Factor_Provider {
*/
abstract public function is_available_for_user( $user );
/**
* If this provider should be available for the user.
*
* @param WP_User|int $user WP_User object, user ID or null to resolve the current user.
*
* @return bool
*/
public static function is_supported_for_user( $user = null ) {
$providers = Two_Factor_Core::get_supported_providers_for_user( $user );
return isset( $providers[ static::class ] );
}
/**
* Generate a random eight-digit string to send out as an auth code.
*
@ -165,4 +178,24 @@ abstract class Two_Factor_Provider {
return (string) $code;
}
/**
* Return the user meta keys that need to be deletated on plugin uninstall.
*
* @return array
*/
public static function uninstall_user_meta_keys() {
return array();
}
/**
* Return the option keys that need to be deleted on plugin uninstall.
*
* Note: this method doesn't have access to the instantiated provider object.
*
* @return array
*/
public static function uninstall_options() {
return array();
}
}

View File

@ -48,7 +48,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_assets' ) );
add_action( 'two_factor_user_options_' . __CLASS__, array( $this, 'user_two_factor_options' ) );
return parent::__construct();
parent::__construct();
}
/**
@ -110,7 +110,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
* Returns the name of the provider.
*/
public function get_label() {
return _x( 'Authenticator app', 'Provider Label', 'two-factor' );
return _x( 'Authenticator App', 'Provider Label', 'two-factor' );
}
/**
@ -119,7 +119,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
* @since 0.9.0
*/
public function get_alternative_provider_label() {
return __( 'Use your authenticator app', 'two-factor' );
return __( 'Use your authenticator app for time-based one-time passwords (TOTP)', 'two-factor' );
}
/**
@ -142,7 +142,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
/**
* Rest API endpoint for handling deactivation of TOTP.
*
* @param WP_Rest_Request $request The Rest Request object.
* @param WP_REST_Request $request The Rest Request object.
* @return array Success array.
*/
public function rest_delete_totp( $request ) {
@ -151,6 +151,10 @@ class Two_Factor_Totp extends Two_Factor_Provider {
$this->delete_user_totp_key( $user_id );
if ( ! Two_Factor_Core::disable_provider_for_user( $user_id, 'Two_Factor_Totp' ) ) {
return new WP_Error( 'db_error', __( 'Unable to disable TOTP provider for this user.', 'two-factor' ), array( 'status' => 500 ) );
}
ob_start();
$this->user_two_factor_options( $user );
$html = ob_get_clean();
@ -164,7 +168,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
/**
* REST API endpoint for setting up TOTP.
*
* @param WP_Rest_Request $request The Rest Request object.
* @param WP_REST_Request $request The Rest Request object.
* @return WP_Error|array Array of data on success, WP_Error on error.
*/
public function rest_setup_totp( $request ) {
@ -203,8 +207,8 @@ class Two_Factor_Totp extends Two_Factor_Provider {
/**
* Generates a URL that can be used to create a QR code.
*
* @param WP_User $user The user to generate a URL for.
* @param string $key The secret key.
* @param WP_User $user The user to generate a URL for.
* @param string $secret_key The secret key.
*
* @return string
*/
@ -260,13 +264,13 @@ class Two_Factor_Totp extends Two_Factor_Provider {
* Display TOTP options on the user settings page.
*
* @param WP_User $user The current user being edited.
* @return false
* @return void
*
* @codeCoverageIgnore
*/
public function user_two_factor_options( $user ) {
if ( ! isset( $user->ID ) ) {
return false;
return;
}
$key = $this->get_user_totp_key( $user->ID );
@ -318,6 +322,15 @@ class Two_Factor_Totp extends Two_Factor_Provider {
qr.make();
document.querySelector( '#two-factor-qr-code a' ).innerHTML = qr.createSvgTag( 5 );
// For accessibility, markup the SVG with a title and role.
var svg = document.querySelector( '#two-factor-qr-code a svg' ),
title = document.createElement( 'title' );
svg.role = 'image';
svg.ariaLabel = <?php echo wp_json_encode( __( 'Authenticator App QR Code', 'two-factor' ) ); ?>;
title.innerText = svg.ariaLabel;
svg.appendChild( title );
};
// Run now if the document is loaded, otherwise on DOMContentLoaded.
@ -340,13 +353,20 @@ class Two_Factor_Totp extends Two_Factor_Provider {
/* translators: Example auth code. */
$placeholder = sprintf( __( 'eg. %s', 'two-factor' ), '123456' );
?>
<input type="tel" name="two-factor-totp-authcode" id="two-factor-totp-authcode" class="input" value="" size="20" pattern="[0-9 ]*" placeholder="<?php echo esc_attr( $placeholder ); ?>" />
<input type="text" inputmode="numeric" name="two-factor-totp-authcode" id="two-factor-totp-authcode" class="input" value="" size="20" pattern="[0-9 ]*" placeholder="<?php echo esc_attr( $placeholder ); ?>" autocomplete="off" />
</label>
<input type="submit" class="button totp-submit" name="two-factor-totp-submit" value="<?php esc_attr_e( 'Submit', 'two-factor' ); ?>" />
</p>
<script>
(function($){
// Focus the auth code input when the checkbox is clicked.
document.getElementById('enabled-Two_Factor_Totp').addEventListener('click', function(e) {
if ( e.target.checked ) {
document.getElementById('two-factor-totp-authcode').focus();
}
});
$('.totp-submit').click( function( e ) {
e.preventDefault();
var key = $('#two-factor-totp-key').val(),
@ -359,6 +379,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
user_id: <?php echo wp_json_encode( $user->ID ); ?>,
key: key,
code: code,
enable_provider: true,
}
} ).fail( function( response, status ) {
var errorMessage = response.responseJSON.message || status,
@ -370,8 +391,10 @@ class Two_Factor_Totp extends Two_Factor_Provider {
$error.find('p').text( errorMessage );
$( '#enabled-Two_Factor_Totp' ).prop( 'checked', false );
$('#two-factor-totp-authcode').val('');
} ).then( function( response ) {
$( '#enabled-Two_Factor_Totp' ).prop( 'checked', true );
$( '#two-factor-totp-options' ).html( response.html );
} );
} );
@ -398,6 +421,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
user_id: <?php echo wp_json_encode( $user->ID ); ?>,
}
} ).then( function( response ) {
$( '#enabled-Two_Factor_Totp' ).prop( 'checked', false );
$( '#two-factor-totp-options' ).html( response.html );
} );
} );
@ -666,7 +690,7 @@ class Two_Factor_Totp extends Two_Factor_Provider {
</p>
<p>
<label for="authcode"><?php esc_html_e( 'Authentication Code:', 'two-factor' ); ?></label>
<input type="text" inputmode="numeric" autocomplete="one-time-code" name="authcode" id="authcode" class="input authcode" value="" size="20" pattern="[0-9 ]*" placeholder="123 456" data-digits="<?php echo esc_attr( self::DEFAULT_DIGIT_COUNT ); ?>" />
<input type="text" inputmode="numeric" autocomplete="one-time-code" name="authcode" id="authcode" class="input authcode" value="" size="20" pattern="[0-9 ]*" placeholder="123 456" autocomplete="one-time-code" data-digits="<?php echo esc_attr( self::DEFAULT_DIGIT_COUNT ); ?>" />
</p>
<script type="text/javascript">
setTimeout( function(){
@ -762,4 +786,16 @@ class Two_Factor_Totp extends Two_Factor_Provider {
}
return ( $a < $b ) ? -1 : 1;
}
/**
* Return user meta keys to delete during plugin uninstall.
*
* @return array
*/
public static function uninstall_user_meta_keys() {
return array(
self::SECRET_META_KEY,
self::LAST_SUCCESSFUL_LOGIN_META_KEY,
);
}
}