From 247e8972d013b3549432d9736db233b632e14fb8 Mon Sep 17 00:00:00 2001 From: Demian Katz Date: Fri, 13 Dec 2024 09:59:59 -0500 Subject: [PATCH 1/3] Adjust SessionCsrf for forward-compatibility with laminas-validator 3. --- composer.json | 2 +- composer.lock | 16 +- .../src/VuFind/Validator/SessionCsrf.php | 177 +++++++++++++++++- 3 files changed, 181 insertions(+), 14 deletions(-) diff --git a/composer.json b/composer.json index 0b6e7f76ba0..661d0658b75 100644 --- a/composer.json +++ b/composer.json @@ -84,7 +84,7 @@ "laminas/laminas-session": "2.21.0", "laminas/laminas-stdlib": "3.19.0", "laminas/laminas-text": "2.11.0", - "laminas/laminas-validator": "2.55.0", + "laminas/laminas-validator": "2.64.2", "laminas/laminas-view": "2.27.0", "league/commonmark": "2.6.0", "league/oauth2-client": "^2.7", diff --git a/composer.lock b/composer.lock index 0ab9a487467..9925c0abf7d 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1a11b1b8757fba47cad77f6aeffb4bfa", + "content-hash": "707506f308fdbe34c207f2313bd5addf", "packages": [ { "name": "ahand/mobileesp", @@ -4397,22 +4397,22 @@ }, { "name": "laminas/laminas-validator", - "version": "2.55.0", + "version": "2.64.2", "source": { "type": "git", "url": "https://github.com/laminas/laminas-validator.git", - "reference": "dc3f2609d41b1e21bc24e3e147d7dd284e8a1556" + "reference": "771e504760448ac7af660710237ceb93be602e08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/dc3f2609d41b1e21bc24e3e147d7dd284e8a1556", - "reference": "dc3f2609d41b1e21bc24e3e147d7dd284e8a1556", + "url": "https://api.github.com/repos/laminas/laminas-validator/zipball/771e504760448ac7af660710237ceb93be602e08", + "reference": "771e504760448ac7af660710237ceb93be602e08", "shasum": "" }, "require": { "laminas/laminas-servicemanager": "^3.21.0", - "laminas/laminas-stdlib": "^3.13", - "php": "~8.1.0 || ~8.2.0 || ~8.3.0", + "laminas/laminas-stdlib": "^3.19", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", "psr/http-message": "^1.0.1 || ^2.0.0" }, "conflict": { @@ -4477,7 +4477,7 @@ "type": "community_bridge" } ], - "time": "2024-06-12T15:00:19+00:00" + "time": "2024-11-26T21:29:17+00:00" }, { "name": "laminas/laminas-view", diff --git a/module/VuFind/src/VuFind/Validator/SessionCsrf.php b/module/VuFind/src/VuFind/Validator/SessionCsrf.php index 257e716a05e..e00c970aeda 100644 --- a/module/VuFind/src/VuFind/Validator/SessionCsrf.php +++ b/module/VuFind/src/VuFind/Validator/SessionCsrf.php @@ -1,7 +1,7 @@ csrf = new Csrf($options); + } + /** * Keep only the most recent N tokens. * @@ -52,7 +75,7 @@ class SessionCsrf extends \Laminas\Validator\Csrf implements CsrfInterface */ public function trimTokenList($limit) { - $session = $this->getSession(); + $session = $this->csrf->getSession(); if ($limit < 1) { // Reset the array if necessary: $session->tokenList = []; @@ -70,6 +93,150 @@ public function trimTokenList($limit) */ public function getTokenCount() { - return count($this->getSession()->tokenList ?? []); + return count($this->csrf->getSession()->tokenList ?? []); + } + + /** + * Retrieve CSRF token + * + * If no CSRF token currently exists, or should be regenerated, + * generates one. + * + * @param bool $regenerate regenerate hash, default false + * + * @return string + */ + public function getHash($regenerate = false) + { + return $this->csrf->getHash($regenerate); + } + + /** + * Sets translator to use in helper + * + * @param TranslatorInterface $translator [optional] translator. + * Default is null, which sets no translator. + * @param string $textDomain [optional] text domain + * Default is null, which skips setTranslatorTextDomain + * + * @return self + */ + public function setTranslator(?TranslatorInterface $translator = null, $textDomain = null) + { + return $this->csrf->setTranslator($translator, $textDomain); + } + + /** + * Returns translator used in object + * + * @return TranslatorInterface|null + */ + public function getTranslator() + { + return $this->csrf->getTranslator(); + } + + /** + * Checks if the object has a translator + * + * @return bool + */ + public function hasTranslator() + { + return $this->csrf->hasTranslator(); + } + + /** + * Sets whether translator is enabled and should be used + * + * @param bool $enabled [optional] whether translator should be used. + * Default is true. + * + * @return self + */ + public function setTranslatorEnabled($enabled = true) + { + return $this->csrf->setTranslatorEnabled($enabled); + } + + /** + * Returns whether translator is enabled and should be used + * + * @return bool + */ + public function isTranslatorEnabled() + { + return $this->csrf->isTranslatorEnabled(); + } + + /** + * Set translation text domain + * + * @param string $textDomain New text domain + * + * @return TranslatorAwareInterface + */ + public function setTranslatorTextDomain($textDomain = 'default') + { + return $this->csrf->setTranslatorTextDomain($textDomain); + } + + /** + * Return the translation text domain + * + * @return string + */ + public function getTranslatorTextDomain() + { + return $this->csrf->getTranslatorTextDomain(); + } + + /** + * Returns true if and only if $value meets the validation requirements + * + * If $value fails validation, then this method returns false, and + * getMessages() will return an array of messages that explain why the + * validation failed. + * + * @param mixed $value Value to validate + * + * @return bool + * @throws Exception\RuntimeException If validation of $value is impossible. + */ + public function isValid($value) + { + return $this->csrf->isValid($value); + } + + /** + * Returns an array of messages that explain why the most recent isValid() + * call returned false. The array keys are validation failure message identifiers, + * and the array values are the corresponding human-readable message strings. + * + * If isValid() was never called or if the most recent isValid() call + * returned true, then this method returns an empty array. + * + * @return array + */ + public function getMessages() + { + return $this->csrf->getMessages(); + } + + /** + * Proxy all other calls to the CSRF object. + * + * @param string $method Method being called + * @param array $args Argument list + * + * @return mixed + * @throws \Exception + */ + public function __call(string $method, array $args = []): mixed + { + if (is_callable([$this->csrf, 'method'])) { + return ($this->csrf->$method)(...$args); + } + throw new \Exception("Undefined method: $method"); } } From 7099c1e65b0d81587bb1706ddae098a5423cd2ad Mon Sep 17 00:00:00 2001 From: Demian Katz Date: Fri, 13 Dec 2024 10:10:19 -0500 Subject: [PATCH 2/3] Simplify. --- .../src/VuFind/Validator/SessionCsrf.php | 114 +----------------- 1 file changed, 4 insertions(+), 110 deletions(-) diff --git a/module/VuFind/src/VuFind/Validator/SessionCsrf.php b/module/VuFind/src/VuFind/Validator/SessionCsrf.php index e00c970aeda..f090930f989 100644 --- a/module/VuFind/src/VuFind/Validator/SessionCsrf.php +++ b/module/VuFind/src/VuFind/Validator/SessionCsrf.php @@ -29,14 +29,10 @@ namespace VuFind\Validator; -use Laminas\Validator\Csrf; -use Laminas\Validator\Translator\TranslatorAwareInterface; -use Laminas\Validator\Translator\TranslatorInterface; -use Laminas\Validator\ValidatorInterface; +use Laminas\Session\Validator\Csrf; use function array_slice; use function count; -use function is_callable; /** * Decorator for Laminas\Validator\Csrf with token counting/clearing functions added. @@ -47,7 +43,7 @@ * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License * @link https://vufind.org/wiki/development Wiki */ -class SessionCsrf implements CsrfInterface, ValidatorInterface, TranslatorAwareInterface +class SessionCsrf implements CsrfInterface { /** * Laminas CSRF class. @@ -112,97 +108,12 @@ public function getHash($regenerate = false) } /** - * Sets translator to use in helper + * Returns true if the CSRF token is valid. * - * @param TranslatorInterface $translator [optional] translator. - * Default is null, which sets no translator. - * @param string $textDomain [optional] text domain - * Default is null, which skips setTranslatorTextDomain - * - * @return self - */ - public function setTranslator(?TranslatorInterface $translator = null, $textDomain = null) - { - return $this->csrf->setTranslator($translator, $textDomain); - } - - /** - * Returns translator used in object - * - * @return TranslatorInterface|null - */ - public function getTranslator() - { - return $this->csrf->getTranslator(); - } - - /** - * Checks if the object has a translator + * @param mixed $value Token to validate * * @return bool */ - public function hasTranslator() - { - return $this->csrf->hasTranslator(); - } - - /** - * Sets whether translator is enabled and should be used - * - * @param bool $enabled [optional] whether translator should be used. - * Default is true. - * - * @return self - */ - public function setTranslatorEnabled($enabled = true) - { - return $this->csrf->setTranslatorEnabled($enabled); - } - - /** - * Returns whether translator is enabled and should be used - * - * @return bool - */ - public function isTranslatorEnabled() - { - return $this->csrf->isTranslatorEnabled(); - } - - /** - * Set translation text domain - * - * @param string $textDomain New text domain - * - * @return TranslatorAwareInterface - */ - public function setTranslatorTextDomain($textDomain = 'default') - { - return $this->csrf->setTranslatorTextDomain($textDomain); - } - - /** - * Return the translation text domain - * - * @return string - */ - public function getTranslatorTextDomain() - { - return $this->csrf->getTranslatorTextDomain(); - } - - /** - * Returns true if and only if $value meets the validation requirements - * - * If $value fails validation, then this method returns false, and - * getMessages() will return an array of messages that explain why the - * validation failed. - * - * @param mixed $value Value to validate - * - * @return bool - * @throws Exception\RuntimeException If validation of $value is impossible. - */ public function isValid($value) { return $this->csrf->isValid($value); @@ -222,21 +133,4 @@ public function getMessages() { return $this->csrf->getMessages(); } - - /** - * Proxy all other calls to the CSRF object. - * - * @param string $method Method being called - * @param array $args Argument list - * - * @return mixed - * @throws \Exception - */ - public function __call(string $method, array $args = []): mixed - { - if (is_callable([$this->csrf, 'method'])) { - return ($this->csrf->$method)(...$args); - } - throw new \Exception("Undefined method: $method"); - } } From b3537855ec828addb6e2c24b2b09917366438a12 Mon Sep 17 00:00:00 2001 From: Demian Katz Date: Fri, 13 Dec 2024 10:13:50 -0500 Subject: [PATCH 3/3] Improve comment. --- module/VuFind/src/VuFind/Validator/SessionCsrf.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/VuFind/src/VuFind/Validator/SessionCsrf.php b/module/VuFind/src/VuFind/Validator/SessionCsrf.php index f090930f989..32523e450b8 100644 --- a/module/VuFind/src/VuFind/Validator/SessionCsrf.php +++ b/module/VuFind/src/VuFind/Validator/SessionCsrf.php @@ -1,7 +1,7 @@