From 935fd43592302571d46ff15a7aad2965296484ff Mon Sep 17 00:00:00 2001
From: Oliver Hader <oliver@typo3.org>
Date: Thu, 4 May 2023 14:16:06 +0200
Subject: [PATCH] [BUGFIX] Correctly represent CSP UriValue('*')

An entire wildcard `UriValue`, which is just `'*'`, was
incorrectly encoded. In the scope of CSP `'*'` is valid.
Using wildcards should be avoided in favor of being specific.

Resolves: #100798
Releases: main, 12.4
Change-Id: Iaf13b1d2095a672653894a6da5f10ad7115a2538
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/78933
Tested-by: Nikita Hovratov <nikita.h@live.de>
Tested-by: core-ci <typo3@b13.com>
Reviewed-by: Nikita Hovratov <nikita.h@live.de>
Reviewed-by: Benni Mack <benni@typo3.org>
Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
Tested-by: Georg Ringer <georg.ringer@gmail.com>
Tested-by: Benni Mack <benni@typo3.org>
Tested-by: Oliver Hader <oliver.hader@typo3.org>
Reviewed-by: Georg Ringer <georg.ringer@gmail.com>
---
 .../Security/ContentSecurityPolicy/UriValue.php      | 12 ++++++++++++
 .../Security/ContentSecurityPolicy/UriValueTest.php  |  3 +++
 2 files changed, 15 insertions(+)

diff --git a/typo3/sysext/core/Classes/Security/ContentSecurityPolicy/UriValue.php b/typo3/sysext/core/Classes/Security/ContentSecurityPolicy/UriValue.php
index 3dd292a00428..ed460a49e65c 100644
--- a/typo3/sysext/core/Classes/Security/ContentSecurityPolicy/UriValue.php
+++ b/typo3/sysext/core/Classes/Security/ContentSecurityPolicy/UriValue.php
@@ -28,6 +28,7 @@ use TYPO3\CMS\Core\Http\Uri;
 final class UriValue extends Uri implements \Stringable, EqualityInterface, CoveringInterface, SourceInterface
 {
     private string $domainName = '';
+    private bool $entireWildcard = false;
     private bool $domainWildcard = false;
 
     public static function fromUri(UriInterface $other): self
@@ -37,6 +38,9 @@ final class UriValue extends Uri implements \Stringable, EqualityInterface, Cove
 
     public function __toString(): string
     {
+        if ($this->entireWildcard) {
+            return '*';
+        }
         if ($this->domainName !== '') {
             return ($this->domainWildcard ? '*.' : '') . $this->domainName;
         }
@@ -53,6 +57,10 @@ final class UriValue extends Uri implements \Stringable, EqualityInterface, Cove
         if (!$other instanceof self) {
             return false;
         }
+        // `*` matches anything
+        if ($this->entireWildcard) {
+            return true;
+        }
         // `*.example.com` or `example.com`
         if ($this->domainName !== '') {
             if ($this->domainWildcard) {
@@ -87,6 +95,10 @@ final class UriValue extends Uri implements \Stringable, EqualityInterface, Cove
 
     protected function parseUri(string $uri): void
     {
+        if ($uri === '*') {
+            $this->entireWildcard = true;
+            return;
+        }
         parent::parseUri($uri);
         // ignore fragments per default
         $this->fragment = '';
diff --git a/typo3/sysext/core/Tests/Unit/Security/ContentSecurityPolicy/UriValueTest.php b/typo3/sysext/core/Tests/Unit/Security/ContentSecurityPolicy/UriValueTest.php
index 5a6063a99946..a9382743fbd0 100644
--- a/typo3/sysext/core/Tests/Unit/Security/ContentSecurityPolicy/UriValueTest.php
+++ b/typo3/sysext/core/Tests/Unit/Security/ContentSecurityPolicy/UriValueTest.php
@@ -40,6 +40,7 @@ final class UriValueTest extends UnitTestCase
         yield ['//www.typo3.org'];
         yield ['www.typo3.org'];
         yield ['*.typo3.org'];
+        yield ['*'];
 
         // expected behavior, falls back to upstream parser´
         // (since e.g. query-param is given, which is not expected here in the scope of CSP with `UriValue`)
@@ -83,6 +84,7 @@ final class UriValueTest extends UnitTestCase
         yield ['example.com/path', 'example.com/path', true];
         yield ['example.com/path', 'example.com/other', false];
         yield ['*.example.com', '*.example.com', true];
+        yield ['*', '*.example.com', true];
 
         yield ['https://example.com/', 'https://example.com/path/file.css', true];
         yield ['example.com', 'https://example.com/path/file.css', true];
@@ -94,6 +96,7 @@ final class UriValueTest extends UnitTestCase
         yield ['*.sub.example.com', 'example.com', false];
         yield ['sub.example.com', '*.example.com', false];
         yield ['*.sub.example.com', '*.example.com', false];
+        yield ['*.example.com', '*', false];
     }
 
     /**
-- 
GitLab