0, 'refresh_tokens_migrated' => 0, 'access_tokens_skipped' => 0, 'refresh_tokens_skipped' => 0, 'errors' => array(), ); // Migrate access tokens. if ( ! empty( $oauth_data['access_tokens'] ) ) { foreach ( $oauth_data['access_tokens'] as &$token_data ) { if ( ! isset( $token_data['access_token'] ) ) { continue; } // Skip if already encrypted. if ( self::is_encrypted( $token_data['access_token'] ) ) { ++$stats['access_tokens_skipped']; continue; } // Encrypt the token. $encrypted = self::encrypt( $token_data['access_token'] ); if ( is_wp_error( $encrypted ) ) { $stats['errors'][] = 'Access token encryption failed: ' . $encrypted->get_error_message(); continue; } $token_data['access_token'] = $encrypted; ++$stats['access_tokens_migrated']; } } // Migrate refresh tokens. if ( ! empty( $oauth_data['refresh_tokens'] ) ) { foreach ( $oauth_data['refresh_tokens'] as &$token_data ) { if ( ! isset( $token_data['refresh_token'] ) ) { continue; } // Skip if already encrypted. if ( self::is_encrypted( $token_data['refresh_token'] ) ) { ++$stats['refresh_tokens_skipped']; continue; } // Encrypt the token. $encrypted = self::encrypt( $token_data['refresh_token'] ); if ( is_wp_error( $encrypted ) ) { $stats['errors'][] = 'Refresh token encryption failed: ' . $encrypted->get_error_message(); continue; } $token_data['refresh_token'] = $encrypted; ++$stats['refresh_tokens_migrated']; } } // Save updated data if any tokens were migrated. if ( $stats['access_tokens_migrated'] > 0 || $stats['refresh_tokens_migrated'] > 0 ) { update_option( Abilities_Bridge_OAuth_Client_Manager::OPTION_NAME, $oauth_data ); } return $stats; } /** * Test encryption and decryption functionality * * Performs self-test to verify encryption is working correctly. * * @return array Test results */ public static function test_encryption() { $results = array( 'success' => true, 'tests' => array(), ); // Test 1: Basic encryption/decryption. $test_token = 'test_token_' . wp_generate_password( 32, true, true ); $encrypted = self::encrypt( $test_token ); if ( is_wp_error( $encrypted ) ) { $results['success'] = false; $results['tests']['basic_encryption'] = array( 'passed' => false, 'error' => $encrypted->get_error_message(), ); } else { $decrypted = self::decrypt( $encrypted ); if ( is_wp_error( $decrypted ) ) { $results['success'] = false; $results['tests']['basic_encryption'] = array( 'passed' => false, 'error' => $decrypted->get_error_message(), ); } else { $passed = hash_equals( $test_token, $decrypted ); $results['tests']['basic_encryption'] = array( 'passed' => $passed, 'original_length' => strlen( $test_token ), 'encrypted_length' => strlen( $encrypted ), 'decrypted_match' => $passed, ); if ( ! $passed ) { $results['success'] = false; } } } // Test 2: Unique IV per encryption. $encrypted1 = self::encrypt( $test_token ); $encrypted2 = self::encrypt( $test_token ); $results['tests']['unique_iv'] = array( 'passed' => ! is_wp_error( $encrypted1 ) && ! is_wp_error( $encrypted2 ) && $encrypted1 !== $encrypted2, 'encrypted1_length' => is_string( $encrypted1 ) ? strlen( $encrypted1 ) : 0, 'encrypted2_length' => is_string( $encrypted2 ) ? strlen( $encrypted2 ) : 0, 'different' => ! is_wp_error( $encrypted1 ) && ! is_wp_error( $encrypted2 ) && $encrypted1 !== $encrypted2, ); if ( ! $results['tests']['unique_iv']['passed'] ) { $results['success'] = false; } // Test 3: Version prefix. if ( ! is_wp_error( $encrypted ) ) { $has_prefix = strpos( $encrypted, self::VERSION ) === 0; $results['tests']['version_prefix'] = array( 'passed' => $has_prefix, 'prefix' => self::VERSION, 'has_prefix' => $has_prefix, ); if ( ! $has_prefix ) { $results['success'] = false; } } // Test 4: Backward compatibility (plaintext tokens). $plaintext_token = 'plaintext_legacy_token_12345'; $decrypted_plaintext = self::decrypt( $plaintext_token ); $results['tests']['backward_compatibility'] = array( 'passed' => ! is_wp_error( $decrypted_plaintext ) && hash_equals( $plaintext_token, $decrypted_plaintext ), 'plaintext_preserved' => ! is_wp_error( $decrypted_plaintext ) && $decrypted_plaintext === $plaintext_token, ); if ( ! $results['tests']['backward_compatibility']['passed'] ) { $results['success'] = false; } // Test 5: Key derivation. $key = self::get_encryption_key(); $results['tests']['key_derivation'] = array( 'passed' => ! is_wp_error( $key ) && strlen( $key ) === 32, 'key_length' => is_string( $key ) ? strlen( $key ) : 0, 'expected_length' => 32, ); if ( ! $results['tests']['key_derivation']['passed'] ) { $results['success'] = false; } return $results; } }