From 2e3dea7a2b88899b4de4fc42650d54842f5a0236 Mon Sep 17 00:00:00 2001
From: Lee Rowlands <lee.rowlands@previousnext.com.au>
Date: Tue, 27 Jun 2023 06:12:34 +1000
Subject: [PATCH] Issue #3370043 by catch, Chi: Asset controller should
 validate filename prefix

---
 .../Core/Asset/JsCollectionOptimizerLazy.php     |  2 ++
 .../src/Controller/AssetControllerBase.php       |  4 ++++
 .../Asset/AssetOptimizationTest.php              | 16 ++++++++++++++++
 3 files changed, 22 insertions(+)

diff --git a/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php b/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php
index f1477eac85ba..0ed426dc0f12 100644
--- a/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php
+++ b/core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php
@@ -133,6 +133,8 @@ public function optimize(array $js_assets, array $libraries) {
             'scope' => $js_asset['scope'] === 'header' ? 'header' : 'footer',
             'delta' => "$order",
           ] + $query_args;
+          // Add a filename prefix to mitigate ad blockers which can block
+          // any script beginning with 'ad'.
           $filename = 'js_' . $this->generateHash($js_asset) . '.js';
           $uri = 'assets://js/' . $filename;
           $js_assets[$order]['data'] = $this->fileUrlGenerator->generateString($uri) . '?' . UrlHelper::buildQuery($query);
diff --git a/core/modules/system/src/Controller/AssetControllerBase.php b/core/modules/system/src/Controller/AssetControllerBase.php
index e9a91c07ea60..620b2ecccf73 100644
--- a/core/modules/system/src/Controller/AssetControllerBase.php
+++ b/core/modules/system/src/Controller/AssetControllerBase.php
@@ -136,6 +136,10 @@ public function deliver(Request $request, string $file_name) {
       throw new BadRequestHttpException('The libraries to include must be passed as a query argument');
     }
     $file_parts = explode('_', basename($file_name, '.' . $this->fileExtension), 2);
+    // Ensure the filename is correctly prefixed.
+    if ($file_parts[0] !== $this->fileExtension) {
+      throw new BadRequestHttpException('The filename prefix must match the file extension');
+    }
 
     // The hash is the second segment of the filename.
     if (!isset($file_parts[1])) {
diff --git a/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php b/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php
index 47bdd8ab081f..d4c6021b80fa 100644
--- a/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php
+++ b/core/tests/Drupal/FunctionalTests/Asset/AssetOptimizationTest.php
@@ -163,6 +163,9 @@ protected function assertInvalidAggregates(string $url): void {
     $session->visit($this->invalidExclude($url));
     $this->assertSession()->statusCodeEquals(400);
 
+    $session->visit($this->replaceFileNamePrefix($url));
+    $this->assertSession()->statusCodeEquals(400);
+
     $session->visit($this->setInvalidLibrary($url));
     $this->assertSession()->statusCodeEquals(200);
 
@@ -210,6 +213,19 @@ protected function replaceGroupHash(string $url): string {
     return $this->getAbsoluteUrl(implode('_', $parts));
   }
 
+  /**
+   * Replaces the filename prefix in the given URL.
+   *
+   * @param string $url
+   *   The source URL.
+   *
+   * @return string
+   *   The URL with the file name prefix replaced.
+   */
+  protected function replaceFileNamePrefix(string $url): string {
+    return str_replace(['/css_', '/js_'], '/xyz_', $url);
+  }
+
   /**
    * Replaces the 'include' entry in the given URL with an invalid value.
    *
-- 
GitLab