From a844294a0285c0074babf205c67090194d0ce9bc Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Mon, 5 Jul 2021 15:36:22 +0100 Subject: [PATCH 01/24] Fix mcrypt fatal on data encryption --- includes/push-syndicate-encryption.php | 68 +++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/includes/push-syndicate-encryption.php b/includes/push-syndicate-encryption.php index c68faaa8..607b6410 100644 --- a/includes/push-syndicate-encryption.php +++ b/includes/push-syndicate-encryption.php @@ -1,18 +1,72 @@ $cipher, + 'iv' => substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ), + 'key' => md5( PUSH_SYNDICATE_KEY ), + ); + } + + return false; // @TODO: return another default cipher? return exception? +} + function push_syndicate_encrypt( $data ) { + // @todo: replace mcrypt with openssl. problem: Rijndael AES is not available on openssl;s AES-256. + // Will most likely break backwards compatibility with older keys + // https://stackoverflow.com/questions/49997338/mcrypt-rijndael-256-to-openssl-aes-256-ecb-conversion + + // Backwards compatibility with PHP < 7.2. + if ( function_exists( 'mcrypt_encrypt' ) ) { + // @codingStandardsIgnoreStart + $data = serialize( $data ); + return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), $data, MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY)))); + // @codingStandardsIgnoreEnd + } + + $data = wp_json_encode( $data ); + $cipher = push_syndicate_get_cipher(); - $data = serialize( $data ); - return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), $data, MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY)))); + if ( ! $cipher ) { + return $data; + } + + $encrypted_data = openssl_encrypt( $data, $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); + return base64_encode( $encrypted_data ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode } function push_syndicate_decrypt( $data ) { - $data = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), base64_decode($data), MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY))), "\0"); - if ( !$data ) - return false; + // Backwards compatibility with PHP < 7.2. + if ( function_exists( 'mcrypt_encrypt' ) ) { + // @codingStandardsIgnoreStart + $data = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, md5( PUSH_SYNDICATE_KEY ), base64_decode( $data ), MCRYPT_MODE_CBC, md5( md5( PUSH_SYNDICATE_KEY ) ) ), "\0" ); + if ( ! $data ) { + return false; + } + return @unserialize( $data ); + // @codingStandardsIgnoreEnd + } + + $cipher = push_syndicate_get_cipher(); + + if ( ! $cipher ) { + return $data; + } - return @unserialize( $data ); + $data = openssl_decrypt( base64_decode( $data ), $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -} \ No newline at end of file + if ( ! $data ) { + return false; + } + + return json_decode( $data ); +} From e89712cd7faf47be2d6d88e6d153125b9a910818 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:17:32 +0100 Subject: [PATCH 02/24] Fix error with unset `push_syndicate_settings` --- includes/class-wp-push-syndication-server.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/class-wp-push-syndication-server.php b/includes/class-wp-push-syndication-server.php index 5da03d62..84b2d4ad 100644 --- a/includes/class-wp-push-syndication-server.php +++ b/includes/class-wp-push-syndication-server.php @@ -1225,7 +1225,7 @@ public function cron_add_pull_time_interval( $schedules ) { // Adds the custom time interval to the existing schedules. $schedules['syn_pull_time_interval'] = array( - 'interval' => intval( $this->push_syndicate_settings['pull_time_interval'] ), + 'interval' => isset( $this->push_syndicate_settings ) ? intval( $this->push_syndicate_settings['pull_time_interval'] ) : 0, 'display' => __( 'Pull Time Interval', 'push-syndication' ) ); From 299750040d30dfa379f4e072d319a5d9a2e3245e Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:17:42 +0100 Subject: [PATCH 03/24] Add initial version of a test suite for the encryption functions. --- tests/test-encryption.php | 108 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 tests/test-encryption.php diff --git a/tests/test-encryption.php b/tests/test-encryption.php new file mode 100644 index 00000000..419c9d16 --- /dev/null +++ b/tests/test-encryption.php @@ -0,0 +1,108 @@ +simple_string = 'this is a simple string!'; + $this->complex_array = array( + 'element' => 'this is a element', + 'group' => array( + 'another', + 'sub', + 'array', + 'info' => 'test', + ), + '', + 145, + 1 => 20.04, + 3 => true, + ); + } + + /** + * Runs after the test, clean-up + */ + public function tearDown() { + // Nothing yet. + } + + /** + * Tests if the cipher is available on PHP < 7.2 and if the function is returning the correct cipher. + * + * If using a PHP version older than 7.2, it will expect a mcrypt cipher. + * + * @requires PHP < 7.2 + */ + public function test_cypher_pre_72() { + // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved + $expected_cipher = MCRYPT_RIJNDAEL_256; + + // Test the cipher. + $cipher = push_syndicate_get_cipher(); + $this->assertSame( $expected_cipher, $cipher ); + } + + /** + * Tests if the cipher is available on PHP >= 7.2 and if the function is returning the correct cipher. + * + * If using a PHP 7.2 or later, it should use openssl instead of mcrypt. + * + * @requires PHP >= 7.2 + */ + public function test_cypher() { + // Test the cipher. + $cipher_data = push_syndicate_get_cipher(); + + // Test if is an array. + $this->assertIsArray( $cipher_data, 'assert if the cipher data is array' ); + $this->assertCount( 3, $cipher_data, 'assert if cipher data have three elements' ); + + $cipher = $cipher_data['cipher']; + $iv = $cipher_data['iv']; + $key = $cipher_data['key']; + + // test cipher. + $expected_cipher = 'aes-256-cbc'; + $this->assertEquals( $expected_cipher, $cipher, 'assert if cipher is available' ); + + // test key. + $this->assertEquals( $key, md5( PUSH_SYNDICATE_KEY ), 'assert if the key is generated as expected' ); + + // test iv. + $this->assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' ); + $generated_iv = substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ); + $this->assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' ); + } + + /** + * Tests the encryption and decryption methods. + */ + public function test_encryption() { + $encrypted_simple = push_syndicate_encrypt( $this->simple_string ); + $encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' ); + $encrypted_complex = push_syndicate_encrypt( $this->complex_array ); + + $this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); + $this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); + + $this->assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); + $this->assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); + + $decrypted_simple = push_syndicate_decrypt( $encrypted_simple ); + $decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex ); + + $this->assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); + $this->assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array ' ); + $this->assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); + } + + +} From 671576d84f27c171fedeba162aea3575aed9bc10 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:24:18 +0100 Subject: [PATCH 04/24] Make push_syndicate_decrypt return an array by default --- includes/push-syndicate-encryption.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/push-syndicate-encryption.php b/includes/push-syndicate-encryption.php index 607b6410..cfee30fc 100644 --- a/includes/push-syndicate-encryption.php +++ b/includes/push-syndicate-encryption.php @@ -43,7 +43,7 @@ function push_syndicate_encrypt( $data ) { } -function push_syndicate_decrypt( $data ) { +function push_syndicate_decrypt( $data, $associative = true ) { // Backwards compatibility with PHP < 7.2. if ( function_exists( 'mcrypt_encrypt' ) ) { @@ -68,5 +68,5 @@ function push_syndicate_decrypt( $data ) { return false; } - return json_decode( $data ); + return json_decode( $data, $associative ); } From f3ad7a1187b87fe2c2d29f64e727c912756fb190 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:32:28 +0100 Subject: [PATCH 05/24] Use `is_string` if `assertIsString` is not available. --- tests/test-encryption.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index 419c9d16..c19b9828 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -90,8 +90,14 @@ public function test_encryption() { $encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' ); $encrypted_complex = push_syndicate_encrypt( $this->complex_array ); - $this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); - $this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); + // Because older WP versions might use older phpunit versions, assertIsString() might not be available. + if ( method_exists( $this, 'assertIsString' ) ) { + $this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); + $this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); + } else { + $this->assertTrue( !is_string( $encrypted_simple ), 'assert if the string is encrypted (is_string)' ); + $this->assertTrue( !is_string( $encrypted_complex ), 'assert if the array is encrypted (is_string)' ); + } $this->assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); $this->assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); From 4d5d0f4917bcad1026d90f8b5553ca7254f8be06 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:32:28 +0100 Subject: [PATCH 06/24] Use `is_string` if `assertIsString` is not available. --- tests/test-encryption.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index 419c9d16..5e8a58ab 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -90,8 +90,14 @@ public function test_encryption() { $encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' ); $encrypted_complex = push_syndicate_encrypt( $this->complex_array ); - $this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); - $this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); + // Because older WP versions might use older phpunit versions, assertIsString() might not be available. + if ( method_exists( $this, 'assertIsString' ) ) { + $this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); + $this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); + } else { + $this->assertTrue( is_string( $encrypted_simple ), 'assert if the string is encrypted (is_string)' ); + $this->assertTrue( is_string( $encrypted_complex ), 'assert if the array is encrypted (is_string)' ); + } $this->assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); $this->assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); From 22ae79857e65769ffdec9df4cf0d96e1345042cb Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:38:41 +0100 Subject: [PATCH 07/24] Use `is_array` if `assertIsArray` is not available. --- tests/test-encryption.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index 5e8a58ab..d1a4e53c 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -106,7 +106,14 @@ public function test_encryption() { $decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex ); $this->assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); - $this->assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array ' ); + + // Because older WP versions might use older phpunit versions, assertIsArray() might not be available. + if ( method_exists( $this, 'assertIsArray' ) ) { + $this->assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); + } else { + $this->assertTrue( is_array( $decrypted_complex_array ), 'asserts if the decrypted complex data was decrypted as an array (is_array)' ); + } + $this->assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); } From ffa394f481dd153ad617268462e6b0aa1a8e5441 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:41:06 +0100 Subject: [PATCH 08/24] Only test with `mcrypt` if the PHP version is < 7.1 --- tests/test-encryption.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index d1a4e53c..05ab782c 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -35,11 +35,11 @@ public function tearDown() { } /** - * Tests if the cipher is available on PHP < 7.2 and if the function is returning the correct cipher. + * Tests if the cipher is available on PHP < 7.1 and if the function is returning the correct cipher. * - * If using a PHP version older than 7.2, it will expect a mcrypt cipher. + * If using a PHP version older than 7.1, it will expect a mcrypt cipher. * - * @requires PHP < 7.2 + * @requires PHP < 7.1 */ public function test_cypher_pre_72() { // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved @@ -51,11 +51,11 @@ public function test_cypher_pre_72() { } /** - * Tests if the cipher is available on PHP >= 7.2 and if the function is returning the correct cipher. + * Tests if the cipher is available on PHP >= 7.1 and if the function is returning the correct cipher. * - * If using a PHP 7.2 or later, it should use openssl instead of mcrypt. + * If using a PHP 7.1 or later, it should use openssl instead of mcrypt. * - * @requires PHP >= 7.2 + * @requires PHP >= 7.1 */ public function test_cypher() { // Test the cipher. From 1f67318676e13f65885b3b2327e8f9d00ab1f851 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Thu, 8 Jul 2021 17:44:04 +0100 Subject: [PATCH 09/24] Extend the PHP 7.1 validation to the encrypt and decrypt functions. --- includes/push-syndicate-encryption.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/push-syndicate-encryption.php b/includes/push-syndicate-encryption.php index cfee30fc..8037f6dc 100644 --- a/includes/push-syndicate-encryption.php +++ b/includes/push-syndicate-encryption.php @@ -3,7 +3,7 @@ function push_syndicate_get_cipher() { $cipher = 'aes-256-cbc'; - if ( function_exists( 'mcrypt_encrypt' ) ) { + if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { return MCRYPT_RIJNDAEL_256; } @@ -23,8 +23,8 @@ function push_syndicate_encrypt( $data ) { // Will most likely break backwards compatibility with older keys // https://stackoverflow.com/questions/49997338/mcrypt-rijndael-256-to-openssl-aes-256-ecb-conversion - // Backwards compatibility with PHP < 7.2. - if ( function_exists( 'mcrypt_encrypt' ) ) { + // Backwards compatibility with PHP < 7.1. Use mcrypt instead. + if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { // @codingStandardsIgnoreStart $data = serialize( $data ); return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), $data, MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY)))); @@ -45,8 +45,8 @@ function push_syndicate_encrypt( $data ) { function push_syndicate_decrypt( $data, $associative = true ) { - // Backwards compatibility with PHP < 7.2. - if ( function_exists( 'mcrypt_encrypt' ) ) { + // Backwards compatibility with PHP < 7.1. Use mcrypt instead. + if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { // @codingStandardsIgnoreStart $data = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, md5( PUSH_SYNDICATE_KEY ), base64_decode( $data ), MCRYPT_MODE_CBC, md5( md5( PUSH_SYNDICATE_KEY ) ) ), "\0" ); if ( ! $data ) { From 5024eaad2908fb2cd7d5073cd036d56b7d9d976c Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Mon, 12 Jul 2021 15:58:01 +0100 Subject: [PATCH 10/24] Use yoast/wp-test-utils for compatibility with different phpunit versions. --- composer.json | 2 +- tests/bootstrap.php | 8 +++++++ tests/test-encryption.php | 45 ++++++++++++++++----------------------- 3 files changed, 27 insertions(+), 28 deletions(-) diff --git a/composer.json b/composer.json index 65160e78..e390d981 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "phpunit/phpunit": "^4 || ^5 || ^6 || ^7", "squizlabs/php_codesniffer": "^3.5", "wp-coding-standards/wpcs": "^2.3.0", - "yoast/phpunit-polyfills": "^0.2.0" + "yoast/wp-test-utils": "^0.2.2" }, "scripts": { "cbf": [ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index f9ca33c8..9a987672 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,9 +1,12 @@ assertSame( $expected_cipher, $cipher ); + self::assertSame( $expected_cipher, $cipher ); } /** @@ -62,8 +65,8 @@ public function test_cypher() { $cipher_data = push_syndicate_get_cipher(); // Test if is an array. - $this->assertIsArray( $cipher_data, 'assert if the cipher data is array' ); - $this->assertCount( 3, $cipher_data, 'assert if cipher data have three elements' ); + self::assertIsArray( $cipher_data, 'assert if the cipher data is array' ); + self::assertCount( 3, $cipher_data, 'assert if cipher data have three elements' ); $cipher = $cipher_data['cipher']; $iv = $cipher_data['iv']; @@ -71,15 +74,15 @@ public function test_cypher() { // test cipher. $expected_cipher = 'aes-256-cbc'; - $this->assertEquals( $expected_cipher, $cipher, 'assert if cipher is available' ); + self::assertEquals( $expected_cipher, $cipher, 'assert if cipher is available' ); // test key. - $this->assertEquals( $key, md5( PUSH_SYNDICATE_KEY ), 'assert if the key is generated as expected' ); + self::assertEquals( $key, md5( PUSH_SYNDICATE_KEY ), 'assert if the key is generated as expected' ); // test iv. - $this->assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' ); + self::assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' ); $generated_iv = substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ); - $this->assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' ); + self::assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' ); } /** @@ -90,31 +93,19 @@ public function test_encryption() { $encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' ); $encrypted_complex = push_syndicate_encrypt( $this->complex_array ); - // Because older WP versions might use older phpunit versions, assertIsString() might not be available. - if ( method_exists( $this, 'assertIsString' ) ) { - $this->assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); - $this->assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); - } else { - $this->assertTrue( is_string( $encrypted_simple ), 'assert if the string is encrypted (is_string)' ); - $this->assertTrue( is_string( $encrypted_complex ), 'assert if the array is encrypted (is_string)' ); - } + self::assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); + self::assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); - $this->assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); - $this->assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); + self::assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); + self::assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); $decrypted_simple = push_syndicate_decrypt( $encrypted_simple ); $decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex ); - $this->assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); - - // Because older WP versions might use older phpunit versions, assertIsArray() might not be available. - if ( method_exists( $this, 'assertIsArray' ) ) { - $this->assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); - } else { - $this->assertTrue( is_array( $decrypted_complex_array ), 'asserts if the decrypted complex data was decrypted as an array (is_array)' ); - } + self::assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); - $this->assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); + self::assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); + self::assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); } From b1690a98d495e2044ab10f183c05bc4aa18c93cf Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Mon, 19 Jul 2021 16:04:47 +0100 Subject: [PATCH 11/24] Refactor encryption to use Syndication_Encryption class --- includes/class-syndication-encryption.php | 64 ++++++++++++ .../class-syndication-encryptor-mcrypt.php | 38 +++++++ .../class-syndication-encryptor-openssl.php | 65 ++++++++++++ includes/class-syndication-encryptor.php | 27 +++++ includes/push-syndicate-encryption.php | 84 ++++------------ tests/test-encryption.php | 98 ++++++++++++------- 6 files changed, 277 insertions(+), 99 deletions(-) create mode 100644 includes/class-syndication-encryption.php create mode 100644 includes/class-syndication-encryptor-mcrypt.php create mode 100644 includes/class-syndication-encryptor-openssl.php create mode 100644 includes/class-syndication-encryptor.php diff --git a/includes/class-syndication-encryption.php b/includes/class-syndication-encryption.php new file mode 100644 index 00000000..130469f2 --- /dev/null +++ b/includes/class-syndication-encryption.php @@ -0,0 +1,64 @@ +encrypt( $data ); + } + + /** + * Decrypts an encrypted $data using a Syndication_Encryptor, and returns the decrypted object. + * + * @param string $data The encrypted data. + * @param bool $associative If true, returns as an associative array. Otherwise returns as a class. + * + * @return false|array|object + */ + public static function decrypt( $data, $associative = true ) { + $encryptor = self::get_encryptor(); + return $encryptor->decrypt( $data, $associative ); + } + +} diff --git a/includes/class-syndication-encryptor-mcrypt.php b/includes/class-syndication-encryptor-mcrypt.php new file mode 100644 index 00000000..1b4a99ab --- /dev/null +++ b/includes/class-syndication-encryptor-mcrypt.php @@ -0,0 +1,38 @@ +getCipher(); + + if ( ! $cipher ) { + return $data; + } + + $encrypted_data = openssl_encrypt( $data, $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); + return base64_encode( $encrypted_data ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode + } + + /** + * @inheritDoc + */ + public function decrypt( $data, $associative = true ) { + $cipher = $this->getCipher(); + + if ( ! $cipher ) { + return $data; + } + + $data = openssl_decrypt( base64_decode( $data ), $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode + + if ( ! $data ) { + return false; + } + + return json_decode( $data, $associative ); + } + + /** + * @inheritDoc + */ + public function getCipher() { + if ( in_array( $this->cipher, openssl_get_cipher_methods(), true ) ) { + return array( + 'cipher' => $this->cipher, + 'iv' => substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ), + 'key' => md5( PUSH_SYNDICATE_KEY ), + ); + } + + return false; // @TODO: return another default cipher? return exception? + } +} diff --git a/includes/class-syndication-encryptor.php b/includes/class-syndication-encryptor.php new file mode 100644 index 00000000..7ae3ec2d --- /dev/null +++ b/includes/class-syndication-encryptor.php @@ -0,0 +1,27 @@ + $cipher, - 'iv' => substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ), - 'key' => md5( PUSH_SYNDICATE_KEY ), - ); - } - - return false; // @TODO: return another default cipher? return exception? -} - +require_once dirname( __FILE__ ) . '/class-syndication-encryption.php'; + +/** + * Encrypts data. + * + * @param string $data The data to encrypt. + * + * @return false|string + */ function push_syndicate_encrypt( $data ) { - // @todo: replace mcrypt with openssl. problem: Rijndael AES is not available on openssl;s AES-256. - // Will most likely break backwards compatibility with older keys - // https://stackoverflow.com/questions/49997338/mcrypt-rijndael-256-to-openssl-aes-256-ecb-conversion - - // Backwards compatibility with PHP < 7.1. Use mcrypt instead. - if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { - // @codingStandardsIgnoreStart - $data = serialize( $data ); - return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5(PUSH_SYNDICATE_KEY), $data, MCRYPT_MODE_CBC, md5(md5(PUSH_SYNDICATE_KEY)))); - // @codingStandardsIgnoreEnd - } - - $data = wp_json_encode( $data ); - $cipher = push_syndicate_get_cipher(); - - if ( ! $cipher ) { - return $data; - } - - $encrypted_data = openssl_encrypt( $data, $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); - return base64_encode( $encrypted_data ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode - + return Syndication_Encryption::encrypt( $data ); } +/** + * Decrypts data. + * + * @param string $data The encrypted data to decrypt. + * @param bool $associative If true, returns as an associative array. Otherwise returns as a class. + * + * @return array|false|object + */ function push_syndicate_decrypt( $data, $associative = true ) { - - // Backwards compatibility with PHP < 7.1. Use mcrypt instead. - if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { - // @codingStandardsIgnoreStart - $data = rtrim( mcrypt_decrypt( MCRYPT_RIJNDAEL_256, md5( PUSH_SYNDICATE_KEY ), base64_decode( $data ), MCRYPT_MODE_CBC, md5( md5( PUSH_SYNDICATE_KEY ) ) ), "\0" ); - if ( ! $data ) { - return false; - } - return @unserialize( $data ); - // @codingStandardsIgnoreEnd - } - - $cipher = push_syndicate_get_cipher(); - - if ( ! $cipher ) { - return $data; - } - - $data = openssl_decrypt( base64_decode( $data ), $cipher['cipher'], $cipher['key'], 0, $cipher['iv'] ); //phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode - - if ( ! $data ) { - return false; - } - - return json_decode( $data, $associative ); + return Syndication_Encryption::decrypt( $data, $associative ); } diff --git a/tests/test-encryption.php b/tests/test-encryption.php index f9a2f5fb..bc4110cb 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -10,6 +10,7 @@ class EncryptionTest extends WPIntegrationTestCase { private $simple_string; private $complex_array; + /** * Runs before the test, set-up. */ @@ -31,38 +32,60 @@ public function setUp() { } /** - * Runs after the test, clean-up + * Test if the encryptor being used with PHP 7.1 or older is the mcrypt encryptor. + * + * @requires PHP < 7.1 */ - public function tearDown() { - // Nothing yet. + public function test_get_encryptor_before_php_71() { + $encryptor = \Syndication_Encryption::get_encryptor(); + + // If PHP < 7.1, it should be using the mcrypt encryptor. + self::assertInstanceOf( \Syndication_Encryptor_MCrypt::class, $encryptor ); } /** - * Tests if the cipher is available on PHP < 7.1 and if the function is returning the correct cipher. + * Test if the encryptor being used with newer PHP is OpenSSL encryptor. * - * If using a PHP version older than 7.1, it will expect a mcrypt cipher. - * - * @requires PHP < 7.1 + * @requires PHP >= 7.1 */ - public function test_cypher_pre_72() { - // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved - $expected_cipher = MCRYPT_RIJNDAEL_256; + public function test_get_encryptor_after_php_71() { + $encryptor = \Syndication_Encryption::get_encryptor(); - // Test the cipher. - $cipher = push_syndicate_get_cipher(); - self::assertSame( $expected_cipher, $cipher ); + // Test if the Encryptor being used is the OpenSSL. + self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor ); } /** - * Tests if the cipher is available on PHP >= 7.1 and if the function is returning the correct cipher. - * - * If using a PHP 7.1 or later, it should use openssl instead of mcrypt. - * - * @requires PHP >= 7.1 + * Tests the encryption and decryption functions */ - public function test_cypher() { + public function test_encryption() { + $encrypted_simple = push_syndicate_encrypt( $this->simple_string ); + $encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' ); + $encrypted_complex = push_syndicate_encrypt( $this->complex_array ); + + self::assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); + self::assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); + + self::assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); + self::assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); + + $decrypted_simple = push_syndicate_decrypt( $encrypted_simple ); + $decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex ); + + self::assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); + + self::assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); + self::assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); + } + + /** + * Tests the Syndication_Encryptor_OpenSSL encryptor. + */ + public function test_encryptor_openssl() { + $encryptor = new \Syndication_Encryptor_OpenSSL(); + // Test the cipher. - $cipher_data = push_syndicate_get_cipher(); + $cipher_data = $encryptor->getCipher(); // Test if is an array. self::assertIsArray( $cipher_data, 'assert if the cipher data is array' ); @@ -83,29 +106,36 @@ public function test_cypher() { self::assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' ); $generated_iv = substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ); self::assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' ); + + // Test simple encryption and decryption. + $encrypted = $encryptor->encrypt( $this->simple_string ); + self::assertIsString( $encrypted ); + + $decrypted = $encryptor->decrypt( $encrypted ); + self::assertEquals( $this->simple_string, $decrypted ); } /** - * Tests the encryption and decryption methods. + * Tests the Syndication_Encryptor_MCrypt encryptor, only if the module is present (usually PHP < 7.1) + * + * @requires extension mcrypt */ - public function test_encryption() { - $encrypted_simple = push_syndicate_encrypt( $this->simple_string ); - $encrypted_simple_different = push_syndicate_encrypt( $this->simple_string . '1' ); - $encrypted_complex = push_syndicate_encrypt( $this->complex_array ); + public function test_encryptor_mcrypt() { + $encryptor = new \Syndication_Encryptor_MCrypt(); - self::assertIsString( $encrypted_simple, 'assert if the string is encrypted' ); - self::assertIsString( $encrypted_complex, 'assert if the array is encrypted' ); - self::assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); - self::assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); - $decrypted_simple = push_syndicate_decrypt( $encrypted_simple ); - $decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex ); + // Test the cipher. + $expected_cipher = MCRYPT_RIJNDAEL_256; // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved + $cipher = $encryptor->getCipher(); + self::assertSame( $expected_cipher, $cipher ); - self::assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); + // Test simple encryption and decryption. + $encrypted = $encryptor->encrypt( $this->simple_string ); + self::assertIsString( $encrypted ); - self::assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); - self::assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); + $decrypted = $encryptor->decrypt( $encrypted ); + self::assertEquals( $this->simple_string, $decrypted ); } From 02f0aa8064b72292bd087bf1ce7b404f10dbe1a8 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Mon, 19 Jul 2021 16:08:34 +0100 Subject: [PATCH 12/24] Fix tests failing on PHP 7.1 --- includes/class-syndication-encryption.php | 5 +++-- tests/test-encryption.php | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/includes/class-syndication-encryption.php b/includes/class-syndication-encryption.php index 130469f2..a0131f96 100644 --- a/includes/class-syndication-encryption.php +++ b/includes/class-syndication-encryption.php @@ -26,8 +26,9 @@ public static function get_encryptor() { return self::$encryptor; } - // If mcrypt is available ( PHP < 7.1 ), use it instead. - if ( defined( 'MCRYPT_RIJNDAEL_256' ) ) { + // On PHP 7.1 mcrypt is available, but will throw a deprecated error if its used. Therefore, checking for the + // PHP version, instead of checking for mcrypt is a better approach. + if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { self::$encryptor = new Syndication_Encryptor_MCrypt(); return self::$encryptor; } diff --git a/tests/test-encryption.php b/tests/test-encryption.php index bc4110cb..dbdc4c7d 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -121,9 +121,12 @@ public function test_encryptor_openssl() { * @requires extension mcrypt */ public function test_encryptor_mcrypt() { - $encryptor = new \Syndication_Encryptor_MCrypt(); - + // Disable deprecation warning for this test, as it will run on PHP 7.1. This test will only ensure functionality of the + // Syndication_Encryptor_MCrypt class. + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting + $error_reporting = error_reporting( error_reporting() & ~E_DEPRECATED ); + $encryptor = new \Syndication_Encryptor_MCrypt(); // Test the cipher. $expected_cipher = MCRYPT_RIJNDAEL_256; // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved @@ -136,6 +139,9 @@ public function test_encryptor_mcrypt() { $decrypted = $encryptor->decrypt( $encrypted ); self::assertEquals( $this->simple_string, $decrypted ); + + // Restore original error reporting. + error_reporting( $error_reporting ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting } From 8a4d2e7dd5b7fd7a167469f1953d747eabbc1b5e Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Tue, 20 Jul 2021 15:32:18 +0100 Subject: [PATCH 13/24] Move imports and initialization to plugin root file --- includes/class-syndication-encryption.php | 25 +++++++++-------- .../class-syndication-encryptor-mcrypt.php | 2 -- .../class-syndication-encryptor-openssl.php | 2 -- push-syndication.php | 28 +++++++++++++++---- 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/includes/class-syndication-encryption.php b/includes/class-syndication-encryption.php index a0131f96..a2ce40ef 100644 --- a/includes/class-syndication-encryption.php +++ b/includes/class-syndication-encryption.php @@ -1,9 +1,5 @@ Date: Tue, 20 Jul 2021 16:09:21 +0100 Subject: [PATCH 14/24] Refactor tests to have individual tests for each encryptor --- includes/class-syndication-encryption.php | 9 +- tests/test-encryption.php | 91 +++++------------ tests/test-encryptor-mcrypt.php | 114 ++++++++++++++++++++++ tests/test-encryptor-openssl.php | 113 +++++++++++++++++++++ 4 files changed, 256 insertions(+), 71 deletions(-) create mode 100644 tests/test-encryptor-mcrypt.php create mode 100644 tests/test-encryptor-openssl.php diff --git a/includes/class-syndication-encryption.php b/includes/class-syndication-encryption.php index a2ce40ef..bc9f0208 100644 --- a/includes/class-syndication-encryption.php +++ b/includes/class-syndication-encryption.php @@ -30,12 +30,15 @@ public static function get_encryptor() { * * @param Syndication_Encryptor $encryptor Encryptor to be used in the encryption. * - * @return Syndication_Encryptor Returns the encryptor + * @return Syndication_Encryptor|false Returns the encryptor */ public static function set_encryptor( $encryptor ) { - self::$encryptor = $encryptor; + if ( $encryptor instanceof Syndication_Encryptor ) { + self::$encryptor = $encryptor; + return self::$encryptor; + } - return self::$encryptor; + return false; } /** diff --git a/tests/test-encryption.php b/tests/test-encryption.php index dbdc4c7d..d012c7a1 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -56,7 +56,18 @@ public function test_get_encryptor_after_php_71() { } /** - * Tests the encryption and decryption functions + * Test if setting the encryptor works as expected + */ + public function test_set_encryptor() { + $encryptor = \Syndication_Encryption::set_encryptor( new \Syndication_Encryptor_OpenSSL() ); + self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor, 'assert if the encryptor is set' ); + + $encryptor = \Syndication_Encryption::set_encryptor( new \stdClass() ); + self::assertFalse( $encryptor, 'assert if invalid encryptor returns false' ); + } + + /** + * Tests the encryption functions */ public function test_encryption() { $encrypted_simple = push_syndicate_encrypt( $this->simple_string ); @@ -69,80 +80,24 @@ public function test_encryption() { self::assertNotEquals( $encrypted_simple, $encrypted_complex, 'assert that the two different objects have different results' ); self::assertNotEquals( $encrypted_simple, $encrypted_simple_different, 'assert that the two different strings have different results' ); - $decrypted_simple = push_syndicate_decrypt( $encrypted_simple ); - $decrypted_complex_array = push_syndicate_decrypt( $encrypted_complex ); - - self::assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); - - self::assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); - self::assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); - } - - /** - * Tests the Syndication_Encryptor_OpenSSL encryptor. - */ - public function test_encryptor_openssl() { - $encryptor = new \Syndication_Encryptor_OpenSSL(); - - // Test the cipher. - $cipher_data = $encryptor->getCipher(); - - // Test if is an array. - self::assertIsArray( $cipher_data, 'assert if the cipher data is array' ); - self::assertCount( 3, $cipher_data, 'assert if cipher data have three elements' ); - - $cipher = $cipher_data['cipher']; - $iv = $cipher_data['iv']; - $key = $cipher_data['key']; - - // test cipher. - $expected_cipher = 'aes-256-cbc'; - self::assertEquals( $expected_cipher, $cipher, 'assert if cipher is available' ); - - // test key. - self::assertEquals( $key, md5( PUSH_SYNDICATE_KEY ), 'assert if the key is generated as expected' ); - - // test iv. - self::assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' ); - $generated_iv = substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ); - self::assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' ); - - // Test simple encryption and decryption. - $encrypted = $encryptor->encrypt( $this->simple_string ); - self::assertIsString( $encrypted ); - - $decrypted = $encryptor->decrypt( $encrypted ); - self::assertEquals( $this->simple_string, $decrypted ); + return array( $encrypted_simple, $encrypted_complex ); } /** - * Tests the Syndication_Encryptor_MCrypt encryptor, only if the module is present (usually PHP < 7.1) + * Tests the decryption functions + * + * @param array[2] $array_encrypted Array with the encrypted data. First element is a string, second element is array. * - * @requires extension mcrypt + * @depends test_encryption */ - public function test_encryptor_mcrypt() { - // Disable deprecation warning for this test, as it will run on PHP 7.1. This test will only ensure functionality of the - // Syndication_Encryptor_MCrypt class. - // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting - $error_reporting = error_reporting( error_reporting() & ~E_DEPRECATED ); + public function test_decryption( $array_encrypted ) { + $decrypted_simple = push_syndicate_decrypt( $array_encrypted[0] ); + $decrypted_complex_array = push_syndicate_decrypt( $array_encrypted[1] ); - $encryptor = new \Syndication_Encryptor_MCrypt(); - - // Test the cipher. - $expected_cipher = MCRYPT_RIJNDAEL_256; // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved - $cipher = $encryptor->getCipher(); - self::assertSame( $expected_cipher, $cipher ); - - // Test simple encryption and decryption. - $encrypted = $encryptor->encrypt( $this->simple_string ); - self::assertIsString( $encrypted ); - - $decrypted = $encryptor->decrypt( $encrypted ); - self::assertEquals( $this->simple_string, $decrypted ); + self::assertEquals( $this->simple_string, $decrypted_simple, 'asserts if the decrypted string is the same as the original' ); - // Restore original error reporting. - error_reporting( $error_reporting ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting + self::assertIsArray( $decrypted_complex_array, 'asserts if the decrypted complex data was decrypted as an array' ); + self::assertEquals( $this->complex_array, $decrypted_complex_array, 'check if the decrypted array is the same as the original' ); } - } diff --git a/tests/test-encryptor-mcrypt.php b/tests/test-encryptor-mcrypt.php new file mode 100644 index 00000000..8eaac3b4 --- /dev/null +++ b/tests/test-encryptor-mcrypt.php @@ -0,0 +1,114 @@ +simple_string = 'this is a simple string!'; + $this->complex_array = array( + 'element' => 'this is a element', + 'group' => array( + 'another', + 'sub', + 'array', + 'info' => 'test', + ), + '', + 145, + 1 => 20.04, + 3 => true, + ); + + $this->encryptor = new \Syndication_Encryptor_MCrypt(); + + // Disable deprecation warning for this test, as it will run on PHP 7.1. This test will only ensure functionality of the + // Syndication_Encryptor_MCrypt class. + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting + $this->error_reporting = error_reporting( error_reporting() & ~E_DEPRECATED ); + } + + /** + * Runs after the test. + */ + public function tearDown() { + // Restore original error reporting. + error_reporting( $this->error_reporting ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting + parent::tearDown(); + } + + /** + * Test a simple string encryption + */ + public function test_simple_encryption() { + $encrypted = $this->encryptor->encrypt( $this->simple_string ); + + self::assertIsString( $encrypted, 'assert if the string encryption returns string' ); + self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); + + return $encrypted; + } + + /** + * Test a simple string decryption. + * + * @param string $encrypted The encrypted string from the previous test. + * + * @depends test_simple_encryption + */ + public function test_simple_decryption( $encrypted ) { + $decrypted = $this->encryptor->decrypt( $encrypted ); + self::assertEquals( $this->simple_string, $decrypted ); + } + + /** + * Test a complex (array) encryption. + */ + public function test_complex_encryption() { + $encrypted = $this->encryptor->encrypt( $this->complex_array ); + + self::assertIsString( $encrypted, 'assert if the array encryption returns string' ); + self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); + + return $encrypted; + } + + /** + * Test an array decryption. + * + * @param string $encrypted The encrypted string from the previous test. + * + * @depends test_complex_encryption + */ + public function test_complex_decryption( $encrypted ) { + $decrypted = $this->encryptor->decrypt( $encrypted ); + + self::assertIsArray( $decrypted, 'assert if the decrypted data is an array' ); + self::assertEquals( $this->complex_array, $decrypted, 'assert if the decrypted array is equal to the original array' ); + } + + /** + * Test the expected cipher for mcrypt + */ + public function test_cipher() { + $expected_cipher = MCRYPT_RIJNDAEL_256; // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved + $cipher = $this->encryptor->getCipher(); + + self::assertSame( $expected_cipher, $cipher ); + } + +} diff --git a/tests/test-encryptor-openssl.php b/tests/test-encryptor-openssl.php new file mode 100644 index 00000000..66948ed0 --- /dev/null +++ b/tests/test-encryptor-openssl.php @@ -0,0 +1,113 @@ +simple_string = 'this is a simple string!'; + $this->complex_array = array( + 'element' => 'this is a element', + 'group' => array( + 'another', + 'sub', + 'array', + 'info' => 'test', + ), + '', + 145, + 1 => 20.04, + 3 => true, + ); + + $this->encryptor = new \Syndication_Encryptor_OpenSSL(); + } + + /** + * Test a simple string encryption + */ + public function test_simple_encryption() { + $encrypted = $this->encryptor->encrypt( $this->simple_string ); + + self::assertIsString( $encrypted, 'assert if the string encryption returns string' ); + self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); + + return $encrypted; + } + + /** + * Test a simple string decryption. + * + * @param string $encrypted The encrypted string from the previous test. + * + * @depends test_simple_encryption + */ + public function test_simple_decryption( $encrypted ) { + $decrypted = $this->encryptor->decrypt( $encrypted ); + self::assertEquals( $this->simple_string, $decrypted ); + } + + /** + * Test a complex (array) encryption. + */ + public function test_complex_encryption() { + $encrypted = $this->encryptor->encrypt( $this->complex_array ); + + self::assertIsString( $encrypted, 'assert if the array encryption returns string' ); + self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); + + return $encrypted; + } + + /** + * Test an array decryption. + * + * @param string $encrypted The encrypted string from the previous test. + * + * @depends test_complex_encryption + */ + public function test_complex_decryption( $encrypted ) { + $decrypted = $this->encryptor->decrypt( $encrypted ); + + self::assertIsArray( $decrypted, 'assert if the decrypted data is an array' ); + self::assertEquals( $this->complex_array, $decrypted, 'assert if the decrypted array is equal to the original array' ); + } + + /** + * Test the expected cipher for openssl + */ + public function test_cipher() { + // Test the cipher. + $cipher_data = $this->encryptor->getCipher(); + + // Test if is an array. + self::assertIsArray( $cipher_data, 'assert if the cipher data is array' ); + self::assertCount( 3, $cipher_data, 'assert if cipher data have three elements' ); + + $cipher = $cipher_data['cipher']; + $iv = $cipher_data['iv']; + $key = $cipher_data['key']; + + // test cipher. + $expected_cipher = 'aes-256-cbc'; + self::assertEquals( $expected_cipher, $cipher, 'assert if cipher is available' ); + + // test key. + self::assertEquals( $key, md5( PUSH_SYNDICATE_KEY ), 'assert if the key is generated as expected' ); + + // test iv. + self::assertEquals( 16, strlen( $iv ), 'assert iv size (must be 16)' ); + $generated_iv = substr( md5( md5( PUSH_SYNDICATE_KEY ) ), 0, 16 ); + self::assertEquals( $generated_iv, $iv, 'assert if generated iv is as expected' ); + } +} From 1e6d3737dc606715c0a3d766da28df9510ff0f0c Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Tue, 20 Jul 2021 16:30:50 +0100 Subject: [PATCH 15/24] Refactor tests to use a abstract test class for Encryptors --- tests/bootstrap.php | 6 ++ tests/class-encryptor-test-case.php | 97 +++++++++++++++++++++++++++++ tests/test-encryption.php | 1 + tests/test-encryptor-mcrypt.php | 53 +--------------- tests/test-encryptor-openssl.php | 70 +-------------------- 5 files changed, 109 insertions(+), 118 deletions(-) create mode 100644 tests/class-encryptor-test-case.php diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 9a987672..35c1f71a 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -26,3 +26,9 @@ function _manually_load_plugin() { */ require_once dirname( __DIR__ ) . '/vendor/yoast/wp-test-utils/src/WPIntegration/bootstrap-functions.php'; WPIntegration\bootstrap_it(); + +/* + * Load tests dependencies + */ + +require_once dirname( __FILE__ ) . '/class-encryptor-test-case.php'; diff --git a/tests/class-encryptor-test-case.php b/tests/class-encryptor-test-case.php new file mode 100644 index 00000000..d6bd54a7 --- /dev/null +++ b/tests/class-encryptor-test-case.php @@ -0,0 +1,97 @@ +simple_string = 'this is a simple string!'; + $this->complex_array = array( + 'element' => 'this is a element', + 'group' => array( + 'another', + 'sub', + 'array', + 'info' => 'test', + ), + '', + 145, + 1 => 20.04, + 3 => true, + ); + } + + /** + * Test a simple string encryption + */ + public function test_simple_encryption() { + $encrypted = $this->encryptor->encrypt( $this->simple_string ); + + self::assertIsString( $encrypted, 'assert if the string encryption returns string' ); + self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); + + return $encrypted; + } + + /** + * Test a simple string decryption. + * + * @param string $encrypted The encrypted string from the previous test. + * + * @depends test_simple_encryption + */ + public function test_simple_decryption( $encrypted ) { + $decrypted = $this->encryptor->decrypt( $encrypted ); + self::assertEquals( $this->simple_string, $decrypted ); + } + + /** + * Test a complex (array) encryption. + */ + public function test_complex_encryption() { + $encrypted = $this->encryptor->encrypt( $this->complex_array ); + + self::assertIsString( $encrypted, 'assert if the array encryption returns string' ); + self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); + + return $encrypted; + } + + /** + * Test an array decryption. + * + * @param string $encrypted The encrypted string from the previous test. + * + * @depends test_complex_encryption + */ + public function test_complex_decryption( $encrypted ) { + $decrypted = $this->encryptor->decrypt( $encrypted ); + + self::assertIsArray( $decrypted, 'assert if the decrypted data is an array' ); + self::assertEquals( $this->complex_array, $decrypted, 'assert if the decrypted array is equal to the original array' ); + + // Test without associative set to true. + $decrypted = $this->encryptor->decrypt( $encrypted, false ); + self::assertIsObject( $decrypted, 'assert if the decrypted data is an object' ); + self::assertEquals( $decrypted->element, $this->complex_array['element'], 'assert if the first element is the same' ); + + } + + /** + * Test the expected cipher + */ + abstract public function test_cipher(); + +} diff --git a/tests/test-encryption.php b/tests/test-encryption.php index d012c7a1..ab1c928e 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -5,6 +5,7 @@ /** * Class EncryptionTest + * */ class EncryptionTest extends WPIntegrationTestCase { private $simple_string; diff --git a/tests/test-encryptor-mcrypt.php b/tests/test-encryptor-mcrypt.php index 8eaac3b4..0afdbd65 100644 --- a/tests/test-encryptor-mcrypt.php +++ b/tests/test-encryptor-mcrypt.php @@ -8,32 +8,14 @@ * * @requires extension mcrypt */ -class EncryptorMCryptTest extends WPIntegrationTestCase { - private $simple_string; - private $complex_array; - private $encryptor; +class EncryptorMCryptTest extends EncryptorTestCase { private $error_reporting; - /** * Runs before the test, set-up. */ public function setUp() { - $this->simple_string = 'this is a simple string!'; - $this->complex_array = array( - 'element' => 'this is a element', - 'group' => array( - 'another', - 'sub', - 'array', - 'info' => 'test', - ), - '', - 145, - 1 => 20.04, - 3 => true, - ); - + parent::setUp(); $this->encryptor = new \Syndication_Encryptor_MCrypt(); // Disable deprecation warning for this test, as it will run on PHP 7.1. This test will only ensure functionality of the @@ -51,40 +33,11 @@ public function tearDown() { parent::tearDown(); } - /** - * Test a simple string encryption - */ - public function test_simple_encryption() { - $encrypted = $this->encryptor->encrypt( $this->simple_string ); - - self::assertIsString( $encrypted, 'assert if the string encryption returns string' ); - self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); - - return $encrypted; - } - - /** - * Test a simple string decryption. - * - * @param string $encrypted The encrypted string from the previous test. - * - * @depends test_simple_encryption - */ - public function test_simple_decryption( $encrypted ) { - $decrypted = $this->encryptor->decrypt( $encrypted ); - self::assertEquals( $this->simple_string, $decrypted ); - } - /** * Test a complex (array) encryption. */ public function test_complex_encryption() { - $encrypted = $this->encryptor->encrypt( $this->complex_array ); - - self::assertIsString( $encrypted, 'assert if the array encryption returns string' ); - self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); - - return $encrypted; + return parent::test_complex_encryption(); } /** diff --git a/tests/test-encryptor-openssl.php b/tests/test-encryptor-openssl.php index 66948ed0..42ad62e4 100644 --- a/tests/test-encryptor-openssl.php +++ b/tests/test-encryptor-openssl.php @@ -6,83 +6,17 @@ /** * Class EncryptorOpenSSLTest */ -class EncryptorOpenSSLTest extends WPIntegrationTestCase { - private $simple_string; - private $complex_array; - private $encryptor; +class EncryptorOpenSSLTest extends EncryptorTestCase { /** * Runs before the test, set-up. */ public function setUp() { - $this->simple_string = 'this is a simple string!'; - $this->complex_array = array( - 'element' => 'this is a element', - 'group' => array( - 'another', - 'sub', - 'array', - 'info' => 'test', - ), - '', - 145, - 1 => 20.04, - 3 => true, - ); + parent::setUp(); $this->encryptor = new \Syndication_Encryptor_OpenSSL(); } - /** - * Test a simple string encryption - */ - public function test_simple_encryption() { - $encrypted = $this->encryptor->encrypt( $this->simple_string ); - - self::assertIsString( $encrypted, 'assert if the string encryption returns string' ); - self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); - - return $encrypted; - } - - /** - * Test a simple string decryption. - * - * @param string $encrypted The encrypted string from the previous test. - * - * @depends test_simple_encryption - */ - public function test_simple_decryption( $encrypted ) { - $decrypted = $this->encryptor->decrypt( $encrypted ); - self::assertEquals( $this->simple_string, $decrypted ); - } - - /** - * Test a complex (array) encryption. - */ - public function test_complex_encryption() { - $encrypted = $this->encryptor->encrypt( $this->complex_array ); - - self::assertIsString( $encrypted, 'assert if the array encryption returns string' ); - self::assertEquals( base64_encode( base64_decode( $encrypted ) ), $encrypted, 'assert if the encrypted data is encoded in base64' ); - - return $encrypted; - } - - /** - * Test an array decryption. - * - * @param string $encrypted The encrypted string from the previous test. - * - * @depends test_complex_encryption - */ - public function test_complex_decryption( $encrypted ) { - $decrypted = $this->encryptor->decrypt( $encrypted ); - - self::assertIsArray( $decrypted, 'assert if the decrypted data is an array' ); - self::assertEquals( $this->complex_array, $decrypted, 'assert if the decrypted array is equal to the original array' ); - } - /** * Test the expected cipher for openssl */ From 8663284357ed44bc4ba84c6c80da0228342c34f1 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Tue, 20 Jul 2021 16:34:26 +0100 Subject: [PATCH 16/24] Change Syndication_Encryptor to interface --- .../class-syndication-encryptor-mcrypt.php | 4 +-- .../class-syndication-encryptor-openssl.php | 8 ++--- includes/class-syndication-encryptor.php | 27 --------------- includes/interface-syndication-encryptor.php | 33 +++++++++++++++++++ push-syndication.php | 4 +-- tests/test-encryptor-mcrypt.php | 2 +- tests/test-encryptor-openssl.php | 2 +- 7 files changed, 43 insertions(+), 37 deletions(-) delete mode 100644 includes/class-syndication-encryptor.php create mode 100644 includes/interface-syndication-encryptor.php diff --git a/includes/class-syndication-encryptor-mcrypt.php b/includes/class-syndication-encryptor-mcrypt.php index d23776b9..02249f6f 100644 --- a/includes/class-syndication-encryptor-mcrypt.php +++ b/includes/class-syndication-encryptor-mcrypt.php @@ -3,7 +3,7 @@ /** * Class Syndication_Encryptor_OpenSSL */ -class Syndication_Encryptor_MCrypt extends Syndication_Encryptor { +class Syndication_Encryptor_MCrypt implements Syndication_Encryptor { /** * @inheritDoc @@ -30,7 +30,7 @@ public function decrypt( $data, $associative = true ) { /** * @inheritDoc */ - public function getCipher() { + public function get_cipher() { return MCRYPT_RIJNDAEL_256; // phpcs:ignore PHPCompatibility.Constants.RemovedConstants.mcrypt_rijndael_256DeprecatedRemoved } } diff --git a/includes/class-syndication-encryptor-openssl.php b/includes/class-syndication-encryptor-openssl.php index fb62d0dd..825f141a 100644 --- a/includes/class-syndication-encryptor-openssl.php +++ b/includes/class-syndication-encryptor-openssl.php @@ -3,7 +3,7 @@ /** * Class Syndication_Encryptor_OpenSSL */ -class Syndication_Encryptor_OpenSSL extends Syndication_Encryptor { +class Syndication_Encryptor_OpenSSL implements Syndication_Encryptor { /** * The cipher to be used for encryption. @@ -17,7 +17,7 @@ class Syndication_Encryptor_OpenSSL extends Syndication_Encryptor { */ public function encrypt( $data ) { $data = wp_json_encode( $data ); - $cipher = $this->getCipher(); + $cipher = $this->get_cipher(); if ( ! $cipher ) { return $data; @@ -31,7 +31,7 @@ public function encrypt( $data ) { * @inheritDoc */ public function decrypt( $data, $associative = true ) { - $cipher = $this->getCipher(); + $cipher = $this->get_cipher(); if ( ! $cipher ) { return $data; @@ -49,7 +49,7 @@ public function decrypt( $data, $associative = true ) { /** * @inheritDoc */ - public function getCipher() { + public function get_cipher() { if ( in_array( $this->cipher, openssl_get_cipher_methods(), true ) ) { return array( 'cipher' => $this->cipher, diff --git a/includes/class-syndication-encryptor.php b/includes/class-syndication-encryptor.php deleted file mode 100644 index 7ae3ec2d..00000000 --- a/includes/class-syndication-encryptor.php +++ /dev/null @@ -1,27 +0,0 @@ -encryptor->getCipher(); + $cipher = $this->encryptor->get_cipher(); self::assertSame( $expected_cipher, $cipher ); } diff --git a/tests/test-encryptor-openssl.php b/tests/test-encryptor-openssl.php index 42ad62e4..fd5712d8 100644 --- a/tests/test-encryptor-openssl.php +++ b/tests/test-encryptor-openssl.php @@ -22,7 +22,7 @@ public function setUp() { */ public function test_cipher() { // Test the cipher. - $cipher_data = $this->encryptor->getCipher(); + $cipher_data = $this->encryptor->get_cipher(); // Test if is an array. self::assertIsArray( $cipher_data, 'assert if the cipher data is array' ); From 18fa88c23e4fdeeed9e7c143b71cf75a87b86b24 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Tue, 20 Jul 2021 16:41:45 +0100 Subject: [PATCH 17/24] Remove leftover require_once --- includes/push-syndicate-encryption.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/includes/push-syndicate-encryption.php b/includes/push-syndicate-encryption.php index 486397b4..8cbea8ce 100644 --- a/includes/push-syndicate-encryption.php +++ b/includes/push-syndicate-encryption.php @@ -1,7 +1,5 @@ Date: Wed, 21 Jul 2021 15:14:59 +0100 Subject: [PATCH 18/24] Change Syndication_Encryption from a static class to an instantiable class --- includes/class-syndication-encryption.php | 41 ++++++++++++----------- includes/push-syndicate-encryption.php | 6 ++-- push-syndication.php | 11 +++--- tests/test-encryption.php | 17 ++++++---- 4 files changed, 43 insertions(+), 32 deletions(-) diff --git a/includes/class-syndication-encryption.php b/includes/class-syndication-encryption.php index bc9f0208..3df08664 100644 --- a/includes/class-syndication-encryption.php +++ b/includes/class-syndication-encryption.php @@ -10,19 +10,24 @@ class Syndication_Encryption { * * @var Syndication_Encryptor */ - private static $encryptor; + private $encryptor; /** - * Returns the best possible Encryptor, given the current environment. + * Syndication_Encryption constructor. * - * @return Syndication_Encryptor|false + * @param Syndication_Encryptor $encryptor Encryptor to be used. */ - public static function get_encryptor() { - if ( isset( self::$encryptor ) && self::$encryptor instanceof Syndication_Encryptor ) { - return self::$encryptor; - } + public function __construct( Syndication_Encryptor $encryptor ) { + $this->encryptor = $encryptor; + } - return false; + /** + * Returns the best possible Encryptor, given the current environment. + * + * @return Syndication_Encryptor + */ + public function get_encryptor() { + return $this->encryptor; } /** @@ -30,15 +35,11 @@ public static function get_encryptor() { * * @param Syndication_Encryptor $encryptor Encryptor to be used in the encryption. * - * @return Syndication_Encryptor|false Returns the encryptor + * @return Syndication_Encryptor Returns the encryptor */ - public static function set_encryptor( $encryptor ) { - if ( $encryptor instanceof Syndication_Encryptor ) { - self::$encryptor = $encryptor; - return self::$encryptor; - } - - return false; + public function set_encryptor( Syndication_Encryptor $encryptor ) { + $this->encryptor = $encryptor; + return $encryptor; } /** @@ -48,8 +49,8 @@ public static function set_encryptor( $encryptor ) { * * @return false|string */ - public static function encrypt( $data ) { - $encryptor = self::get_encryptor(); + public function encrypt( $data ) { + $encryptor = $this->get_encryptor(); return $encryptor->encrypt( $data ); } @@ -61,8 +62,8 @@ public static function encrypt( $data ) { * * @return false|array|object */ - public static function decrypt( $data, $associative = true ) { - $encryptor = self::get_encryptor(); + public function decrypt( $data, $associative = true ) { + $encryptor = $this->get_encryptor(); return $encryptor->decrypt( $data, $associative ); } diff --git a/includes/push-syndicate-encryption.php b/includes/push-syndicate-encryption.php index 8cbea8ce..1bf801dc 100644 --- a/includes/push-syndicate-encryption.php +++ b/includes/push-syndicate-encryption.php @@ -8,7 +8,8 @@ * @return false|string */ function push_syndicate_encrypt( $data ) { - return Syndication_Encryption::encrypt( $data ); + global $push_syndication_encryption; // @todo: move from global to WP_Push_Syndication_Server attribute + return $push_syndication_encryption->encrypt( $data ); } /** @@ -20,5 +21,6 @@ function push_syndicate_encrypt( $data ) { * @return array|false|object */ function push_syndicate_decrypt( $data, $associative = true ) { - return Syndication_Encryption::decrypt( $data, $associative ); + global $push_syndication_encryption; // @todo: move from global to WP_Push_Syndication_Server attribute + return $push_syndication_encryption->decrypt( $data, $associative ); } diff --git a/push-syndication.php b/push-syndication.php index 96829de7..5a298d41 100644 --- a/push-syndication.php +++ b/push-syndication.php @@ -41,7 +41,7 @@ require __DIR__ . '/includes/class-syndication-site-auto-retry.php'; new Failed_Syndication_Auto_Retry(); -// Load encryption classes +// Load encryption classes. require_once dirname( __FILE__ ) . '/includes/class-syndication-encryption.php'; require_once dirname( __FILE__ ) . '/includes/interface-syndication-encryptor.php'; require_once dirname( __FILE__ ) . '/includes/class-syndication-encryptor-mcrypt.php'; @@ -49,8 +49,11 @@ // On PHP 7.1 mcrypt is available, but will throw a deprecated error if its used. Therefore, checking for the // PHP version, instead of checking for mcrypt is a better approach. -if ( version_compare( PHP_VERSION, '7.1', '<' ) ) { - Syndication_Encryption::set_encryptor( new Syndication_Encryptor_MCrypt() ); +if ( PHP_VERSION_ID < 70100 ) { + $syndication_encryption = new Syndication_Encryption( new Syndication_Encryptor_MCrypt() ); } else { - Syndication_Encryption::set_encryptor( new Syndication_Encryptor_OpenSSL() ); + $syndication_encryption = new Syndication_Encryption( new Syndication_Encryptor_OpenSSL() ); } + +// @TODO: instead of saving this as a global, have it as an attribute of WP_Push_Syndication_Server +$GLOBALS['push_syndication_encryption'] = $syndication_encryption; diff --git a/tests/test-encryption.php b/tests/test-encryption.php index ab1c928e..e3e09a68 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -11,6 +11,7 @@ class EncryptionTest extends WPIntegrationTestCase { private $simple_string; private $complex_array; + private $syndication_encryption; /** * Runs before the test, set-up. @@ -30,6 +31,9 @@ public function setUp() { 1 => 20.04, 3 => true, ); + + global $push_syndication_encryption; + $this->syndication_encryption = $push_syndication_encryption; } /** @@ -38,7 +42,7 @@ public function setUp() { * @requires PHP < 7.1 */ public function test_get_encryptor_before_php_71() { - $encryptor = \Syndication_Encryption::get_encryptor(); + $encryptor = $this->syndication_encryption->get_encryptor(); // If PHP < 7.1, it should be using the mcrypt encryptor. self::assertInstanceOf( \Syndication_Encryptor_MCrypt::class, $encryptor ); @@ -50,7 +54,7 @@ public function test_get_encryptor_before_php_71() { * @requires PHP >= 7.1 */ public function test_get_encryptor_after_php_71() { - $encryptor = \Syndication_Encryption::get_encryptor(); + $encryptor = $this->syndication_encryption->get_encryptor(); // Test if the Encryptor being used is the OpenSSL. self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor ); @@ -60,11 +64,12 @@ public function test_get_encryptor_after_php_71() { * Test if setting the encryptor works as expected */ public function test_set_encryptor() { - $encryptor = \Syndication_Encryption::set_encryptor( new \Syndication_Encryptor_OpenSSL() ); - self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor, 'assert if the encryptor is set' ); + $new_encryptor = $this->syndication_encryption->set_encryptor( new \Syndication_Encryptor_OpenSSL() ); + self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $new_encryptor, 'assert if the encryptor is set' ); - $encryptor = \Syndication_Encryption::set_encryptor( new \stdClass() ); - self::assertFalse( $encryptor, 'assert if invalid encryptor returns false' ); + $encryptor = $this->syndication_encryption->get_encryptor(); + self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor, 'assert if the encryptor is set' ); + self::assertEquals( $new_encryptor, $encryptor, 'assert if the set encryptor is the same as the one retrieved' ); } /** From d418b9cfeecf9c21f47f671dbddbeb50a278cb82 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Wed, 21 Jul 2021 15:20:31 +0100 Subject: [PATCH 19/24] Add extra validation for older PHP versions (<5.2.7), just in case. --- push-syndication.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/push-syndication.php b/push-syndication.php index 5a298d41..f58745fe 100644 --- a/push-syndication.php +++ b/push-syndication.php @@ -49,7 +49,7 @@ // On PHP 7.1 mcrypt is available, but will throw a deprecated error if its used. Therefore, checking for the // PHP version, instead of checking for mcrypt is a better approach. -if ( PHP_VERSION_ID < 70100 ) { +if ( ! defined( 'PHP_VERSION_ID' ) || PHP_VERSION_ID < 70100 ) { $syndication_encryption = new Syndication_Encryption( new Syndication_Encryptor_MCrypt() ); } else { $syndication_encryption = new Syndication_Encryption( new Syndication_Encryptor_OpenSSL() ); From 4e3873bab736c7b52f08a346c12c4fbd83f5455b Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Fri, 23 Jul 2021 16:16:20 +0100 Subject: [PATCH 20/24] Remove encryptor strategy getters and setters --- includes/class-syndication-encryption.php | 27 ++--------------------- 1 file changed, 2 insertions(+), 25 deletions(-) diff --git a/includes/class-syndication-encryption.php b/includes/class-syndication-encryption.php index 3df08664..a9333db9 100644 --- a/includes/class-syndication-encryption.php +++ b/includes/class-syndication-encryption.php @@ -21,27 +21,6 @@ public function __construct( Syndication_Encryptor $encryptor ) { $this->encryptor = $encryptor; } - /** - * Returns the best possible Encryptor, given the current environment. - * - * @return Syndication_Encryptor - */ - public function get_encryptor() { - return $this->encryptor; - } - - /** - * Set the Encryptor that will be used for the encryption and decryption operations. - * - * @param Syndication_Encryptor $encryptor Encryptor to be used in the encryption. - * - * @return Syndication_Encryptor Returns the encryptor - */ - public function set_encryptor( Syndication_Encryptor $encryptor ) { - $this->encryptor = $encryptor; - return $encryptor; - } - /** * Given $data, encrypt it using a Syndication_Encryptor and return the encrypted string. * @@ -50,8 +29,7 @@ public function set_encryptor( Syndication_Encryptor $encryptor ) { * @return false|string */ public function encrypt( $data ) { - $encryptor = $this->get_encryptor(); - return $encryptor->encrypt( $data ); + return $this->encryptor->encrypt( $data ); } /** @@ -63,8 +41,7 @@ public function encrypt( $data ) { * @return false|array|object */ public function decrypt( $data, $associative = true ) { - $encryptor = $this->get_encryptor(); - return $encryptor->decrypt( $data, $associative ); + return $this->encryptor->decrypt( $data, $associative ); } } From 16ec5b8af6e0dae7ab523112e1910bc749491413 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Fri, 23 Jul 2021 16:34:18 +0100 Subject: [PATCH 21/24] Address feedback on Encryption_Test --- tests/test-encryption.php | 51 ++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index e3e09a68..9ebbbfce 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -5,13 +5,11 @@ /** * Class EncryptionTest - * */ class EncryptionTest extends WPIntegrationTestCase { private $simple_string; private $complex_array; - private $syndication_encryption; /** * Runs before the test, set-up. @@ -31,45 +29,42 @@ public function setUp() { 1 => 20.04, 3 => true, ); - - global $push_syndication_encryption; - $this->syndication_encryption = $push_syndication_encryption; } /** * Test if the encryptor being used with PHP 7.1 or older is the mcrypt encryptor. * - * @requires PHP < 7.1 + * @requires module mcrypt */ - public function test_get_encryptor_before_php_71() { - $encryptor = $this->syndication_encryption->get_encryptor(); + public function test_new_encryption_instance_with_mcrypt() { + $syndication_encryption = new \Syndication_Encryption( new \Syndication_Encryptor_MCrypt() ); - // If PHP < 7.1, it should be using the mcrypt encryptor. - self::assertInstanceOf( \Syndication_Encryptor_MCrypt::class, $encryptor ); - } + // Disable deprecated warnings for PHP 7.. + $original_error_reporting = error_reporting( error_reporting() & ~E_DEPRECATED ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting - /** - * Test if the encryptor being used with newer PHP is OpenSSL encryptor. - * - * @requires PHP >= 7.1 - */ - public function test_get_encryptor_after_php_71() { - $encryptor = $this->syndication_encryption->get_encryptor(); + // Quick encryption/decryption test. + $quick_test_string = 'This is a quick test.'; + $encrypted = $syndication_encryption->encrypt( $quick_test_string ); + $decrypted = $syndication_encryption->decrypt( $encrypted ); + self::assertEquals( $encrypted, $syndication_encryption->encrypt( $quick_test_string ), 'assert that encryption results are consistent' ); + self::assertEquals( $quick_test_string, $decrypted, 'assert that decrypted string is the same as original' ); - // Test if the Encryptor being used is the OpenSSL. - self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor ); + // Restore original error reporting. + error_reporting( $original_error_reporting ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting } /** - * Test if setting the encryptor works as expected + * Test if the encryptor being used with newer PHP is OpenSSL encryptor. */ - public function test_set_encryptor() { - $new_encryptor = $this->syndication_encryption->set_encryptor( new \Syndication_Encryptor_OpenSSL() ); - self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $new_encryptor, 'assert if the encryptor is set' ); - - $encryptor = $this->syndication_encryption->get_encryptor(); - self::assertInstanceOf( \Syndication_Encryptor_OpenSSL::class, $encryptor, 'assert if the encryptor is set' ); - self::assertEquals( $new_encryptor, $encryptor, 'assert if the set encryptor is the same as the one retrieved' ); + public function test_new_encryption_instance_with_openssl() { + $syndication_encryption = new \Syndication_Encryption( new \Syndication_Encryptor_OpenSSL() ); + + // Quick encryption/decryption test. + $quick_test_string = 'This is a quick test.'; + $encrypted = $syndication_encryption->encrypt( $quick_test_string ); + $decrypted = $syndication_encryption->decrypt( $encrypted ); + self::assertEquals( $encrypted, $syndication_encryption->encrypt( $quick_test_string ), 'assert that encryption results are consistent' ); + self::assertEquals( $quick_test_string, $decrypted, 'assert that decrypted string is the same as original' ); } /** From c9f684e1b9907a8e80ffc5311b0d987ef31fe5b2 Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Fri, 23 Jul 2021 16:37:08 +0100 Subject: [PATCH 22/24] Correction on the tests PHPDOC --- tests/test-encryption.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index 9ebbbfce..dde74b87 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -32,9 +32,9 @@ public function setUp() { } /** - * Test if the encryptor being used with PHP 7.1 or older is the mcrypt encryptor. + * Test new instance of Syndication_Encryption with the MCrypt strategy. * - * @requires module mcrypt + * @requires extension mcrypt */ public function test_new_encryption_instance_with_mcrypt() { $syndication_encryption = new \Syndication_Encryption( new \Syndication_Encryptor_MCrypt() ); @@ -54,7 +54,7 @@ public function test_new_encryption_instance_with_mcrypt() { } /** - * Test if the encryptor being used with newer PHP is OpenSSL encryptor. + * Test new instance of Syndication_Encryption with the OpenSSL strategy. */ public function test_new_encryption_instance_with_openssl() { $syndication_encryption = new \Syndication_Encryption( new \Syndication_Encryptor_OpenSSL() ); From 1f6b87c39ca4a758e0bf1f93bfd60a1e2957ff1d Mon Sep 17 00:00:00 2001 From: Henrique Mouta Date: Wed, 28 Jul 2021 17:04:24 +0100 Subject: [PATCH 23/24] Change EncryptionTest to test the `encrypt` and `decrypt` methods. --- tests/test-encryption.php | 42 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/tests/test-encryption.php b/tests/test-encryption.php index dde74b87..2714234f 100644 --- a/tests/test-encryption.php +++ b/tests/test-encryption.php @@ -32,39 +32,31 @@ public function setUp() { } /** - * Test new instance of Syndication_Encryption with the MCrypt strategy. - * - * @requires extension mcrypt + * Test if the `encrypt` method on Syndication_Encryption calls the `encrypt` method on the specific Syndication_Encryptor */ - public function test_new_encryption_instance_with_mcrypt() { - $syndication_encryption = new \Syndication_Encryption( new \Syndication_Encryptor_MCrypt() ); + public function test_encrypt_method_is_called_on_encryptor_object() { + $fake_encrypted_string = 'I\'m an encrypted string.'; - // Disable deprecated warnings for PHP 7.. - $original_error_reporting = error_reporting( error_reporting() & ~E_DEPRECATED ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting + $mock_encryptor = $this->createMock( \Syndication_Encryptor::class ); + $mock_encryptor->method( 'encrypt' )->will( $this->returnValue( $fake_encrypted_string ) ); - // Quick encryption/decryption test. - $quick_test_string = 'This is a quick test.'; - $encrypted = $syndication_encryption->encrypt( $quick_test_string ); - $decrypted = $syndication_encryption->decrypt( $encrypted ); - self::assertEquals( $encrypted, $syndication_encryption->encrypt( $quick_test_string ), 'assert that encryption results are consistent' ); - self::assertEquals( $quick_test_string, $decrypted, 'assert that decrypted string is the same as original' ); + $syndication_encryption = new \Syndication_Encryption( $mock_encryptor ); - // Restore original error reporting. - error_reporting( $original_error_reporting ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting + self::assertSame( $fake_encrypted_string, $syndication_encryption->encrypt( 'I am a plain-text string' ) ); } /** - * Test new instance of Syndication_Encryption with the OpenSSL strategy. + * Test if the `decrypt` method on Syndication_Encryption calls the `decrypt` method on the specific Syndication_Encryptor */ - public function test_new_encryption_instance_with_openssl() { - $syndication_encryption = new \Syndication_Encryption( new \Syndication_Encryptor_OpenSSL() ); - - // Quick encryption/decryption test. - $quick_test_string = 'This is a quick test.'; - $encrypted = $syndication_encryption->encrypt( $quick_test_string ); - $decrypted = $syndication_encryption->decrypt( $encrypted ); - self::assertEquals( $encrypted, $syndication_encryption->encrypt( $quick_test_string ), 'assert that encryption results are consistent' ); - self::assertEquals( $quick_test_string, $decrypted, 'assert that decrypted string is the same as original' ); + public function test_decrypt_method_is_called_on_encryptor_object() { + $fake_plain_text_string = 'I am a plain-text string.'; + + $mock_encryptor = $this->createMock( \Syndication_Encryptor::class ); + $mock_encryptor->method( 'decrypt' )->will( $this->returnValue( $fake_plain_text_string ) ); + + $syndication_encryption = new \Syndication_Encryption( $mock_encryptor ); + + self::assertSame( $fake_plain_text_string, $syndication_encryption->decrypt( 'I\'m an encrypted string.' ) ); } /** From 9a3434dae64d23a2042ad869b1bf4587318a8d86 Mon Sep 17 00:00:00 2001 From: Gary Jones Date: Sun, 11 Feb 2024 11:37:17 +0000 Subject: [PATCH 24/24] Fix DocBlock --- includes/class-syndication-encryptor-mcrypt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/class-syndication-encryptor-mcrypt.php b/includes/class-syndication-encryptor-mcrypt.php index 02249f6f..24b48c23 100644 --- a/includes/class-syndication-encryptor-mcrypt.php +++ b/includes/class-syndication-encryptor-mcrypt.php @@ -1,7 +1,7 @@