From bc15f40a8a381455e3504953ce450ea2119b09fb Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Thu, 14 Nov 2024 13:47:59 +0100 Subject: [PATCH 1/3] Routing: Allow to mark parsed URLs as tainted --- libraries/src/Router/Router.php | 41 ++++++++++++++++++++++++ plugins/system/sef/src/Extension/Sef.php | 19 +++++++++++ 2 files changed, 60 insertions(+) diff --git a/libraries/src/Router/Router.php b/libraries/src/Router/Router.php index 1e40cd40cd0cf..de7411507c3d2 100644 --- a/libraries/src/Router/Router.php +++ b/libraries/src/Router/Router.php @@ -80,6 +80,16 @@ class Router */ protected $cache = []; + /** + * Flag to mark the last parsed URL as tainted + * If a URL could be read, but has errors, this + * flag can be set to true to mark the URL as errornous. + * + * @var bool + * @since __DEPLOY_VERSION__ + */ + protected $tainted = false; + /** * Router instances container. * @@ -140,6 +150,9 @@ public static function getInstance($client, $options = []) */ public function parse(&$uri, $setVars = false) { + // Reset the tainted flag + $this->tainted = false; + // Do the preprocess stage of the URL parse process $this->processParseRules($uri, self::PROCESS_BEFORE); @@ -362,6 +375,34 @@ public function getRules() return $this->rules; } + /** + * Set the currently parsed URL as tainted + * If a URL can be parsed, but not all parts were correct, + * (for example an ID was found, but the alias was wrong) the parsing + * can be marked as tainted. When the URL is marked as tainted, the router + * has to have returned correct data to create the right URL afterwards and + * can later do additional processing, like redirecting to the right URL. + * If the URL is demonstrably wrong, it should still throw a 404 exception. + * + * @since __DEPLOY_VERSION__ + */ + public function setTainted() + { + $this->tainted = true; + } + + /** + * Return if the last parsed URL was tainted. + * + * @return bool + * + * @since __DEPLOY_VERSION__ + */ + public function isTainted() + { + return $this->tainted; + } + /** * Process the parsed router variables based on custom defined rules * diff --git a/plugins/system/sef/src/Extension/Sef.php b/plugins/system/sef/src/Extension/Sef.php index 2e0568059cbf9..ed8aa9aa63d0e 100644 --- a/plugins/system/sef/src/Extension/Sef.php +++ b/plugins/system/sef/src/Extension/Sef.php @@ -100,6 +100,25 @@ public function onAfterRoute() return; } + $router = $this->getSiteRouter(); + + if ($router->isTainted()) { + $parsedVars = $router->getVars(); + + if ($app->getLanguageFilter()) { + $parsedVars['lang'] = $parsedVars['language']; + unset($parsedVars['language']); + } + + $newRoute = Route::_($parsedVars, false); + $origUri = clone Uri::getInstance(); + $route = $origUri->toString(['path', 'query']); + + if ($route !== $newRoute) { + $app->redirect($newRoute, 301); + } + } + // Enforce removing index.php with a redirect if ($app->get('sef_rewrite') && $this->params->get('indexphp')) { $this->removeIndexphp(); From 7d9e478c30031ca10cab1b479d60eb746603119d Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Fri, 15 Nov 2024 09:14:13 +0100 Subject: [PATCH 2/3] Add comment --- plugins/system/sef/src/Extension/Sef.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/system/sef/src/Extension/Sef.php b/plugins/system/sef/src/Extension/Sef.php index ed8aa9aa63d0e..581ef6a334e0c 100644 --- a/plugins/system/sef/src/Extension/Sef.php +++ b/plugins/system/sef/src/Extension/Sef.php @@ -102,6 +102,11 @@ public function onAfterRoute() $router = $this->getSiteRouter(); + /** + * The URL was successfully parsed, but is "tainted", e.g. parts of + * it were recoverably wrong. So we take the parsed variables, build + * a new URL and redirect to that. + */ if ($router->isTainted()) { $parsedVars = $router->getVars(); From 51f23a926d30c784ac3a78d0916992e10f2b70bc Mon Sep 17 00:00:00 2001 From: Hannes Papenberg Date: Wed, 20 Nov 2024 12:23:18 +0100 Subject: [PATCH 3/3] Update libraries/src/Router/Router.php Co-authored-by: Quy --- libraries/src/Router/Router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/src/Router/Router.php b/libraries/src/Router/Router.php index de7411507c3d2..0a2e810663e0b 100644 --- a/libraries/src/Router/Router.php +++ b/libraries/src/Router/Router.php @@ -83,7 +83,7 @@ class Router /** * Flag to mark the last parsed URL as tainted * If a URL could be read, but has errors, this - * flag can be set to true to mark the URL as errornous. + * flag can be set to true to mark the URL as erroneous. * * @var bool * @since __DEPLOY_VERSION__