From c86acfb2af7c064c9c5a307644ea9835baa84189 Mon Sep 17 00:00:00 2001
From: Oliver Hader <oliver@typo3.org>
Date: Thu, 10 Mar 2022 12:08:49 +0100
Subject: [PATCH] [BUGFIX] Use defaultScheme setting instead of hard-coded
 'http'
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Several places in the TYPO3 core fall back to using 'http' as
protocol for links in case none was given. In order to adjust this
behavior new $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme']
setting has been introduced, which uses 'http' as default.

In order to adjust the default protocol, one has to add the following
assignment to their LocalConfiguration.php settings:

$GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme'] = 'https'

Resolves: #97111
Releases: main, 11.5
Change-Id: I8c86a3b98dfdfef96c6e433de28e24c1af7f27ab
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/73867
Reviewed-by: Oliver Klee <typo3-coding@oliverklee.de>
Reviewed-by: Stefan Bürk <stefan@buerk.tech>
Reviewed-by: Nikita Hovratov <nikita.h@live.de>
Tested-by: Stefan Bürk <stefan@buerk.tech>
Tested-by: core-ci <typo3@b13.com>
Tested-by: Nikita Hovratov <nikita.h@live.de>
---
 Build/phpstan/phpstan-baseline.neon           |  5 --
 .../LegacyLinkNotationConverter.php           |  2 +-
 .../LinkHandling/LinkHandlingInterface.php    |  7 +++
 .../Classes/LinkHandling/UrlLinkHandler.php   | 16 ++++--
 .../Configuration/DefaultConfiguration.php    |  1 +
 .../DefaultConfigurationDescription.yaml      |  6 +++
 .../Important-97111-DefaultURIScheme.rst      | 24 +++++++++
 .../12.0/Important-97111-DefaultURIScheme.rst | 24 +++++++++
 .../Unit/LinkHandling/UrlLinkHandlerTest.php  | 52 ++++++++++++++-----
 9 files changed, 116 insertions(+), 21 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/11.5.x/Important-97111-DefaultURIScheme.rst
 create mode 100644 typo3/sysext/core/Documentation/Changelog/12.0/Important-97111-DefaultURIScheme.rst

diff --git a/Build/phpstan/phpstan-baseline.neon b/Build/phpstan/phpstan-baseline.neon
index 5eafaffb109b..5ac247ea6e9a 100644
--- a/Build/phpstan/phpstan-baseline.neon
+++ b/Build/phpstan/phpstan-baseline.neon
@@ -1715,11 +1715,6 @@ parameters:
 			count: 1
 			path: ../../typo3/sysext/core/Tests/Unit/LinkHandling/FolderLinkHandlerTest.php
 
-		-
-			message: "#^Parameter \\#1 \\$data of method TYPO3\\\\CMS\\\\Core\\\\LinkHandling\\\\UrlLinkHandler\\:\\:resolveHandlerData\\(\\) expects array, string given\\.$#"
-			count: 1
-			path: ../../typo3/sysext/core/Tests/Unit/LinkHandling/UrlLinkHandlerTest.php
-
 		-
 			message: "#^Parameter \\#2 \\$locale of function setlocale expects array\\|string\\|null, int given\\.$#"
 			count: 3
diff --git a/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php b/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php
index 0208149d8452..a13be8bd09c4 100644
--- a/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php
+++ b/typo3/sysext/core/Classes/LinkHandling/LegacyLinkNotationConverter.php
@@ -135,7 +135,7 @@ class LegacyLinkNotationConverter
             // url (external): If doubleSlash or if a '.' comes before a '/'.
             if (!$isIdOrAlias && $isLocalFile !== 1 && $urlChar && (!$containsSlash || $urlChar < $fileChar)) {
                 $result['type'] = LinkService::TYPE_URL;
-                $result['url'] = 'http://' . $linkParameter;
+                $result['url'] = UrlLinkHandler::getDefaultScheme() . '://' . $linkParameter;
             // file (internal) or folder
             } elseif ($containsSlash || $isLocalFile) {
                 $result = $this->getFileOrFolderObjectFromMixedIdentifier($linkParameter);
diff --git a/typo3/sysext/core/Classes/LinkHandling/LinkHandlingInterface.php b/typo3/sysext/core/Classes/LinkHandling/LinkHandlingInterface.php
index 33fa833af5b0..513b2461662c 100644
--- a/typo3/sysext/core/Classes/LinkHandling/LinkHandlingInterface.php
+++ b/typo3/sysext/core/Classes/LinkHandling/LinkHandlingInterface.php
@@ -24,6 +24,13 @@ namespace TYPO3\CMS\Core\LinkHandling;
  */
 interface LinkHandlingInterface
 {
+    /**
+     * @var non-empty-string will be used for links without a scheme if no default scheme is configured
+     *
+     * @internal Do not use directly; please use `UrlLinkHandler::getDefaultScheme()` instead to also take the
+     *           configured default scheme into account.
+     */
+    public const DEFAULT_SCHEME = 'http';
 
     /**
      * Returns a string interpretation of the link href query from objects, something like
diff --git a/typo3/sysext/core/Classes/LinkHandling/UrlLinkHandler.php b/typo3/sysext/core/Classes/LinkHandling/UrlLinkHandler.php
index 64dde174e9d1..7a0df4f5e115 100644
--- a/typo3/sysext/core/Classes/LinkHandling/UrlLinkHandler.php
+++ b/typo3/sysext/core/Classes/LinkHandling/UrlLinkHandler.php
@@ -44,7 +44,7 @@ class UrlLinkHandler implements LinkHandlingInterface
     }
 
     /**
-     * Ensures that a scheme is always added, if www.typo3.org was added previously
+     * Ensures that a scheme is always added, if www.typo3.org was added previously.
      *
      * @param string $url the URL
      * @return string
@@ -57,8 +57,7 @@ class UrlLinkHandler implements LinkHandlingInterface
             }
             $scheme = parse_url($url, PHP_URL_SCHEME);
             if (empty($scheme)) {
-                $url = 'http://' . $url;
-            // 'java{TAB}script:' is parsed as empty URL scheme, thus not ending up here
+                $url = self::getDefaultScheme() . '://' . $url;
             } elseif (in_array(strtolower($scheme), ['javascript', 'data'], true)) {
                 // deny using insecure scheme's like `javascript:` or `data:` as URL scheme
                 $url = '';
@@ -66,4 +65,15 @@ class UrlLinkHandler implements LinkHandlingInterface
         }
         return $url;
     }
+
+    /**
+     * Returns the scheme (e.g. `http`) to be used for links with URLs without a scheme, e.g., for `www.example.com`.
+     *
+     * @return non-empty-string
+     */
+    public static function getDefaultScheme(): string
+    {
+        return ($GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme'] ?? '')
+            ?: LinkHandlingInterface::DEFAULT_SCHEME;
+    }
 }
diff --git a/typo3/sysext/core/Configuration/DefaultConfiguration.php b/typo3/sysext/core/Configuration/DefaultConfiguration.php
index a3735162746b..7253ac216406 100644
--- a/typo3/sysext/core/Configuration/DefaultConfiguration.php
+++ b/typo3/sysext/core/Configuration/DefaultConfiguration.php
@@ -379,6 +379,7 @@ return [
                 ],
             ],
         ],
+        'defaultScheme' => \TYPO3\CMS\Core\LinkHandling\LinkHandlingInterface::DEFAULT_SCHEME,
         'linkHandler' => [ // Array: Available link types, class which implement the LinkHandling interface
             'page'   => \TYPO3\CMS\Core\LinkHandling\PageLinkHandler::class,
             'file'   => \TYPO3\CMS\Core\LinkHandling\FileLinkHandler::class,
diff --git a/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml b/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml
index 845b701aab6d..12ef31c77552 100644
--- a/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml
+++ b/typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml
@@ -93,6 +93,12 @@ SYS:
         hhmm:
             type: text
             description: 'Format of Hours-Minutes - see PHP-function <a href="https://php.net/date" target="_blank" rel="noreferrer">date()</a>'
+        defaultScheme:
+            type: text
+            allowedValues:
+              'http': 'http'
+              'https': 'https'
+            description: 'Default URI scheme to be used in case none was given, e.g. "www.typo3.org" becomes "http://www.typo3.org"'
         loginCopyrightWarrantyProvider:
             type: text
             description: 'If you provide warranty for TYPO3 to your customers insert you (company) name here. It will appear in the login-dialog as the warranty provider. (You must also set URL below).'
diff --git a/typo3/sysext/core/Documentation/Changelog/11.5.x/Important-97111-DefaultURIScheme.rst b/typo3/sysext/core/Documentation/Changelog/11.5.x/Important-97111-DefaultURIScheme.rst
new file mode 100644
index 000000000000..c8b53c8b874e
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/11.5.x/Important-97111-DefaultURIScheme.rst
@@ -0,0 +1,24 @@
+.. include:: /Includes.rst.txt
+
+.. _important-97111-1657214951:
+
+======================================
+Important: #97111 - Default URI scheme
+======================================
+
+See :issue:`97111`
+
+Description
+===========
+
+Several places in the TYPO3 core fall back to using `http` as a protocol for
+links in case none was given. In order to adjust this behavior the new
+:php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme']` setting has been
+introduced, which uses `http` as default.
+
+In order to adjust the default protocol, one has to add the following
+assignment to their :file:`typo3conf/LocalConfiguration.php` settings:
+
+:php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme'] = 'https'`
+
+.. index:: LocalConfiguration, RTE, ext:core
diff --git a/typo3/sysext/core/Documentation/Changelog/12.0/Important-97111-DefaultURIScheme.rst b/typo3/sysext/core/Documentation/Changelog/12.0/Important-97111-DefaultURIScheme.rst
new file mode 100644
index 000000000000..c8b53c8b874e
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/12.0/Important-97111-DefaultURIScheme.rst
@@ -0,0 +1,24 @@
+.. include:: /Includes.rst.txt
+
+.. _important-97111-1657214951:
+
+======================================
+Important: #97111 - Default URI scheme
+======================================
+
+See :issue:`97111`
+
+Description
+===========
+
+Several places in the TYPO3 core fall back to using `http` as a protocol for
+links in case none was given. In order to adjust this behavior the new
+:php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme']` setting has been
+introduced, which uses `http` as default.
+
+In order to adjust the default protocol, one has to add the following
+assignment to their :file:`typo3conf/LocalConfiguration.php` settings:
+
+:php:`$GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme'] = 'https'`
+
+.. index:: LocalConfiguration, RTE, ext:core
diff --git a/typo3/sysext/core/Tests/Unit/LinkHandling/UrlLinkHandlerTest.php b/typo3/sysext/core/Tests/Unit/LinkHandling/UrlLinkHandlerTest.php
index b5a03f9106b8..61be21832fff 100644
--- a/typo3/sysext/core/Tests/Unit/LinkHandling/UrlLinkHandlerTest.php
+++ b/typo3/sysext/core/Tests/Unit/LinkHandling/UrlLinkHandlerTest.php
@@ -17,6 +17,7 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Core\Tests\Unit\LinkHandling;
 
+use TYPO3\CMS\Core\LinkHandling\LinkHandlingInterface;
 use TYPO3\CMS\Core\LinkHandling\UrlLinkHandler;
 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 
@@ -115,14 +116,9 @@ class UrlLinkHandlerTest extends UnitTestCase
     /**
      * @test
      *
-     * @param string $input
-     * @param array  $expected
-     * @param string $finalString
-     *
      * @dataProvider resolveParametersForNonFilesDataProvider
-     * @todo Defining the method parameter types results in test bench errors
      */
-    public function resolveReturnsSplitParameters($input, $expected, $finalString): void
+    public function resolveReturnsSplitParameters(array $input, array $expected, string $finalString): void
     {
         $subject = new UrlLinkHandler();
         self::assertEquals($expected, $subject->resolveHandlerData($input));
@@ -131,16 +127,48 @@ class UrlLinkHandlerTest extends UnitTestCase
     /**
      * @test
      *
-     * @param string $input
-     * @param array  $parameters
-     * @param string $expected
-     *
      * @dataProvider resolveParametersForNonFilesDataProvider
-     * @todo Defining the method parameter types results in test bench errors
      */
-    public function splitParametersToUnifiedIdentifier($input, $parameters, $expected): void
+    public function splitParametersToUnifiedIdentifier(array $input, array $parameters, string $expected): void
     {
         $subject = new UrlLinkHandler();
         self::assertEquals($expected, $subject->asString($parameters));
     }
+
+    /**
+     * @test
+     */
+    public function getDefaultSchemeForNoSchemeInConfigurationReturnsFallbackScheme(): void
+    {
+        unset($GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme']);
+
+        $result = UrlLinkHandler::getDefaultScheme();
+
+        self::assertSame(LinkHandlingInterface::DEFAULT_SCHEME, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function getDefaultSchemeForEmptySchemeInConfigurationReturnsFallbackScheme(): void
+    {
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme'] = '';
+
+        $result = UrlLinkHandler::getDefaultScheme();
+
+        self::assertSame(LinkHandlingInterface::DEFAULT_SCHEME, $result);
+    }
+
+    /**
+     * @test
+     */
+    public function getDefaultSchemeForSchemeInConfigurationReturnsSchemeFromConfiguration(): void
+    {
+        $scheme = 'https';
+        $GLOBALS['TYPO3_CONF_VARS']['SYS']['defaultScheme'] = $scheme;
+
+        $result = UrlLinkHandler::getDefaultScheme();
+
+        self::assertSame($scheme, $result);
+    }
 }
-- 
GitLab