Currently we have some license issues. We are working on it.

Verified Commit 0f154683 authored by noplanman's avatar noplanman
Browse files

Adhere to WPCS, improve and harden code.

parent 4d95b1b1
Pipeline #4509 passed with stage
in 28 seconds
......@@ -13,6 +13,7 @@ use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;
use OTPHP\TOTP;
use ParagonIE\ConstantTime\Base32;
use Throwable;
use WP_User;
/**
......@@ -31,7 +32,7 @@ class Wp_Otp_Admin {
*/
public function enqueue_styles( $hook ): void {
if ( 'profile.php' === $hook ) {
wp_enqueue_style( WP_OTP_SLUG . '-admin', plugin_dir_url( __FILE__ ) . 'css/wp-otp-admin.css' );
wp_enqueue_style( WP_OTP_SLUG . '-admin', plugin_dir_url( __FILE__ ) . 'css/wp-otp-admin.css', [], WP_OTP_VERSION );
}
}
......@@ -46,12 +47,10 @@ class Wp_Otp_Admin {
if ( 'profile.php' === $hook ) {
$handle = WP_OTP_SLUG . '-admin';
wp_enqueue_script( $handle, plugin_dir_url( __FILE__ ) . 'js/wp-otp-admin.js', [ 'jquery' ], null, true );
wp_enqueue_script( $handle, plugin_dir_url( __FILE__ ) . 'js/wp-otp-admin.js', [ 'jquery' ], WP_OTP_VERSION, true );
wp_localize_script( $handle, 'wp_otp', [
'confirm_reconfigure' =>
__( 'Are you sure you want to reconfigure WP-OTP?', 'wp-otp' ),
'confirm_new_recovery_codes' =>
__( 'Are you sure you want to regenerate your recovery codes?', 'wp-otp' ),
'confirm_reconfigure' => __( 'Are you sure you want to reconfigure WP-OTP?', 'wp-otp' ),
'confirm_new_recovery_codes' => __( 'Are you sure you want to regenerate your recovery codes?', 'wp-otp' ),
] );
}
}
......@@ -61,16 +60,17 @@ class Wp_Otp_Admin {
*
* @since 0.1.0
*
* @param int $user_id
* @param int $user_id WordPress User ID.
*
* @return void
* @throws \Exception
*/
public function user_profile_updated( $user_id ): void {
if ( ! current_user_can( 'edit_user', $user_id ) ) {
return;
}
check_admin_referer( 'wp_otp_code', 'wp_otp_code' );
$user = get_userdata( $user_id );
$user_meta_data = Wp_Otp_User_Meta::get_instance();
......@@ -81,7 +81,7 @@ class Wp_Otp_Admin {
$otp = TOTP::create( $secret );
$otp->setLabel( $user->user_login );
$otp_code = $_POST['wp_otp_code'] ?? '';
$otp_code = sanitize_key( $_POST['wp_otp_code'] ?? '' );
if ( $otp_code && ! $user_meta_data->get( 'enabled', false ) ) {
/** Filter documented in class-wp-otp-public.php */
$otp_window = (int) apply_filters( 'wp_otp_code_expiration_window', 2 );
......@@ -124,13 +124,15 @@ class Wp_Otp_Admin {
* @since 0.1.0
*/
public function admin_init(): void {
if ( isset( $_GET['wp-otp-reconfigure'] ) && 'yes' === $_GET['wp-otp-reconfigure'] ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( 'yes' === ( sanitize_key( $_GET['wp-otp-reconfigure'] ?? '' ) ) ) {
Wp_Otp_User_Meta::clear();
wp_redirect( get_edit_profile_url() . '#wp_otp' );
wp_safe_redirect( get_edit_profile_url() . '#wp_otp' );
exit;
}
if ( isset( $_GET['wp-otp-new-recovery-codes'] ) && 'yes' === $_GET['wp-otp-new-recovery-codes'] ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( 'yes' === ( sanitize_key( $_GET['wp-otp-new-recovery-codes'] ?? '' ) ) ) {
$otp_recovery_codes = $this->get_random_recovery_codes();
Wp_Otp_User_Meta::get_instance()->set_all( [
'recovery_codes' => $otp_recovery_codes,
......@@ -145,7 +147,7 @@ class Wp_Otp_Admin {
],
], true );
wp_redirect( get_edit_profile_url() );
wp_safe_redirect( get_edit_profile_url() );
exit;
}
}
......@@ -161,7 +163,6 @@ class Wp_Otp_Admin {
* @param null|int $codes_length_override Override the filter and default for the codes length.
*
* @return array
* @throws \Exception
*/
public function get_random_recovery_codes( $codes_count_override = null, $codes_length_override = null ): array {
/**
......@@ -185,8 +186,9 @@ class Wp_Otp_Admin {
$codes_length = min( max( 8, $codes_length ), 64 );
$codes = [];
// phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found
while ( count( $codes ) < $codes_count ) {
$code = substr( bin2hex( random_bytes( 32 ) ), 0, $codes_length );
$code = $this->get_random_hash( $codes_length );
if ( ! array_key_exists( $code, $codes ) ) {
$codes[ $code ] = true;
}
......@@ -203,7 +205,6 @@ class Wp_Otp_Admin {
* @param null|int $secret_length_override Override the filter and default for the codes count.
*
* @return string
* @throws \Exception
*/
public function get_random_secret( $secret_length_override = null ): string {
/**
......@@ -216,7 +217,30 @@ class Wp_Otp_Admin {
$secret_length = $secret_length_override ?: (int) apply_filters( 'wp_otp_secret_length', 16 );
$secret_length = min( max( 8, $secret_length ), 64 );
return substr( Base32::encode( random_bytes( 42 ) ), 0, $secret_length );
return $this->get_random_hash( $secret_length );
}
/**
* Get a random hash string of up to 100 characters.
*
* @since Unreleased
*
* @param int $length Length of the random hash (max 100).
*
* @return string
*/
public function get_random_hash( $length = 0 ): string {
try {
$random_hash = Base32::encode( random_bytes( 64 ) );
} catch ( Throwable $e ) {
$random_hash = Base32::encode( md5( microtime( true ) ) . md5( microtime( true ) ) );
}
if ( $length <= 0 ) {
return substr( $random_hash, 0, 100 );
}
return substr( $random_hash, 0, min( $length, 100 ) );
}
/**
......@@ -224,9 +248,7 @@ class Wp_Otp_Admin {
*
* @since 0.1.0
*
* @param WP_User $user
*
* @throws \Exception
* @param WP_User $user WordPress User Object.
*/
public function user_profile_render( $user ): void {
$user_meta_data = Wp_Otp_User_Meta::get_instance();
......@@ -252,7 +274,6 @@ class Wp_Otp_Admin {
* @param string $qr_code_provisioning_uri
*/
$qr_code_provisioning_uri = apply_filters( 'wp_otp_qr_code_provisioning_uri', $qr_code_provisioning_uri_default );
$otp_qr_code_img_uri = $otp->getQrCodeUri( $qr_code_provisioning_uri, '{PROVISIONING_URI}' );
// If no custom provisioning URI is set, opt for internal QR code processing, if possible.
if ( $qr_code_provisioning_uri === $qr_code_provisioning_uri_default ) {
......@@ -261,11 +282,15 @@ class Wp_Otp_Admin {
$qr_code = new QRCode( $qr_code_options );
$otp_qr_code_raw_uri = $otp->getProvisioningUri();
$otp_qr_code_img_uri = $qr_code->render( $otp_qr_code_raw_uri );
} catch ( \Throwable $e ) {
// Silently fail and fall back to online provisioning.
} catch ( Throwable $e ) {
$otp_qr_code_img_uri = null;
}
}
if ( ! isset( $otp_qr_code_img_uri ) ) {
$otp_qr_code_img_uri = $otp->getQrCodeUri( $qr_code_provisioning_uri, '{PROVISIONING_URI}' );
}
$otp_enabled = $user_meta_data->get( 'enabled' );
$otp_apps = [
......@@ -339,7 +364,7 @@ class Wp_Otp_Admin {
$class = $classes[ array_key_exists( $type, $classes ) ? $type : 'notice' ];
?>
<div id="message" class="<?php echo esc_attr( $class ); ?>">
<p><?php echo implode( '<br>', $messages ); ?></p>
<p><?php echo implode( '<br>', $messages ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></p>
</div>
<?php
}
......@@ -354,24 +379,14 @@ class Wp_Otp_Admin {
public function admin_notices(): void {
$user_meta_data = Wp_Otp_User_Meta::get_instance();
/*if ( ! $user_meta_data->get( 'enabled' ) ) {
$this->show_user_notification( [
__( '<strong>Note:</strong> You have not configured WP-OTP yet.', 'wp-otp' ),
sprintf(
'<a href="%1$s#wp_otp" class="button">%2$s</a>',
get_edit_profile_url(),
_x( 'Configure now', 'Link text to go to WP-OTP section in user profile', 'wp-otp' )
),
] );
} else {*/
if ( $user_meta_data->get( 'enabled' ) ) {
$recovery_codes = array_filter( $user_meta_data->get( 'recovery_codes' ) );
$recovery_codes_count = count( $recovery_codes );
if ( $recovery_codes_count < 3 ) {
$this->show_user_notification( [
'<strong>' . __( 'Important', 'wp-otp' ) . '</strong>',
'<strong>' . esc_html__( 'Important', 'wp-otp' ) . '</strong>',
sprintf(
_n(
_n( // phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
'You have %d WP-OTP recovery code left. You should generate new ones.',
'You have %d WP-OTP recovery codes left. You should generate new ones.',
$recovery_codes_count,
......@@ -381,8 +396,8 @@ class Wp_Otp_Admin {
),
sprintf(
'<a href="%1$s" class="button">%2$s</a>',
add_query_arg( 'wp-otp-new-recovery-codes', 'yes', get_edit_profile_url() ),
_x( 'Regenerate', 'Link to regenerate the WP-OTP recovery codes', 'wp-otp' )
esc_url( add_query_arg( 'wp-otp-new-recovery-codes', 'yes', get_edit_profile_url() ) ),
esc_html_x( 'Regenerate', 'Link to regenerate the WP-OTP recovery codes', 'wp-otp' )
),
], 'error' );
}
......
.wp-otp-app-box {
display: inline-block;
margin: 8px 16px;
display: inline-block;
margin: 8px 16px;
}
.wp-otp-link-reconfigure,
.wp-otp-link-new-recovery-codes {
margin: 4px !important;
display: inline-block;
margin: 4px !important;
display: inline-block;
}
.wp-otp-recovery-codes-box del,
.wp-otp-recovery-codes-box span {
font-weight: normal;
display: block;
margin: 4px;
font-weight: normal;
display: block;
margin: 4px;
}
.wp-otp-recovery-codes-box del {
color: #800;
color: #800;
}
<?php // Silence is golden
<?php // Silence is golden
......@@ -2,76 +2,79 @@
/**
* Render the WP-OTP section in the user profile in WP Admin
*
* @since 0.1.0
* @package Wp_Otp
* @subpackage Admin
* @since 0.1.0
*/
?>
<a name="wp_otp"></a>
<h2><?php _e( 'Set up WP-OTP (WordPress One Time Password)', 'wp-otp' ); ?></h2>
<h2><?php esc_html_e( 'Set up WP-OTP (WordPress One Time Password)', 'wp-otp' ); ?></h2>
<table class="form-table">
<tr>
<th scope="row">
<?php echo __( 'OTP Secret', 'wp-otp' ) . ':<br>' . implode( ' ', str_split( $secret, 4 ) ) . '<br><br>'; ?>
<?php esc_html_e( 'OTP Secret', 'wp-otp' ); ?>:<br>
<?php echo esc_html( implode( ' ', str_split( $secret, 4 ) ) ); ?><br><br>
<?php if ( $otp_enabled ) : ?>
<?php
printf(
'<em>%1$s</em><br><a href="%2$s" class="button button-small wp-otp-link-reconfigure">%3$s</a>',
__( 'WP-OTP has been configured successfully.', 'wp-otp' ),
add_query_arg( 'wp-otp-reconfigure', 'yes' ),
_x( 'Reconfigure', 'Link to reset and reconfigure WP-OTP secret', 'wp-otp' )
esc_html__( 'WP-OTP has been configured successfully.', 'wp-otp' ),
esc_url( add_query_arg( 'wp-otp-reconfigure', 'yes' ) ),
esc_html_x( 'Reconfigure', 'Link to reset and reconfigure WP-OTP secret', 'wp-otp' )
);
?>
<br><br>
<div class="wp-otp-recovery-codes-box">
<?php _e( 'Recovery codes', 'wp-otp' ); ?>:<br>
<?php esc_html_e( 'Recovery codes', 'wp-otp' ); ?>:<br>
<?php
foreach ( $user_meta_data->get( 'recovery_codes' ) as $code => $unused ) {
printf( '<%1$s>%2$s</%1$s>', $unused ? 'span' : 'del', $code );
printf( '<%1$s>%2$s</%1$s>', $unused ? 'span' : 'del', $code ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
printf(
'<a href="%1$s" class="button button-small wp-otp-link-new-recovery-codes">%2$s</a>',
add_query_arg( 'wp-otp-new-recovery-codes', 'yes' ),
_x( 'Regenerate', 'Link to regenerate the WP-OTP recovery codes', 'wp-otp' )
esc_url( add_query_arg( 'wp-otp-new-recovery-codes', 'yes' ) ),
esc_html_x( 'Regenerate', 'Link to regenerate the WP-OTP recovery codes', 'wp-otp' )
);
?>
</div>
<?php else : ?>
<em><?php _e( 'To activate WP-OTP, enter the One Time Password from your authenticator app and save your profile.', 'wp-otp' ); ?></em><br><br>
<label for="wp_otp_code"><?php _e( 'One Time Password', 'wp-otp' ); ?></label><br>
<em><?php esc_html_e( 'To activate WP-OTP, enter the One Time Password from your authenticator app and save your profile.', 'wp-otp' ); ?></em><br><br>
<label for="wp_otp_code"><?php esc_html_e( 'One Time Password', 'wp-otp' ); ?></label><br>
<input type="text" size="25" name="wp_otp_code" id="wp_otp_code"/>
<?php wp_nonce_field( 'wp_otp_nonce', 'wp_otp_nonce' ); ?>
<?php endif; ?>
</th>
<td>
<img src="<?php echo $otp_qr_code_img_uri; ?>" alt="<?php _e( 'QR Code to scan with mobile app', 'wp-otp' ); ?>"/><br>
<img src="<?php echo esc_attr( $otp_qr_code_img_uri ); ?>" alt="<?php esc_attr_e( 'QR Code to scan with mobile app', 'wp-otp' ); ?>" style="background-color:#fff;"/><br>
</td>
<td>
<span class="description">
<?php _e( 'Download any OTP Authenticator app on your smart phone and scan the QR Code to activate WP-OTP.', 'wp-otp' ); ?>
<?php esc_html_e( 'Download any OTP Authenticator app on your smart phone and scan the QR Code to activate WP-OTP.', 'wp-otp' ); ?>
</span><br><br>
<?php foreach ( $otp_apps as $otp_app ) : ?>
<span class="wp-otp-app-box">
<?php $app_name = esc_attr( $otp_app['name'] ); ?>
<strong><?php echo $otp_app['name']; ?></strong><br>
<a href="<?php echo $otp_app['uri']; ?>" target="_blank">
<img src="<?php echo $otp_app['uri_logo']; ?>"
alt="<?php echo $app_name; ?>"
title="<?php echo $app_name; ?>"
<strong><?php echo esc_html( $otp_app['name'] ); ?></strong><br>
<a href="<?php echo esc_html( $otp_app['uri'] ); ?>" target="_blank">
<img src="<?php echo esc_url( $otp_app['uri_logo'] ); ?>"
alt="<?php echo esc_attr( $otp_app['name'] ); ?>"
title="<?php echo esc_attr( $otp_app['name'] ); ?>"
/></a>&nbsp;
<?php foreach ( $app_providers as $app_provider_key => $app_provider ) : ?>
<?php
if ( ! array_key_exists( 'uri_' . $app_provider_key, $otp_app ) ) {
continue;
}
$get_it_on_text = sprintf(
esc_attr__( 'Get it on %s', 'wp-otp' ),
$app_provider['name']
);
// translators: Placeholder is an app provider name.
$get_it_on_text = sprintf( esc_attr__( 'Get it on %s', 'wp-otp' ), $app_provider['name'] );
?>
<a href="<?php echo $otp_app[ 'uri_' . $app_provider_key ]; ?>" target="_blank">
<img src="<?php echo $app_provider['uri_logo']; ?>"
alt="<?php echo $get_it_on_text; ?>"
title="<?php echo $get_it_on_text; ?>"
<a href="<?php echo esc_url( $otp_app[ 'uri_' . $app_provider_key ] ); ?>" target="_blank">
<img src="<?php echo esc_url( $app_provider['uri_logo'] ); ?>"
alt="<?php echo esc_attr( $get_it_on_text ); ?>"
title="<?php echo esc_attr( $get_it_on_text ); ?>"
/></a>&nbsp;
<?php endforeach; ?>
</span>
......
......@@ -71,7 +71,7 @@ class Wp_Otp_Setup {
return;
}
$plugin = $_REQUEST['plugin'] ?? '';
$plugin = sanitize_key( $_REQUEST['plugin'] ?? '' );
check_admin_referer( "activate-plugin_{$plugin}" );
}
......@@ -89,7 +89,7 @@ class Wp_Otp_Setup {
return;
}
$plugin = $_REQUEST['plugin'] ?? '';
$plugin = sanitize_key( $_REQUEST['plugin'] ?? '' );
check_admin_referer( "deactivate-plugin_{$plugin}" );
}
......
......@@ -87,7 +87,7 @@ class Wp_Otp_User_Meta {
public static function get_instance( $user_id = 0 ): Wp_Otp_User_Meta {
if ( null === self::$instance ) {
self::$user_id = $user_id ?: get_current_user_id();
self::$instance = new self;
self::$instance = new self();
}
return self::$instance;
......@@ -126,10 +126,14 @@ class Wp_Otp_User_Meta {
if ( isset( self::$user_meta[ $key ] ) ) {
// Return found option value.
return self::$user_meta[ $key ];
} elseif ( null !== $default ) {
}
if ( null !== $default ) {
// Return overridden default value.
return $default;
} elseif ( isset( self::$default_user_meta[ $key ] ) ) {
}
if ( isset( self::$default_user_meta[ $key ] ) ) {
// Return default option value.
return self::$default_user_meta[ $key ];
}
......
<?php // Silence is golden
<?php // Silence is golden
<?xml version="1.0"?>
<ruleset name="WordPress Coding Standards">
<ruleset name="WordPress Coding Standards based custom ruleset for your plugin">
<description>Generally-applicable sniffs for WordPress plugins.</description>
<arg value="snp"/>
<arg name="colors"/>
<arg name="extensions" value="php"/>
<arg name="encoding" value="utf-8"/>
<arg name="parallel" value="8"/>
<arg name="report-width" value="150"/>
<!-- What to scan -->
<file>.</file>
<exclude-pattern>/tests/</exclude-pattern>
<exclude-pattern>/vendor/</exclude-pattern>
<file>.</file>
<!-- How to scan -->
<!-- Usage instructions: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage -->
<!-- Annotated ruleset: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
<arg value="sp"/> <!-- Show sniff and progress -->
<arg name="basepath" value="./"/><!-- Strip the file paths down to the relevant bit -->
<arg name="colors"/>
<arg name="extensions" value="php"/>
<arg name="parallel" value="8"/><!-- Enables parallel processing when available for faster results. -->
<!-- Exclude Composer vendor directory. -->
<exclude-pattern>*/vendor/*</exclude-pattern>
<!-- Rules: Check PHP version compatibility -->
<!-- https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions -->
<config name="testVersion" value="7.2-"/>
<!-- https://github.com/PHPCompatibility/PHPCompatibilityWP -->
<rule ref="PHPCompatibilityWP"/>
<rule ref="WordPress-Core">
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found"/>
<exclude name="WordPress.PHP.DisallowShortTernary.Found"/>
</rule>
<rule ref="Generic.Commenting.DocComment.MissingShort">
<!-- Temporarily disabled until https://github.com/WordPress/WordPress-Coding-Standards/issues/403 is fixed. -->
<severity>0</severity>
</rule>
<rule ref="PEAR.Functions.FunctionCallSignature">
<exclude name="PEAR.Functions.FunctionCallSignature.ContentAfterOpenBracket"/>
<exclude name="PEAR.Functions.FunctionCallSignature.CloseBracketLine"/>
<exclude name="PEAR.Functions.FunctionCallSignature.MultipleArguments"/>
</rule>
<!-- Rules: WordPress Coding Standards -->
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards -->
<!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties -->
<config name="minimum_supported_wp_version" value="4.6"/>
<rule ref="WordPress">
<exclude name="Generic.Arrays.DisallowShortArraySyntax.Found" />
<exclude name="PEAR.Functions.FunctionCallSignature.ContentAfterOpenBracket" />
<exclude name="PEAR.Functions.FunctionCallSignature.CloseBracketLine" />
<exclude name="PEAR.Functions.FunctionCallSignature.MultipleArguments" />
<exclude name="WordPress.PHP.DisallowShortTernary.Found" />
<exclude name="WordPress.WhiteSpace.PrecisionAlignment.Found" />
</rule>
<rule ref="WordPress.WP.I18n">
<properties>
<!-- Value: replace the text domain used. -->
<property name="text_domain" type="array" value="wp-otp"/>
</properties>
</rule>
<rule ref="WordPress.WhiteSpace.ControlStructureSpacing">
<properties>
<property name="blank_line_check" value="true"/>
</properties>
</rule>
</ruleset>
......@@ -12,6 +12,7 @@
namespace Wp_Otp;
use OTPHP\TOTP;
use OTPHP\TOTPInterface;
use WP_Error;
use WP_User;
......@@ -52,8 +53,8 @@ class Wp_Otp_Public {
);
?>
<p>
<label for="wp_otp_code"><?php echo $otp_text; ?></label><br/>
<?php '' !== $otp_text_sub && printf( '<em>%s</em>', $otp_text_sub ); ?>
<label for="wp_otp_code"><?php echo wp_kses_data( $otp_text ); ?></label><br/>
<?php '' !== $otp_text_sub && print wp_kses_data( sprintf( '<em>%s</em>', $otp_text_sub ) ); ?>
<input type="text" class="input" name="wp_otp_code" id="wp_otp_code"/>
</p>
<?php
......@@ -77,7 +78,10 @@ class Wp_Otp_Public {
if ( null === $otp ) {
return $user;
}
$otp_code = $_POST['wp_otp_code'] ?? '';
// We can safely ignore the PHPCS error here, as this gets handled by WP.
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$otp_code = sanitize_key( $_POST['wp_otp_code'] ?? '' );
// If this is a valid OTP code, all good!
if ( $this->verify_otp( $otp, $otp_code ) ) {
......@@ -137,8 +141,8 @@ class Wp_Otp_Public {
}
// First let's check for a valid OTP code input.
$otp_code = substr( $password, - 6 );
$tmp_pass = substr( $password, 0, - 6 );
$otp_code = substr( $password, -6 );
$tmp_pass = substr( $password, 0, -6 );
if ( wp_check_password( $tmp_pass, $user->user_pass, $user->ID ) && $this->verify_otp( $otp, $otp_code ) ) {
$password = $tmp_pass;
return;
......@@ -147,12 +151,12 @@ class Wp_Otp_Public {
// Then check if it's a recovery code.
$recovery_codes = $user_meta_data->get( 'recovery_codes' );
foreach ( array_keys( array_filter( $recovery_codes ) ) as $recovery_code ) {
$otp_code = substr( $password, - strlen( $recovery_code ) );
$otp_code = substr( $password, -strlen( $recovery_code ) );
if ( $otp_code !== $recovery_code ) {
continue;
}
$tmp_pass = substr( $password, 0, - strlen( $recovery_code ) );
$tmp_pass = substr( $password, 0, -strlen( $recovery_code ) );
if ( wp_check_password( $tmp_pass, $user->user_pass, $user->ID ) ) {
// Unset the recovery code that has just been used.
$recovery_codes[ $otp_code ] = false;
......@@ -168,11 +172,11 @@ class Wp_Otp_Public {
*
* @since 0.3.0
*
* @param Wp_Otp_User_Meta $user_meta_data
* @param Wp_Otp_User_Meta $user_meta_data Meta data object of the user.
*
* @return null|TOTP
* @return TOTPInterface|null
*/
private function get_otp_if_enabled( $user_meta_data ): ?TOTP {
private function get_otp_if_enabled( $user_meta_data ): ?TOTPInterface {
if ( $user_meta_data->get( 'enabled' ) && null !== $user_meta_data->get( 'secret' ) ) {
return TOTP::create( $user_meta_data->get( 'secret' ) );
}
......@@ -185,8 +189,8 @@ class Wp_Otp_Public {
*
* @since 0.3.0
*
* @param TOTP $otp
* @param string $otp_code
* @param TOTP $otp OTP object.
* @param string $otp_code OTP code to be verified.
*
* @return bool
*/
......
<?php // Silence is golden
......@@ -98,6 +98,7 @@ This means that you will need to add your OTP (or recovery) code at the end of y
* Require at least PHP 7.2.
* Update OTPHP to 10.0.
* Add native QR code rendering.
* Harden security by adhering to WordPress Code Sniffer.
= 0.4.1 =
* Fix nullable return type when checking if OTP is enabled.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment