From e681cfaa4faa9c937fa9cc9596e8ff898730a3bd Mon Sep 17 00:00:00 2001
From: Benni Mack <benni@typo3.org>
Date: Thu, 7 Dec 2017 21:44:05 +0100
Subject: [PATCH] [!!!][TASK] Remove config.lockFilePath functionality

When using the stdWrap.filelist functionality, the lockFilePath
only allowed to be used for a certain directory (usually, if not set, it
was set to fileadmin/), however, this is both very unsecure and inflexible.

Thus, stdWrap.filelist is extended to be used with all local FAL storages.

Add the same time, the public property TSFE->lockFilePath and the TypoScript
option "config.lockFilePath" is removed.

Resolves: #83256
Releases: master
Change-Id: Ia86c6686128dae4c0870cd15e019f4d53a4b28b6
Reviewed-on: https://review.typo3.org/54974
Reviewed-by: Andreas Fernandez <typo3@scripting-base.de>
Reviewed-by: Daniel Gorges <daniel.gorges@b13.de>
Tested-by: Daniel Gorges <daniel.gorges@b13.de>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
Tested-by: Stefan Neufeind <typo3.neufeind@speedpartner.de>
---
 ...83256-RemovedLockFilePathFunctionality.rst | 51 +++++++++++++++++
 .../ContentObject/ContentObjectRenderer.php   | 55 ++++++++-----------
 .../TypoScriptFrontendController.php          |  8 ---
 .../Php/MethodCallMatcher.php                 |  7 +++
 .../Php/PropertyPublicMatcher.php             |  5 ++
 .../t3editor/Resources/Private/tsref.xml      |  5 --
 .../JavaScript/Mode/typoscript/typoscript.js  |  1 -
 7 files changed, 86 insertions(+), 46 deletions(-)
 create mode 100644 typo3/sysext/core/Documentation/Changelog/master/Breaking-83256-RemovedLockFilePathFunctionality.rst

diff --git a/typo3/sysext/core/Documentation/Changelog/master/Breaking-83256-RemovedLockFilePathFunctionality.rst b/typo3/sysext/core/Documentation/Changelog/master/Breaking-83256-RemovedLockFilePathFunctionality.rst
new file mode 100644
index 000000000000..c3acf3a882d0
--- /dev/null
+++ b/typo3/sysext/core/Documentation/Changelog/master/Breaking-83256-RemovedLockFilePathFunctionality.rst
@@ -0,0 +1,51 @@
+.. include:: ../../Includes.txt
+
+=====================================================
+Breaking: #83256 - Removed lockFilePath functionality
+=====================================================
+
+See :issue:`83256`
+
+Description
+===========
+
+The TypoScript option :typoscript:`config.lockFilePath` has been removed, which was possible to allow TypoScript
+:typoscript:`stdWrap.filelist` to use a different base directory than fileadmin/ (which was the default).
+
+However, :typoscript:`stdWrap.filelist` now checks for valid local FAL storages (File Abstraction Layer), which can
+now be used if multiple storages are in use.
+
+Thus, the following PHP property has been removed:
+
+* :php:`TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->lockFilePath
+
+The following PHP method has been removed:
+
+* :php:`TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->clean_directory()`
+
+
+Impact
+======
+
+Setting :typoscript:`config.lockFilePath` has no effect anymore.
+
+Accessing or setting :php:`TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->lockFilePath` will trigger
+a PHP notice.
+
+Calling :php:`TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->clean_directory()` will trigger a PHP fatal error.
+
+
+Affected Installations
+======================
+
+Any installation using the PHP method/property or having config.lockFilePath set to a specific non-FAL folder,
+and using stdWrap.filelist functionality.
+
+
+Migration
+=========
+
+If the TypoScript option was set to a different folder than a FAL storage, ensure to set a local FAL storage
+to this folder.
+
+.. index:: Frontend, TypoScript, PartiallyScanned
diff --git a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
index 754b0ac9a4c8..83fb59abd341 100644
--- a/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
+++ b/typo3/sysext/frontend/Classes/ContentObject/ContentObjectRenderer.php
@@ -37,6 +37,7 @@ use TYPO3\CMS\Core\Resource\FileReference;
 use TYPO3\CMS\Core\Resource\Folder;
 use TYPO3\CMS\Core\Resource\ProcessedFile;
 use TYPO3\CMS\Core\Resource\ResourceFactory;
+use TYPO3\CMS\Core\Resource\StorageRepository;
 use TYPO3\CMS\Core\Service\DependencyOrderingService;
 use TYPO3\CMS\Core\Service\MarkerBasedTemplateService;
 use TYPO3\CMS\Core\TimeTracker\TimeTracker;
@@ -3067,15 +3068,28 @@ class ContentObjectRenderer
         if ($data === '') {
             return '';
         }
-        $data_arr = explode('|', $data);
+        list($possiblePath, $ext_list, $sorting, $reverse, $useFullPath) = GeneralUtility::trimExplode('|', $data);
         // read directory:
         // MUST exist!
         $path = '';
-        if ($this->getTypoScriptFrontendController()->lockFilePath) {
-            // Cleaning name..., only relative paths accepted.
-            $path = $this->clean_directory($data_arr[0]);
-            // See if path starts with lockFilePath, the additional '/' is needed because clean_directory gets rid of it
-            $path = GeneralUtility::isFirstPartOfStr($path . '/', $this->getTypoScriptFrontendController()->lockFilePath) ? $path : '';
+        // proceeds if no '//', '..' or '\' is in the $theFile
+        if (GeneralUtility::validPathStr($possiblePath)) {
+            // Removes all dots, slashes and spaces after a path.
+            $possiblePath = preg_replace('/[\\/\\. ]*$/', '', $possiblePath);
+            if (!GeneralUtility::isAbsPath($possiblePath) && @is_dir($possiblePath)) {
+                // Now check if it matches one of the FAL storages
+                $storageRepository = GeneralUtility::makeInstance(StorageRepository::class);
+                $storages = $storageRepository->findAll();
+                foreach ($storages as $storage) {
+                    if ($storage->getDriverType() === 'Local' && $storage->isPublic() && $storage->isOnline()) {
+                        $folder = $storage->getPublicUrl($storage->getRootLevelFolder(), true);
+                        if (GeneralUtility::isFirstPartOfStr($possiblePath . '/', $folder)) {
+                            $path = $possiblePath;
+                            break;
+                        }
+                    }
+                }
+            }
         }
         if (!$path) {
             return '';
@@ -3084,8 +3098,7 @@ class ContentObjectRenderer
             'files' => [],
             'sorting' => []
         ];
-        $ext_list = strtolower(GeneralUtility::uniqueList($data_arr[1]));
-        $sorting = trim($data_arr[2]);
+        $ext_list = strtolower(GeneralUtility::uniqueList($ext_list));
         // Read dir:
         $d = @dir($path);
         if (is_object($d)) {
@@ -3126,7 +3139,7 @@ class ContentObjectRenderer
         }
         // Sort if required
         if (!empty($items['sorting'])) {
-            if (strtolower(trim($data_arr[3])) !== 'r') {
+            if (strtolower($reverse) !== 'r') {
                 asort($items['sorting']);
             } else {
                 arsort($items['sorting']);
@@ -3135,37 +3148,15 @@ class ContentObjectRenderer
         if (!empty($items['files'])) {
             // Make list
             reset($items['sorting']);
-            $fullPath = trim($data_arr[4]);
             $list_arr = [];
             foreach ($items['sorting'] as $key => $v) {
-                $list_arr[] = $fullPath ? $path . '/' . $items['files'][$key] : $items['files'][$key];
+                $list_arr[] = $useFullPath ? $path . '/' . $items['files'][$key] : $items['files'][$key];
             }
             return implode(',', $list_arr);
         }
         return '';
     }
 
-    /**
-     * Cleans $theDir for slashes in the end of the string and returns the new path, if it exists on the server.
-     *
-     * @param string $theDir Absolute path to directory
-     * @return string The directory path if it existed as was valid to access.
-     * @access private
-     * @see filelist()
-     */
-    public function clean_directory($theDir)
-    {
-        // proceeds if no '//', '..' or '\' is in the $theFile
-        if (GeneralUtility::validPathStr($theDir)) {
-            // Removes all dots, slashes and spaces after a path...
-            $theDir = preg_replace('/[\\/\\. ]*$/', '', $theDir);
-            if (!GeneralUtility::isAbsPath($theDir) && @is_dir($theDir)) {
-                return $theDir;
-            }
-        }
-        return '';
-    }
-
     /**
      * Passes the input value, $theValue, to an instance of "\TYPO3\CMS\Core\Html\HtmlParser"
      * together with the TypoScript options which are first converted from a TS style array
diff --git a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
index 06f0bc9e1815..ab205b42b4d4 100644
--- a/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
+++ b/typo3/sysext/frontend/Classes/Controller/TypoScriptFrontendController.php
@@ -482,12 +482,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface
      */
     public $absRefPrefix = '';
 
-    /**
-     * Lock file path
-     * @var string
-     */
-    public $lockFilePath = '';
-
     /**
      * <A>-tag parameters
      * @var string
@@ -3208,8 +3202,6 @@ class TypoScriptFrontendController implements LoggerAwareInterface
         } else {
             $this->absRefPrefix = '';
         }
-        $this->lockFilePath = '' . $this->config['config']['lockFilePath'];
-        $this->lockFilePath = $this->lockFilePath ?: $GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'];
         $this->ATagParams = trim($this->config['config']['ATagParams']) ? ' ' . trim($this->config['config']['ATagParams']) : '';
         $this->initializeSearchWordDataInTsfe();
         // linkVars
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
index d18ce5c4bfa1..8e5988fc5df5 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/MethodCallMatcher.php
@@ -1521,4 +1521,11 @@ return [
             'Breaking-83122-RemovedStdWrapOptionTCAselectItem.rst',
         ],
     ],
+    'TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer->clean_directory' => [
+        'numberOfMandatoryArguments' => 0,
+        'maximumNumberOfArguments' => 0,
+        'restFiles' => [
+            'Breaking-83256-RemovedLockFilePathFunctionality.rst',
+        ],
+    ],
 ];
diff --git a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
index 39099230fb56..9532841dc3fd 100644
--- a/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
+++ b/typo3/sysext/install/Configuration/ExtensionScanner/Php/PropertyPublicMatcher.php
@@ -219,6 +219,11 @@ return [
             'Breaking-81460-DeprecateGetByTagOnCacheFrontends.rst',
         ],
     ],
+    'TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController->lockFilePath' => [
+        'restFiles' => [
+            'Breaking-83256-RemovedLockFilePathFunctionality.rst',
+        ],
+    ],
 
     // Deprecated public properties
     'TYPO3\CMS\Frontend\Page\PageRepository->workspaceCache' => [
diff --git a/typo3/sysext/t3editor/Resources/Private/tsref.xml b/typo3/sysext/t3editor/Resources/Private/tsref.xml
index f2ccb938f8cc..dc5c4313cb10 100644
--- a/typo3/sysext/t3editor/Resources/Private/tsref.xml
+++ b/typo3/sysext/t3editor/Resources/Private/tsref.xml
@@ -541,11 +541,6 @@ locale_all = da_DK]]></description>
 			<default><![CDATA[
 ]]></default>
 		</property>
-		<property name="lockFilePath" type="string">
-			<description><![CDATA[This is used to lock paths to be "inside" this path.
-Used by "filelist" in stdWrap]]></description>
-			<default><![CDATA[fileadmin/]]></default>
-		</property>
 		<property name="message_page_is_being_generated" type="string">
 			<description><![CDATA[Alternative HTML message that appears if a page is being generated.
 Normally when a page is being generated a temporary copy is stored in the cache-table with an expire-time of 30 seconds.
diff --git a/typo3/sysext/t3editor/Resources/Public/JavaScript/Mode/typoscript/typoscript.js b/typo3/sysext/t3editor/Resources/Public/JavaScript/Mode/typoscript/typoscript.js
index e45785d75be4..261b1247c8bc 100644
--- a/typo3/sysext/t3editor/Resources/Public/JavaScript/Mode/typoscript/typoscript.js
+++ b/typo3/sysext/t3editor/Resources/Public/JavaScript/Mode/typoscript/typoscript.js
@@ -542,7 +542,6 @@
 				'locale_all': kw('locale_all'),
 				'localNesting': kw('localNesting'),
 				'locationData': kw('locationData'),
-				'lockFilePath': kw('lockFilePath'),
 				'lockToIP': kw('lockToIP'),
 				'login': B,
 				'loginUser': A,
-- 
GitLab