From 253a823c9aa029794260bb4d211c90a9d49b1828 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:20:00 +0300 Subject: [PATCH 01/31] Introduce a matching disable provider for user method --- class-two-factor-core.php | 47 ++++++++++++++------------------------- 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 99033a70..cf5945e8 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -1889,30 +1889,18 @@ public static function user_two_factor_options( $user ) { * @return bool True if the provider was enabled, false otherwise. */ public static function enable_provider_for_user( $user_id, $new_provider ) { - $available_providers = self::get_providers(); + $enabled_providers = self::get_enabled_providers_for_user( $user_id ); - if ( ! array_key_exists( $new_provider, $available_providers ) ) { - return false; + if ( ! in_array( $new_provider, $enabled_providers ) ) { + $enabled_providers[] = $new_provider; } - $user = get_userdata( $user_id ); - $enabled_providers = self::get_enabled_providers_for_user( $user ); - - if ( in_array( $new_provider, $enabled_providers ) ) { - return true; + // Add as primary if none set. + if ( ! self::get_primary_provider_for_user( $user_id ) ) { + update_user_meta( $user_id, self::PROVIDER_USER_META_KEY, $new_provider ); } - $enabled_providers[] = $new_provider; - $enabled = update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $enabled_providers ); - - // Primary provider must be enabled. - $has_primary = is_object( self::get_primary_provider_for_user( $user_id ) ); - - if ( ! $has_primary ) { - $has_primary = update_user_meta( $user_id, self::PROVIDER_USER_META_KEY, $new_provider ); - } - - return $enabled && $has_primary; + return (bool) update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $enabled_providers ); } /** @@ -1929,23 +1917,22 @@ public static function enable_provider_for_user( $user_id, $new_provider ) { * @return bool True if the provider was disabled, false otherwise. */ public static function disable_provider_for_user( $user_id, $provider_to_delete ) { - $is_registered = array_key_exists( $provider_to_delete, self::get_providers() ); + $enabled_providers = self::get_enabled_providers_for_user( $user_id ); - if ( ! $is_registered ) { - return false; + // Check if this is disabled already. + if ( ! in_array( $provider_to_delete, $enabled_providers ) ) { + return true; } - $old_enabled_providers = self::get_enabled_providers_for_user( $user_id ); - $is_enabled = in_array( $provider_to_delete, $old_enabled_providers ); + $enabled_providers = array_diff( $enabled_providers, array( $provider_to_delete ) ); - if ( ! $is_enabled ) { - return true; + // Remove this from being a primary provider, if set. + $primary_provider = self::get_primary_provider_for_user( $user_id ); + if ( $primary_provider && $primary_provider->get_key() === $provider_to_delete ) { + delete_user_meta( $user_id, self::PROVIDER_USER_META_KEY ); } - $new_enabled_providers = array_diff( $old_enabled_providers, array( $provider_to_delete ) ); - $was_disabled = update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $new_enabled_providers ); - - return (bool) $was_disabled; + return (bool) update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $enabled_providers ); } /** From 7f05a5dab7669456d8bc247326d4da6a051086e4 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:20:18 +0300 Subject: [PATCH 02/31] Account for primary being disabled --- class-two-factor-core.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index cf5945e8..8ec4aaf0 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -1793,9 +1793,13 @@ public static function user_two_factor_options( $user ) { $enabled_providers = array_keys( self::get_available_providers_for_user( $user ) ); $primary_provider = self::get_primary_provider_for_user( $user->ID ); - if ( ! empty( $primary_provider ) && is_object( $primary_provider ) ) { + $primary_provider_key = null; + if ( is_object( $primary_provider ) ) { $primary_provider_key = $primary_provider->get_key(); - } else { + } + + // Reset the primary if it isn't set to one of the enabled providers. + if ( ! in_array( $primary_provider_key, $enabled_providers ) ) { $primary_provider_key = null; } From 4031d4d9d9162d764fc252e0680b7584e99a911e Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:20:38 +0300 Subject: [PATCH 03/31] Enable by default --- providers/class-two-factor-totp.php | 1 + 1 file changed, 1 insertion(+) diff --git a/providers/class-two-factor-totp.php b/providers/class-two-factor-totp.php index 7bafe1a1..4229e82d 100644 --- a/providers/class-two-factor-totp.php +++ b/providers/class-two-factor-totp.php @@ -368,6 +368,7 @@ public function user_two_factor_options( $user ) { user_id: ID ); ?>, key: key, code: code, + enable_provider: true, } } ).fail( function( response, status ) { var errorMessage = response.responseJSON.message || status, From edf24d2d4eb417e6ed3383b70a781f43e5022350 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:20:48 +0300 Subject: [PATCH 04/31] Disable on deactivate --- providers/class-two-factor-totp.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/providers/class-two-factor-totp.php b/providers/class-two-factor-totp.php index 4229e82d..99786bd3 100644 --- a/providers/class-two-factor-totp.php +++ b/providers/class-two-factor-totp.php @@ -151,6 +151,10 @@ public function rest_delete_totp( $request ) { $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(); From d86f234a3aceb7998ce07daf524622717d2836f9 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:50:00 +0300 Subject: [PATCH 05/31] Describe tests to quickly identify failing tests --- tests/class-two-factor-core.php | 36 ++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/class-two-factor-core.php b/tests/class-two-factor-core.php index 5f6a15a2..c1d06b72 100644 --- a/tests/class-two-factor-core.php +++ b/tests/class-two-factor-core.php @@ -818,52 +818,52 @@ public function test_show_password_reset_error() { public function test_enable_disable_provider_for_user() { $user = self::factory()->user->create_and_get(); $enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user->ID ); - $this->assertEmpty( $enabled_providers ); + $this->assertEmpty( $enabled_providers, 'No providers are enabled by default' ); // Disabling one that's already disabled should succeed. $totp_disabled = Two_Factor_Core::disable_provider_for_user( $user->ID, 'Two_Factor_Totp' ); - $this->assertTrue( $totp_disabled ); + $this->assertTrue( $totp_disabled, 'Disabling something that wasn\'t enabled should succeed' ); // Disabling one that doesn't exist should fail. $nonexistent_enabled = Two_Factor_Core::enable_provider_for_user( $user->ID, 'Nonexistent_Provider' ); $enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user->ID ); - $this->assertFalse( $nonexistent_enabled ); - $this->assertEmpty( $enabled_providers ); - $this->assertNull( Two_Factor_Core::get_primary_provider_for_user( $user->ID ) ); + $this->assertFalse( $nonexistent_enabled, 'Nonexistent shouldn\'t be allowed to be enabled' ); + $this->assertEmpty( $enabled_providers, 'Nonexistent wasn\'t enabled' ); + $this->assertNull( Two_Factor_Core::get_primary_provider_for_user( $user->ID ), 'Nonexistent wasn\'t set as primary' ); // Enabling a valid one should succeed. The first one that's enabled and configured should be the default primary. $totp = Two_Factor_Totp::get_instance(); $totp->set_user_totp_key( $user->ID, 'foo' ); $totp_enabled = Two_Factor_Core::enable_provider_for_user( $user->ID, 'Two_Factor_Totp' ); $enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user->ID ); - $this->assertTrue( $totp_enabled ); - $this->assertSame( array( 'Two_Factor_Totp' ), $enabled_providers ); - $this->assertSame( 'Two_Factor_Totp', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key() ); + $this->assertTrue( $totp_enabled, 'Can enable a valid provider' ); + $this->assertSame( array( 'Two_Factor_Totp' ), $enabled_providers, 'Enabled provider is now listed as enabled' ); + $this->assertSame( 'Two_Factor_Totp', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key(), 'Primary is now the only enabled provider' ); // Enabling one that's already enabled should succeed. $totp_enabled = Two_Factor_Core::enable_provider_for_user( $user->ID, 'Two_Factor_Totp' ); - $this->assertTrue( $totp_enabled ); + $this->assertTrue( $totp_enabled, 'Can enable a provider that is already enabled' ); // Enabling another should succeed, and not change the primary. $dummy_enabled = Two_Factor_Core::enable_provider_for_user( $user->ID, 'Two_Factor_Dummy' ); $enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user->ID ); - $this->assertTrue( $dummy_enabled ); - $this->assertSame( array( 'Two_Factor_Totp', 'Two_Factor_Dummy' ), $enabled_providers ); - $this->assertSame( 'Two_Factor_Totp', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key() ); + $this->assertTrue( $dummy_enabled, 'Can enable valid provider' ); + $this->assertSame( array( 'Two_Factor_Totp', 'Two_Factor_Dummy' ), $enabled_providers, 'Multiple can be enabled at the same time' ); + $this->assertSame( 'Two_Factor_Totp', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key(), 'The primary not changed upon additional providers being enabled' ); // Disabling one that doesn't exist should fail. $nonexistent_disabled = Two_Factor_Core::disable_provider_for_user( $user->ID, 'Nonexistent_Provider' ); $enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user->ID ); - $this->assertFalse( $nonexistent_disabled ); - $this->assertSame( array( 'Two_Factor_Totp', 'Two_Factor_Dummy' ), $enabled_providers ); - $this->assertSame( 'Two_Factor_Totp', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key() ); + $this->assertFalse( $nonexistent_disabled, 'Unavailable provider can\'t be disabled' ); + $this->assertSame( array( 'Two_Factor_Totp', 'Two_Factor_Dummy' ), $enabled_providers, 'Unavailable wasn\'t added to the list of enabled proviers' ); + $this->assertSame( 'Two_Factor_Totp', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key(), 'The primary is still the same after unavailable disable attempt' ); // Disabling one that's enabled should succeed, and change the primary to the next available one. $totp_disabled = Two_Factor_Core::disable_provider_for_user( $user->ID, 'Two_Factor_Totp' ); $enabled_providers = Two_Factor_Core::get_enabled_providers_for_user( $user->ID ); - $this->assertTrue( $totp_disabled ); //todo enable and fix - $this->assertSame( array( 1 => 'Two_Factor_Dummy' ), $enabled_providers ); - $this->assertSame( 'Two_Factor_Dummy', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key() ); + $this->assertTrue( $totp_disabled, 'Can disable a provider that is enabled' ); + $this->assertSame( array( 1 => 'Two_Factor_Dummy' ), $enabled_providers, 'The other providers are kept enabled' ); + $this->assertSame( 'Two_Factor_Dummy', Two_Factor_Core::get_primary_provider_for_user( $user->ID )->get_key(), 'Primary is updated to the first available' ); } /** From 64c0fce35c4659d8c769a4126ed2a7250d9f2fca Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:50:11 +0300 Subject: [PATCH 06/31] Maintain the previous logic --- class-two-factor-core.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 8ec4aaf0..398bb25f 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -1893,12 +1893,19 @@ public static function user_two_factor_options( $user ) { * @return bool True if the provider was enabled, false otherwise. */ public static function enable_provider_for_user( $user_id, $new_provider ) { + if ( ! in_array( $new_provider, self::get_providers_classes(), true ) ) { + return false; + } + $enabled_providers = self::get_enabled_providers_for_user( $user_id ); - if ( ! in_array( $new_provider, $enabled_providers ) ) { - $enabled_providers[] = $new_provider; + // Check if this is enabled already. + if ( in_array( $new_provider, $enabled_providers ) ) { + return true; } + $enabled_providers[] = $new_provider; + // Add as primary if none set. if ( ! self::get_primary_provider_for_user( $user_id ) ) { update_user_meta( $user_id, self::PROVIDER_USER_META_KEY, $new_provider ); @@ -1921,6 +1928,11 @@ public static function enable_provider_for_user( $user_id, $new_provider ) { * @return bool True if the provider was disabled, false otherwise. */ public static function disable_provider_for_user( $user_id, $provider_to_delete ) { + // Check if the provider is even enabled. + if ( ! in_array( $provider_to_delete, self::get_providers_classes(), true ) ) { + return false; + } + $enabled_providers = self::get_enabled_providers_for_user( $user_id ); // Check if this is disabled already. From faf80cb132fbeb9ed10cdc31e9a86018ceb9dba0 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 14:53:48 +0300 Subject: [PATCH 07/31] =?UTF-8?q?Don=E2=80=99t=20deal=20with=20setting=20t?= =?UTF-8?q?he=20primary?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- class-two-factor-core.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 398bb25f..eb5b2149 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -1906,11 +1906,6 @@ public static function enable_provider_for_user( $user_id, $new_provider ) { $enabled_providers[] = $new_provider; - // Add as primary if none set. - if ( ! self::get_primary_provider_for_user( $user_id ) ) { - update_user_meta( $user_id, self::PROVIDER_USER_META_KEY, $new_provider ); - } - return (bool) update_user_meta( $user_id, self::ENABLED_PROVIDERS_USER_META_KEY, $enabled_providers ); } From a8a6c4aabbb169d0a716410f7bca5bfda022d11f Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 15:17:37 +0300 Subject: [PATCH 08/31] Toggle the checkbox outside of the control panel --- providers/class-two-factor-totp.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/providers/class-two-factor-totp.php b/providers/class-two-factor-totp.php index 99786bd3..74f0f2e6 100644 --- a/providers/class-two-factor-totp.php +++ b/providers/class-two-factor-totp.php @@ -384,8 +384,10 @@ public function user_two_factor_options( $user ) { $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 ); } ); } ); @@ -412,6 +414,7 @@ public function user_two_factor_options( $user ) { user_id: ID ); ?>, } } ).then( function( response ) { + $( '#enabled-Two_Factor_Totp' ).prop( 'checked', false ); $( '#two-factor-totp-options' ).html( response.html ); } ); } ); From a5b22146ed56108f18b44d5c58cc4fd19690b404 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 15:26:35 +0300 Subject: [PATCH 09/31] get_primary_provider_for_user() already ensures that primary is always one of the enabled options --- class-two-factor-core.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index eb5b2149..9f143e35 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -1246,6 +1246,8 @@ public static function current_user_can_update_two_factor_options( $context = 'd return false; } + return true; + // If the current user is not using two-factor, they can adjust the settings. if ( ! self::is_user_using_two_factor( $user_id ) ) { return true; @@ -1794,15 +1796,10 @@ public static function user_two_factor_options( $user ) { $primary_provider = self::get_primary_provider_for_user( $user->ID ); $primary_provider_key = null; - if ( is_object( $primary_provider ) ) { + if ( ! empty( $primary_provider ) && is_object( $primary_provider ) ) { $primary_provider_key = $primary_provider->get_key(); } - // Reset the primary if it isn't set to one of the enabled providers. - if ( ! in_array( $primary_provider_key, $enabled_providers ) ) { - $primary_provider_key = null; - } - // This is specific to the current session, not the displayed user. $show_2fa_options = self::current_user_can_update_two_factor_options(); From ba5750d31b68a6a3e66cc051fb509d62961862c2 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Thu, 19 Sep 2024 15:27:06 +0300 Subject: [PATCH 10/31] Remove debug logic --- class-two-factor-core.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/class-two-factor-core.php b/class-two-factor-core.php index 9f143e35..bf37eaef 100644 --- a/class-two-factor-core.php +++ b/class-two-factor-core.php @@ -1246,8 +1246,6 @@ public static function current_user_can_update_two_factor_options( $context = 'd return false; } - return true; - // If the current user is not using two-factor, they can adjust the settings. if ( ! self::is_user_using_two_factor( $user_id ) ) { return true; From e6c3ea1c1db9e6d13b9b7a73a1ed918a526da2a7 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Mon, 2 Dec 2024 15:28:59 +0200 Subject: [PATCH 11/31] Allow filtering the email token length --- providers/class-two-factor-email.php | 4 +++- readme.txt | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/providers/class-two-factor-email.php b/providers/class-two-factor-email.php index da7a7c60..a3d86b43 100644 --- a/providers/class-two-factor-email.php +++ b/providers/class-two-factor-email.php @@ -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_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 ) ); diff --git a/readme.txt b/readme.txt index 8c2ff974..07cd5777 100644 --- a/readme.txt +++ b/readme.txt @@ -28,6 +28,7 @@ Here is a list of action and filter hooks provided by the plugin: - `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_token_length` filter overrides the default 8 character count for email tokens. == Frequently Asked Questions == From 1b103109da01b2f315f9b2355c53477461f15edd Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Mon, 2 Dec 2024 15:29:12 +0200 Subject: [PATCH 12/31] Allow filtering the backup code length --- providers/class-two-factor-backup-codes.php | 10 +++++++++- readme.txt | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/providers/class-two-factor-backup-codes.php b/providers/class-two-factor-backup-codes.php index 12601d5c..89389238 100644 --- a/providers/class-two-factor-backup-codes.php +++ b/providers/class-two-factor-backup-codes.php @@ -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 ); diff --git a/readme.txt b/readme.txt index 07cd5777..d0853539 100644 --- a/readme.txt +++ b/readme.txt @@ -29,6 +29,7 @@ Here is a list of action and filter hooks provided by the plugin: - `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_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 == From bbcd0415f9b517d753520ed918d982b068332f72 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Mon, 2 Dec 2024 15:40:57 +0200 Subject: [PATCH 13/31] Add tests for the backup code length filter --- .../class-two-factor-backup-codes.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) 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' ); + } } From 61a74896b7ec5ebb1a207df104c01e78ee19d801 Mon Sep 17 00:00:00 2001 From: Kaspars Dambis Date: Mon, 2 Dec 2024 15:45:16 +0200 Subject: [PATCH 14/31] Add tests for email token length too --- tests/providers/class-two-factor-email.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tests/providers/class-two-factor-email.php b/tests/providers/class-two-factor-email.php index 93e5dc76..0b5a154c 100644 --- a/tests/providers/class-two-factor-email.php +++ b/tests/providers/class-two-factor-email.php @@ -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_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_token_length' ); + } + } From 6a9a1336c141a851e108f249417ccb8baebaabd9 Mon Sep 17 00:00:00 2001 From: Stefan Momm Date: Mon, 6 Jan 2025 18:07:03 +0100 Subject: [PATCH 15/31] Disable input autocompletion --- providers/class-two-factor-backup-codes.php | 2 +- providers/class-two-factor-email.php | 2 +- providers/class-two-factor-totp.php | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/providers/class-two-factor-backup-codes.php b/providers/class-two-factor-backup-codes.php index 12601d5c..3597d80b 100644 --- a/providers/class-two-factor-backup-codes.php +++ b/providers/class-two-factor-backup-codes.php @@ -330,7 +330,7 @@ public function authentication_page( $user ) {


- +

- +

diff --git a/providers/class-two-factor-totp.php b/providers/class-two-factor-totp.php index 003a9774..9d44b67b 100644 --- a/providers/class-two-factor-totp.php +++ b/providers/class-two-factor-totp.php @@ -349,7 +349,7 @@ public function user_two_factor_options( $user ) { /* translators: Example auth code. */ $placeholder = sprintf( __( 'eg. %s', 'two-factor' ), '123456' ); ?> - +

@@ -682,7 +682,7 @@ public function authentication_page( $user ) {

- +