From 508eaa7197f254d015d75744d552255fcec0ce57 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sun, 5 Feb 2023 17:33:16 -0600 Subject: [PATCH 1/2] Tests: PHPUnit 10 updates --- .github/workflows/ci.yml | 9 +++-- tests/Functional/Net/SSH2Test.php | 1 + tests/PhpseclibTestCase.php | 36 +------------------ tests/Unit/Crypt/HashTest.php | 8 ++--- tests/Unit/Net/SSH2UnitTest.php | 19 ++++++++++ ....php => make_compatible_with_phpunit7.php} | 13 ++++--- tests/make_compatible_with_phpunit9.php | 23 ++++++++++++ 7 files changed, 60 insertions(+), 49 deletions(-) rename tests/{make_compatible_with_new_phpunit_versions.php => make_compatible_with_phpunit7.php} (65%) mode change 100755 => 100644 create mode 100644 tests/make_compatible_with_phpunit9.php diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ea04cc0..a24ccacf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,9 +58,12 @@ jobs: php-version: ${{ matrix.php-version }} - name: Composer Install run: composer install --classmap-authoritative --no-interaction --no-cache - - name: Make Tests Compatiable With New PHPUnit Versions + - name: Make Tests Compatiable With PHPUnit 7+ if: matrix.php-version != '5.6' && matrix.php-version != '7.0' - run: php tests/make_compatible_with_new_phpunit_versions.php + run: php tests/make_compatible_with_phpunit7.php + - name: Make Tests Compatiable With PHPUnit 9+ + if: matrix.php-version != '5.6' && matrix.php-version != '7.0' && matrix.php-version != '7.1' && matrix.php-version != '7.2' + run: php tests/make_compatible_with_phpunit9.php - name: Setup Secure Shell Functional Tests if: matrix.os == 'ubuntu-latest' run: | @@ -84,7 +87,7 @@ jobs: echo "PHPSECLIB_SSH_HOME=/home/phpseclib" >> $GITHUB_ENV echo "SSH_AUTH_SOCK=$SSH_AUTH_SOCK" >> $GITHUB_ENV - name: PHPUnit - run: vendor/bin/phpunit --verbose --configuration tests/phpunit.xml + run: vendor/bin/phpunit --configuration tests/phpunit.xml strategy: fail-fast: false matrix: diff --git a/tests/Functional/Net/SSH2Test.php b/tests/Functional/Net/SSH2Test.php index 0995ded4..632ab1cb 100644 --- a/tests/Functional/Net/SSH2Test.php +++ b/tests/Functional/Net/SSH2Test.php @@ -108,6 +108,7 @@ class SSH2Test extends PhpseclibFunctionalTestCase /** * @depends testPasswordLogin * @group github280 + * @requires PHPUnit < 10 */ public function testExecWithMethodCallback(SSH2 $ssh) { diff --git a/tests/PhpseclibTestCase.php b/tests/PhpseclibTestCase.php index f40f395f..68108791 100644 --- a/tests/PhpseclibTestCase.php +++ b/tests/PhpseclibTestCase.php @@ -105,66 +105,36 @@ abstract class PhpseclibTestCase extends TestCase // assertIsArray was not introduced until PHPUnit 8 public static function assertIsArray($actual, $message = '') { - if (method_exists(parent::class, 'assertIsArray')) { - parent::assertIsArray($actual, $message); - return; - } - parent::assertInternalType('array', $actual, $message); } // assertIsString was not introduced until PHPUnit 8 public static function assertIsString($actual, $message = '') { - if (method_exists(parent::class, 'assertIsString')) { - parent::assertIsString($actual, $message); - return; - } - parent::assertInternalType('string', $actual, $message); } // assertIsResource was not introduced until PHPUnit 8 public static function assertIsResource($actual, $message = '') { - if (method_exists(parent::class, 'assertIsResource')) { - parent::assertIsResource($actual, $message); - return; - } - parent::assertInternalType('resource', $actual, $message); } // assertIsObject was not introduced until PHPUnit 8 public static function assertIsObject($actual, $message = '') { - if (method_exists(parent::class, 'assertIsObject')) { - parent::assertIsObject($actual, $message); - return; - } - parent::assertInternalType('object', $actual, $message); } // assertContains is deprecated for strings in PHPUnit 8 public static function assertStringContainsString($needle, $haystack, $message = '') { - if (method_exists(parent::class, 'assertStringContainsString')) { - parent::assertStringContainsString($needle, $haystack, $message); - return; - } - parent::assertContains($needle, $haystack, $message); } // assertNotContains is deprecated for strings in PHPUnit 8 public static function assertStringNotContainsString($needle, $haystack, $message = '') { - if (method_exists(parent::class, 'assertStringContainsString')) { - parent::assertStringNotContainsString($needle, $haystack, $message); - return; - } - parent::assertNotContains($needle, $haystack, $message); } @@ -178,10 +148,6 @@ abstract class PhpseclibTestCase extends TestCase */ public static function assertMatchesRegularExpression($pattern, $string, $message = '') { - if (method_exists(parent::class, 'assertMatchesRegularExpression')) { - parent::assertMatchesRegularExpression($pattern, $string, $message); - } else { - parent::assertRegExp($pattern, $string, $message); - } + parent::assertRegExp($pattern, $string, $message); } } diff --git a/tests/Unit/Crypt/HashTest.php b/tests/Unit/Crypt/HashTest.php index 836fcbfb..a2b5f711 100644 --- a/tests/Unit/Crypt/HashTest.php +++ b/tests/Unit/Crypt/HashTest.php @@ -169,7 +169,7 @@ class HashTest extends PhpseclibTestCase } /** - * @dataProvider hmacData() + * @dataProvider hmacData */ public function testHMAC($hash, $key, $message, $result) { @@ -177,7 +177,7 @@ class HashTest extends PhpseclibTestCase } /** - * @dataProvider hmacData() + * @dataProvider hmacData */ public function testHMAC96($hash, $key, $message, $result) { @@ -370,7 +370,7 @@ class HashTest extends PhpseclibTestCase } /** - * @dataProvider hashData() + * @dataProvider hashData */ public function testHash($hash, $message, $result) { @@ -378,7 +378,7 @@ class HashTest extends PhpseclibTestCase } /** - * @dataProvider hashData() + * @dataProvider hashData */ public function testHash96($hash, $message, $result) { diff --git a/tests/Unit/Net/SSH2UnitTest.php b/tests/Unit/Net/SSH2UnitTest.php index 21e22be7..7d3e154e 100644 --- a/tests/Unit/Net/SSH2UnitTest.php +++ b/tests/Unit/Net/SSH2UnitTest.php @@ -31,6 +31,7 @@ class SSH2UnitTest extends PhpseclibTestCase /** * @dataProvider formatLogDataProvider + * @requires PHPUnit < 10 */ public function testFormatLog(array $message_log, array $message_number_log, $expected) { @@ -40,6 +41,9 @@ class SSH2UnitTest extends PhpseclibTestCase $this->assertEquals($expected, $result); } + /** + * @requires PHPUnit < 10 + */ public function testGenerateIdentifier() { $identifier = self::callFunc($this->createSSHMock(), 'generate_identifier'); @@ -72,6 +76,9 @@ class SSH2UnitTest extends PhpseclibTestCase } } + /** + * @requires PHPUnit < 10 + */ public function testGetExitStatusIfNotConnected() { $ssh = $this->createSSHMock(); @@ -79,12 +86,18 @@ class SSH2UnitTest extends PhpseclibTestCase $this->assertFalse($ssh->getExitStatus()); } + /** + * @requires PHPUnit < 10 + */ public function testPTYIDefaultValue() { $ssh = $this->createSSHMock(); $this->assertFalse($ssh->isPTYEnabled()); } + /** + * @requires PHPUnit < 10 + */ public function testEnablePTY() { $ssh = $this->createSSHMock(); @@ -96,6 +109,9 @@ class SSH2UnitTest extends PhpseclibTestCase $this->assertFalse($ssh->isPTYEnabled()); } + /** + * @requires PHPUnit < 10 + */ public function testQuietModeDefaultValue() { $ssh = $this->createSSHMock(); @@ -103,6 +119,9 @@ class SSH2UnitTest extends PhpseclibTestCase $this->assertFalse($ssh->isQuietModeEnabled()); } + /** + * @requires PHPUnit < 10 + */ public function testEnableQuietMode() { $ssh = $this->createSSHMock(); diff --git a/tests/make_compatible_with_new_phpunit_versions.php b/tests/make_compatible_with_phpunit7.php old mode 100755 new mode 100644 similarity index 65% rename from tests/make_compatible_with_new_phpunit_versions.php rename to tests/make_compatible_with_phpunit7.php index e9448b6c..deb68aca --- a/tests/make_compatible_with_new_phpunit_versions.php +++ b/tests/make_compatible_with_phpunit7.php @@ -12,13 +12,12 @@ foreach ($files as $file) { '~ function setUpBeforeClass\(\)~' => ' function setUpBeforeClass(): void', '~ function setUp\(\)~' => ' function setUp(): void', '~ function tearDown\(\)~' => ' function tearDown(): void', - '~ function assertIsArray\(\$actual, \$message = \'\'\)~' => ' function assertIsArray($actual, string $message = \'\'): void', - '~ function assertIsResource\(\$actual, \$message = \'\'\)~' => ' function assertIsResource($actual, string $message = \'\'): void', - '~ function assertIsObject\(\$actual, \$message = \'\'\)~' => ' function assertIsObject($actual, string $message = \'\'): void', - '~ function assertIsString\(\$actual, \$message = \'\'\)~' => ' function assertIsString($actual, string $message = \'\'): void', - '~ function assertStringContainsString\(\$needle, \$haystack, \$message = \'\'\)~' => ' function assertStringContainsString(string $needle, string $haystack, string $message = \'\'): void', - '~ function assertStringNotContainsString\(\$needle, \$haystack, \$message = \'\'\)~' => ' function assertStringNotContainsString(string $needle, string $haystack, string $message = \'\'): void', - '~ function assertMatchesRegularExpression\(\$pattern, \$string, \$message = \'\'\)~' => ' function assertMatchesRegularExpression(string $pattern, string $string, string $message = \'\'): void', + '~ function assertIsArray\(\$actual, \$message = \'\'\)~' => ' function _assertIsArray($actual, string $message = \'\')', + '~ function assertIsResource\(\$actual, \$message = \'\'\)~' => ' function _assertIsResource($actual, string $message = \'\')', + '~ function assertIsObject\(\$actual, \$message = \'\'\)~' => ' function _assertIsObject($actual, string $message = \'\')', + '~ function assertIsString\(\$actual, \$message = \'\'\)~' => ' function _assertIsString($actual, string $message = \'\')', + '~ function assertStringContainsString\(\$needle, \$haystack, \$message = \'\'\)~' => ' function _assertStringContainsString(string $needle, string $haystack, string $message = \'\')', + '~ function assertStringNotContainsString\(\$needle, \$haystack, \$message = \'\'\)~' => ' function _assertStringNotContainsString(string $needle, string $haystack, string $message = \'\')' ]; $updatedFileContents = preg_replace( array_keys($patternToReplacementMap), diff --git a/tests/make_compatible_with_phpunit9.php b/tests/make_compatible_with_phpunit9.php new file mode 100644 index 00000000..db04795d --- /dev/null +++ b/tests/make_compatible_with_phpunit9.php @@ -0,0 +1,23 @@ + $files */ +$files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__)); +foreach ($files as $file) { + if ($file->getExtension() === 'php' && $file->getPathname() !== __FILE__) { + $fileContents = file_get_contents($file->getPathname()); + if ($fileContents === false) { + throw new \RuntimeException('file_get_contents() failed: ' . $file->getPathname()); + } + $patternToReplacementMap = [ + '~ function assertMatchesRegularExpression\(\$pattern, \$string, \$message = \'\'\)~' => ' function _assertMatchesRegularExpression(string $pattern, string $string, string $message = \'\')', + ]; + $updatedFileContents = preg_replace( + array_keys($patternToReplacementMap), + array_values($patternToReplacementMap), + $fileContents + ); + if (file_put_contents($file->getPathname(), $updatedFileContents) === false) { + throw new \RuntimeException('file_put_contents() failed: ' . $file->getPathname()); + } + } +} From 2487192558c893cf553648269215c1c5fdf11809 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sun, 5 Feb 2023 17:44:51 -0600 Subject: [PATCH 2/2] AsymmetricKey: error out on unsupported operations --- phpseclib/Crypt/Common/AsymmetricKey.php | 5 +++++ phpseclib/Crypt/DH.php | 14 ++++++++++++-- phpseclib/Crypt/DH/Parameters.php | 2 +- phpseclib/Crypt/DH/PrivateKey.php | 2 +- phpseclib/Crypt/DH/PublicKey.php | 2 +- phpseclib/Crypt/DSA.php | 10 ++++++++++ phpseclib/Crypt/DSA/Parameters.php | 2 +- phpseclib/Crypt/DSA/PrivateKey.php | 2 +- phpseclib/Crypt/DSA/PublicKey.php | 2 +- phpseclib/Crypt/EC.php | 5 +++++ phpseclib/Crypt/EC/Parameters.php | 2 +- phpseclib/Crypt/EC/PrivateKey.php | 2 +- phpseclib/Crypt/EC/PublicKey.php | 2 +- phpseclib/Crypt/RSA.php | 5 +++++ phpseclib/Crypt/RSA/PrivateKey.php | 2 +- phpseclib/Crypt/RSA/PublicKey.php | 2 +- 16 files changed, 48 insertions(+), 13 deletions(-) diff --git a/phpseclib/Crypt/Common/AsymmetricKey.php b/phpseclib/Crypt/Common/AsymmetricKey.php index a261dfc4..407f0369 100644 --- a/phpseclib/Crypt/Common/AsymmetricKey.php +++ b/phpseclib/Crypt/Common/AsymmetricKey.php @@ -136,6 +136,11 @@ abstract class AsymmetricKey { self::initialize_static_variables(); + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('load() should not be called from final classes (' . static::class . ')'); + } + $components = false; foreach (self::$plugins[static::ALGORITHM]['Keys'] as $format) { if (isset(self::$invisiblePlugins[static::ALGORITHM]) && in_array($format, self::$invisiblePlugins[static::ALGORITHM])) { diff --git a/phpseclib/Crypt/DH.php b/phpseclib/Crypt/DH.php index 876cdbf8..e1deaf08 100644 --- a/phpseclib/Crypt/DH.php +++ b/phpseclib/Crypt/DH.php @@ -81,6 +81,11 @@ abstract class DH extends AsymmetricKey */ public static function createParameters(...$args) { + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')'); + } + $params = new Parameters(); if (count($args) == 2 && $args[0] instanceof BigInteger && $args[1] instanceof BigInteger) { //if (!$args[0]->isPrime()) { @@ -242,6 +247,11 @@ abstract class DH extends AsymmetricKey */ public static function createKey(Parameters $params, $length = 0) { + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); + } + $one = new BigInteger(1); if ($length) { $max = $one->bitwise_leftShift($length); @@ -387,9 +397,9 @@ abstract class DH extends AsymmetricKey */ public function getParameters() { - $type = self::validatePlugin('Keys', 'PKCS1', 'saveParameters'); + $type = DH::validatePlugin('Keys', 'PKCS1', 'saveParameters'); $key = $type::saveParameters($this->prime, $this->base); - return self::load($key, 'PKCS1'); + return DH::load($key, 'PKCS1'); } } diff --git a/phpseclib/Crypt/DH/Parameters.php b/phpseclib/Crypt/DH/Parameters.php index e4c15576..c0ded84c 100644 --- a/phpseclib/Crypt/DH/Parameters.php +++ b/phpseclib/Crypt/DH/Parameters.php @@ -18,7 +18,7 @@ use phpseclib3\Crypt\DH; * * @author Jim Wigginton */ -class Parameters extends DH +final class Parameters extends DH { /** * Returns the parameters diff --git a/phpseclib/Crypt/DH/PrivateKey.php b/phpseclib/Crypt/DH/PrivateKey.php index fe03452c..737781f8 100644 --- a/phpseclib/Crypt/DH/PrivateKey.php +++ b/phpseclib/Crypt/DH/PrivateKey.php @@ -19,7 +19,7 @@ use phpseclib3\Crypt\DH; * * @author Jim Wigginton */ -class PrivateKey extends DH +final class PrivateKey extends DH { use Common\Traits\PasswordProtected; diff --git a/phpseclib/Crypt/DH/PublicKey.php b/phpseclib/Crypt/DH/PublicKey.php index 3536360c..87726a5a 100644 --- a/phpseclib/Crypt/DH/PublicKey.php +++ b/phpseclib/Crypt/DH/PublicKey.php @@ -19,7 +19,7 @@ use phpseclib3\Crypt\DH; * * @author Jim Wigginton */ -class PublicKey extends DH +final class PublicKey extends DH { use Common\Traits\Fingerprint; diff --git a/phpseclib/Crypt/DSA.php b/phpseclib/Crypt/DSA.php index 1d265860..0123c66c 100644 --- a/phpseclib/Crypt/DSA.php +++ b/phpseclib/Crypt/DSA.php @@ -105,6 +105,11 @@ abstract class DSA extends AsymmetricKey { self::initialize_static_variables(); + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('createParameters() should not be called from final classes (' . static::class . ')'); + } + if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } @@ -180,6 +185,11 @@ abstract class DSA extends AsymmetricKey { self::initialize_static_variables(); + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); + } + if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } diff --git a/phpseclib/Crypt/DSA/Parameters.php b/phpseclib/Crypt/DSA/Parameters.php index 6bcb152d..84d16ba6 100644 --- a/phpseclib/Crypt/DSA/Parameters.php +++ b/phpseclib/Crypt/DSA/Parameters.php @@ -18,7 +18,7 @@ use phpseclib3\Crypt\DSA; * * @author Jim Wigginton */ -class Parameters extends DSA +final class Parameters extends DSA { /** * Returns the parameters diff --git a/phpseclib/Crypt/DSA/PrivateKey.php b/phpseclib/Crypt/DSA/PrivateKey.php index 7039941b..74d3e69e 100644 --- a/phpseclib/Crypt/DSA/PrivateKey.php +++ b/phpseclib/Crypt/DSA/PrivateKey.php @@ -21,7 +21,7 @@ use phpseclib3\Math\BigInteger; * * @author Jim Wigginton */ -class PrivateKey extends DSA implements Common\PrivateKey +final class PrivateKey extends DSA implements Common\PrivateKey { use Common\Traits\PasswordProtected; diff --git a/phpseclib/Crypt/DSA/PublicKey.php b/phpseclib/Crypt/DSA/PublicKey.php index 7e00e24a..c14ffbdf 100644 --- a/phpseclib/Crypt/DSA/PublicKey.php +++ b/phpseclib/Crypt/DSA/PublicKey.php @@ -20,7 +20,7 @@ use phpseclib3\Crypt\DSA\Formats\Signature\ASN1 as ASN1Signature; * * @author Jim Wigginton */ -class PublicKey extends DSA implements Common\PublicKey +final class PublicKey extends DSA implements Common\PublicKey { use Common\Traits\Fingerprint; diff --git a/phpseclib/Crypt/EC.php b/phpseclib/Crypt/EC.php index e61f0092..10b38254 100644 --- a/phpseclib/Crypt/EC.php +++ b/phpseclib/Crypt/EC.php @@ -140,6 +140,11 @@ abstract class EC extends AsymmetricKey { self::initialize_static_variables(); + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); + } + if (!isset(self::$engines['PHP'])) { self::useBestEngine(); } diff --git a/phpseclib/Crypt/EC/Parameters.php b/phpseclib/Crypt/EC/Parameters.php index c9bf1bea..c0ed64a8 100644 --- a/phpseclib/Crypt/EC/Parameters.php +++ b/phpseclib/Crypt/EC/Parameters.php @@ -18,7 +18,7 @@ use phpseclib3\Crypt\EC; * * @author Jim Wigginton */ -class Parameters extends EC +final class Parameters extends EC { /** * Returns the parameters diff --git a/phpseclib/Crypt/EC/PrivateKey.php b/phpseclib/Crypt/EC/PrivateKey.php index 8bf86862..462ea1a3 100644 --- a/phpseclib/Crypt/EC/PrivateKey.php +++ b/phpseclib/Crypt/EC/PrivateKey.php @@ -29,7 +29,7 @@ use phpseclib3\Math\BigInteger; * * @author Jim Wigginton */ -class PrivateKey extends EC implements Common\PrivateKey +final class PrivateKey extends EC implements Common\PrivateKey { use Common\Traits\PasswordProtected; diff --git a/phpseclib/Crypt/EC/PublicKey.php b/phpseclib/Crypt/EC/PublicKey.php index 609d5960..4558ce34 100644 --- a/phpseclib/Crypt/EC/PublicKey.php +++ b/phpseclib/Crypt/EC/PublicKey.php @@ -28,7 +28,7 @@ use phpseclib3\Math\BigInteger; * * @author Jim Wigginton */ -class PublicKey extends EC implements Common\PublicKey +final class PublicKey extends EC implements Common\PublicKey { use Common\Traits\Fingerprint; diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index 207a9051..7b935cc2 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -304,6 +304,11 @@ abstract class RSA extends AsymmetricKey { self::initialize_static_variables(); + $class = new \ReflectionClass(static::class); + if ($class->isFinal()) { + throw new \RuntimeException('createKey() should not be called from final classes (' . static::class . ')'); + } + $regSize = $bits >> 1; // divide by two to see how many bits P and Q would be if ($regSize > self::$smallestPrime) { $num_primes = floor($bits / self::$smallestPrime); diff --git a/phpseclib/Crypt/RSA/PrivateKey.php b/phpseclib/Crypt/RSA/PrivateKey.php index 84cede8e..37dd09a4 100644 --- a/phpseclib/Crypt/RSA/PrivateKey.php +++ b/phpseclib/Crypt/RSA/PrivateKey.php @@ -23,7 +23,7 @@ use phpseclib3\Math\BigInteger; * * @author Jim Wigginton */ -class PrivateKey extends RSA implements Common\PrivateKey +final class PrivateKey extends RSA implements Common\PrivateKey { use Common\Traits\PasswordProtected; diff --git a/phpseclib/Crypt/RSA/PublicKey.php b/phpseclib/Crypt/RSA/PublicKey.php index 89408792..58939a9f 100644 --- a/phpseclib/Crypt/RSA/PublicKey.php +++ b/phpseclib/Crypt/RSA/PublicKey.php @@ -28,7 +28,7 @@ use phpseclib3\Math\BigInteger; * * @author Jim Wigginton */ -class PublicKey extends RSA implements Common\PublicKey +final class PublicKey extends RSA implements Common\PublicKey { use Common\Traits\Fingerprint;