From be3b4984d6f726241e3f9669587e349fc5dba671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Malte=20Schlu=CC=88ter?= Date: Tue, 17 Oct 2023 14:05:33 +0200 Subject: [PATCH] [DowngradePhp81] Downgrade hash algorithm --- config/set/downgrade-php81.php | 4 +- ...DowngradeHashAlgorithmXxHashRectorTest.php | 28 +++ .../Fixture/fixture_configured_value.php.inc | 27 +++ .../Fixture/fixture_constant.php.inc | 27 +++ .../Fixture/fixture_named_arguments.php.inc | 27 +++ ...ixture_named_arguments_false_order.php.inc | 27 +++ .../Fixture/fixture_xxh128.php.inc | 27 +++ .../Fixture/fixture_xxh32.php.inc | 27 +++ .../Fixture/fixture_xxh64.php.inc | 27 +++ .../Fixture/skip_different_func_call.php.inc | 11 + .../skip_has_allowed_algorithm.php.inc | 11 + .../config/configured_rule.php | 12 ++ .../DowngradeHashAlgorithmXxHashRector.php | 194 ++++++++++++++++++ 13 files changed, 448 insertions(+), 1 deletion(-) create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/DowngradeHashAlgorithmXxHashRectorTest.php create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_configured_value.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_constant.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments_false_order.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh128.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh32.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh64.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/skip_different_func_call.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/skip_has_allowed_algorithm.php.inc create mode 100644 rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/config/configured_rule.php create mode 100644 rules/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHashRector.php diff --git a/config/set/downgrade-php81.php b/config/set/downgrade-php81.php index 67b3c8f1..7df8e4a4 100644 --- a/config/set/downgrade-php81.php +++ b/config/set/downgrade-php81.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use Rector\DowngradePhp81\Rector\FuncCall\DowngradeHashAlgorithmXxHashRector; use Rector\DowngradePhp81\Rector\LNumber\DowngradeOctalNumberRector; use Rector\DowngradePhp81\Rector\MethodCall\DowngradeIsEnumRector; use Rector\Config\RectorConfig; @@ -35,7 +36,8 @@ DowngradeArrayIsListRector::class, DowngradeSetAccessibleReflectionPropertyRector::class, DowngradeIsEnumRector::class, - DowngradeOctalNumberRector::class + DowngradeOctalNumberRector::class, + DowngradeHashAlgorithmXxHashRector::class, ]); // @see https://php.watch/versions/8.1/internal-method-return-types#reflection diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/DowngradeHashAlgorithmXxHashRectorTest.php b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/DowngradeHashAlgorithmXxHashRectorTest.php new file mode 100644 index 00000000..570432b4 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/DowngradeHashAlgorithmXxHashRectorTest.php @@ -0,0 +1,28 @@ +doTestFile($filePath); + } + + public static function provideData(): Iterator + { + return self::yieldFilesFromDirectory(__DIR__ . '/Fixture'); + } + + public function provideConfigFilePath(): string + { + return __DIR__ . '/config/configured_rule.php'; + } +} diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_configured_value.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_configured_value.php.inc new file mode 100644 index 00000000..2434487a --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_configured_value.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_constant.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_constant.php.inc new file mode 100644 index 00000000..8cc6c094 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_constant.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments.php.inc new file mode 100644 index 00000000..ca6b1440 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments_false_order.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments_false_order.php.inc new file mode 100644 index 00000000..9cbbaba3 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_named_arguments_false_order.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh128.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh128.php.inc new file mode 100644 index 00000000..e4c0e887 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh128.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh32.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh32.php.inc new file mode 100644 index 00000000..d7e39dd2 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh32.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh64.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh64.php.inc new file mode 100644 index 00000000..a9937f95 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/fixture_xxh64.php.inc @@ -0,0 +1,27 @@ + +----- + diff --git a/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/skip_different_func_call.php.inc b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/skip_different_func_call.php.inc new file mode 100644 index 00000000..61d2df65 --- /dev/null +++ b/rules-tests/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHash/Fixture/skip_different_func_call.php.inc @@ -0,0 +1,11 @@ +ruleWithConfiguration(DowngradeHashAlgorithmXxHashRector::class, [ + 'xxh3' => 'sha1', + ]); +}; diff --git a/rules/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHashRector.php b/rules/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHashRector.php new file mode 100644 index 00000000..39bc4e21 --- /dev/null +++ b/rules/DowngradePhp81/Rector/FuncCall/DowngradeHashAlgorithmXxHashRector.php @@ -0,0 +1,194 @@ + MHASH_XXH32, + 'xxh64' => MHASH_XXH64, + 'xxh3' => MHASH_XXH3, + 'xxh128' => MHASH_XXH128, + ]; + + /** + * @var array + */ + private array $hashAlgorithmsToDowngradeMapping = []; + + private int $argNamedKey; + + public function __construct( + private readonly ArgsAnalyzer $argsAnalyzer, + private readonly ValueResolver $valueResolver, + ) { + } + + public function getRuleDefinition(): RuleDefinition + { + return new RuleDefinition( + 'Downgrade hash algorithm xxh32, xxh64, xxh3 or xxh128 by default to md5. You can configure the algorithm to downgrade.', + [ + new CodeSample( + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + return hash('xxh128', 'some-data-to-hash'); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + return hash('md5', 'some-data-to-hash'); + } +} +CODE_SAMPLE + ), + new ConfiguredCodeSample( + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + return hash('xxh3', 'some-data-to-hash'); + } +} +CODE_SAMPLE + , + <<<'CODE_SAMPLE' +class SomeClass +{ + public function run() + { + return hash('sha1', 'some-data-to-hash'); + } +} +CODE_SAMPLE + , + [ + 'xxh3' => 'sha1', + ] + ), + ] + ); + } + + /** + * @return array> + */ + public function getNodeTypes(): array + { + return [FuncCall::class]; + } + + /** + * @param FuncCall $node + */ + public function refactor(Node $node): ?Node + { + if ($this->shouldSkip($node)) { + return null; + } + + $this->argNamedKey = 0; + + $algorithm = $this->getHashAlgorithm($node->getArgs()); + + if (! array_key_exists($algorithm, self::HASH_ALGORITHMS_TO_DOWNGRADE)) { + return null; + } + + $newAlgorithm = $this->hashAlgorithmsToDowngradeMapping[$algorithm] ?? 'md5'; + + $arg = $node->args[$this->argNamedKey]; + + if (! $arg instanceof Arg) { + throw new ShouldNotHappenException(); + } + + $arg->value = new String_($newAlgorithm); + + return $node; + } + + /** + * @param mixed[] $configuration + */ + public function configure(array $configuration): void + { + Assert::allString($configuration); + Assert::allString(array_keys($configuration)); + + $this->hashAlgorithmsToDowngradeMapping = $configuration; + } + + private function shouldSkip(FuncCall $funcCall): bool + { + return ! $this->nodeNameResolver->isName($funcCall, 'hash'); + } + + /** + * @param Arg[] $args + */ + private function getHashAlgorithm(array $args): string + { + $arg = null; + + if ($this->argsAnalyzer->hasNamedArg($args)) { + foreach ($args as $key => $arg) { + if ($arg->name?->name !== 'algo') { + continue; + } + + $this->argNamedKey = $key; + + break; + } + } else { + $arg = $args[$this->argNamedKey]; + } + + $algorithmNode = $arg?->value; + + return match (true) { + $algorithmNode instanceof String_ => $this->valueResolver->getValue($algorithmNode), + $algorithmNode instanceof ConstFetch => $this->mapConstantToString( + $this->valueResolver->getValue($algorithmNode) + ), + default => throw new ShouldNotHappenException(), + }; + } + + private function mapConstantToString(string $constant): string + { + $mappedConstant = array_search(constant($constant), self::HASH_ALGORITHMS_TO_DOWNGRADE, true); + + return $mappedConstant !== false ? $mappedConstant : $constant; + } +}