diff --git a/providers/class-two-factor-backup-codes.php b/providers/class-two-factor-backup-codes.php index d74592b3..2f5e1d84 100644 --- a/providers/class-two-factor-backup-codes.php +++ b/providers/class-two-factor-backup-codes.php @@ -317,7 +317,8 @@ public function generate_codes( $user, $args = array() ) { // Append or replace (default). if ( isset( $args['method'] ) && 'append' === $args['method'] ) { - $codes_hashed = (array) get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true ); + $existing = get_user_meta( $user->ID, self::BACKUP_CODES_META_KEY, true ); + $codes_hashed = is_array( $existing ) ? $existing : array(); } $code_length = $this->get_backup_code_length( $user ); diff --git a/tests/providers/class-two-factor-backup-codes.php b/tests/providers/class-two-factor-backup-codes.php index 0d6041ab..4aa9f825 100644 --- a/tests/providers/class-two-factor-backup-codes.php +++ b/tests/providers/class-two-factor-backup-codes.php @@ -201,6 +201,33 @@ public function test_delete_code() { $this->assertEquals( 1, $this->provider->codes_remaining_for_user( $user ) ); } + /** + * Verify appending codes for a user with no existing codes does not store an empty entry. + * + * @covers Two_Factor_Backup_Codes::generate_codes + * @covers Two_Factor_Backup_Codes::codes_remaining_for_user + */ + public function test_generate_codes_append_with_no_existing_codes() { + $user = new WP_User( self::factory()->user->create() ); + + $codes = $this->provider->generate_codes( + $user, + array( + 'number' => Two_Factor_Backup_Codes::NUMBER_OF_CODES, + 'method' => 'append', + ) + ); + + $this->assertCount( Two_Factor_Backup_Codes::NUMBER_OF_CODES, $codes ); + + $backup_codes = get_user_meta( $user->ID, Two_Factor_Backup_Codes::BACKUP_CODES_META_KEY, true ); + + $this->assertIsArray( $backup_codes ); + $this->assertCount( Two_Factor_Backup_Codes::NUMBER_OF_CODES, $backup_codes ); + $this->assertNotContains( '', $backup_codes ); + $this->assertEquals( Two_Factor_Backup_Codes::NUMBER_OF_CODES, $this->provider->codes_remaining_for_user( $user ) ); + } + /** * Test backup code length filter. */