Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add filters for email token and backup code length #653

Merged
merged 17 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 6 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
10 changes: 9 additions & 1 deletion providers/class-two-factor-backup-codes.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,16 @@ public function generate_codes( $user, $args = '' ) {
$codes_hashed = (array) get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true );
}

/**
* 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 );

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 );
Expand Down
17 changes: 15 additions & 2 deletions providers/class-two-factor-email.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ public function get_alternative_provider_label() {
* @return string
*/
public function generate_token( $user_id ) {
$token = $this->get_code();
$token_length = (int) apply_filters( 'two_factor_email_token_length', 8 );

$token = $this->get_code( $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 ) );
Expand Down Expand Up @@ -142,14 +144,25 @@ public function user_token_lifetime( $user_id ) {
public function user_token_ttl( $user_id ) {
$token_ttl = 15 * MINUTE_IN_SECONDS;

/**
* 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.
*/
$token_ttl = (int) apply_filters_deprecated( 'two_factor_token_ttl', array( $token_ttl, $user_id ), '0.7.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_token_ttl', $token_ttl, $user_id );
return (int) apply_filters( 'two_factor_email_token_ttl', $token_ttl, $user_id );
}

/**
Expand Down
4 changes: 3 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ==

Expand Down
21 changes: 21 additions & 0 deletions tests/providers/class-two-factor-backup-codes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
}
}
20 changes: 20 additions & 0 deletions tests/providers/class-two-factor-email.php
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,24 @@ 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' );
}

}
Loading