diff --git a/providers/class-two-factor-backup-codes.php b/providers/class-two-factor-backup-codes.php index a2ed7a98..2a3345b4 100644 --- a/providers/class-two-factor-backup-codes.php +++ b/providers/class-two-factor-backup-codes.php @@ -214,6 +214,25 @@ public function user_options( $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 @@ public static function codes_remaining_for_user( $user ) { */ 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 ); + ?> -


+

- +

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 @@ public function user_token_ttl( $user_id ) { * 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 @@ public function authentication_page( $user ) { $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'; ?>

- +

diff --git a/readme.txt b/readme.txt index 8c2ff974..4fd95f27 100644 --- a/readme.txt +++ b/readme.txt @@ -27,7 +27,9 @@ Here is a list of action and filter hooks provided by the plugin: - `two_factor_providers` filter overrides the available two-factor providers such as email and time-based one-time passwords. Array values are PHP classnames of the two-factor providers. - `two_factor_enabled_providers_for_user` filter overrides the list of two-factor providers enabled for a user. First argument is an array of enabled provider classnames as values, the second argument is the user ID. - `two_factor_user_authenticated` action which receives the logged in `WP_User` object as the first argument for determining the logged in user right after the authentication workflow. -- `two_factor_token_ttl` filter overrides the time interval in seconds that an email token is considered after generation. Accepts the time in seconds as the first argument and the ID of the `WP_User` object being authenticated. +- `two_factor_email_token_ttl` filter overrides the time interval in seconds that an email token is considered after generation. Accepts the time in seconds as the first argument and the ID of the `WP_User` object being authenticated. +- `two_factor_email_token_length` filter overrides the default 8 character count for email tokens. +- `two_factor_backup_code_length` filter overrides the default 8 character count for backup codes. Providers the `WP_User` of the associated user as the second argument. == Frequently Asked Questions == diff --git a/tests/providers/class-two-factor-backup-codes.php b/tests/providers/class-two-factor-backup-codes.php index a926044e..fb134b60 100644 --- a/tests/providers/class-two-factor-backup-codes.php +++ b/tests/providers/class-two-factor-backup-codes.php @@ -194,4 +194,25 @@ public function test_delete_code() { $this->provider->delete_code( $user, $backup_codes[0] ); $this->assertEquals( 1, $this->provider->codes_remaining_for_user( $user ) ); } + + public function test_backup_code_length_filter() { + $user = new WP_User( self::factory()->user->create() ); + + $code_default = $this->provider->generate_codes( $user, array( 'number' => 1 ) ); + + add_filter( + 'two_factor_backup_code_length', + function() { + return 7; + } + ); + + $code_custom_length = $this->provider->generate_codes( $user, array( 'number' => 1 ) ); + + $this->assertNotEquals( strlen( $code_custom_length[0] ), strlen( $code_default[0] ), 'Backup code length can be adjusted via filter' ); + + $this->assertEquals( 7, strlen( $code_custom_length[0] ), 'Backup code length matches the filtered length' ); + + remove_all_filters( 'two_factor_backup_code_length' ); + } } diff --git a/tests/providers/class-two-factor-email.php b/tests/providers/class-two-factor-email.php index 93e5dc76..bfcfb681 100644 --- a/tests/providers/class-two-factor-email.php +++ b/tests/providers/class-two-factor-email.php @@ -352,4 +352,67 @@ public function test_tokens_can_expire() { ); } + public function test_custom_token_length() { + $user_id = self::factory()->user->create(); + + $default_token = $this->provider->generate_token( $user_id ); + + add_filter( + 'two_factor_email_token_length', + function() { + return 15; + } + ); + + $custom_token = $this->provider->generate_token( $user_id ); + + $this->assertNotEquals( strlen( $default_token ), strlen( $custom_token ), 'Token length is different due to filter' ); + $this->assertEquals( 15, strlen( $custom_token ), 'Token length matches the filter value' ); + + remove_all_filters( 'two_factor_email_token_length' ); + } + + /** + * Test the email token TTL. + * + * @expectedDeprecated two_factor_token_ttl + */ + public function test_email_token_ttl() { + $this->assertEquals( + 15 * MINUTE_IN_SECONDS, + $this->provider->user_token_ttl( 123 ), + 'The email token matches the default TTL' + ); + + add_filter( + 'two_factor_email_token_ttl', + function() { + return 42; + } + ); + + $this->assertEquals( + 42, + $this->provider->user_token_ttl( 123 ), + 'The email token ttl can be filtered' + ); + + remove_all_filters( 'two_factor_email_token_ttl' ); + + add_filter( + 'two_factor_token_ttl', + function() { + return 66; + } + ); + + $this->assertEquals( + 66, + $this->provider->user_token_ttl( 123 ), + 'The email token matches can be filtered with the deprecated filter' + ); + + remove_all_filters( 'two_factor_token_ttl' ); + } + }