2 namespace TYPO3\CMS\Core\FormProtection
;
5 * This file is part of the TYPO3 CMS project.
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
14 * The TYPO3 project - inspiring people to share!
17 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication
;
18 use TYPO3\CMS\Core\Localization\LanguageService
;
19 use TYPO3\CMS\Core\Messaging\FlashMessage
;
20 use TYPO3\CMS\Core\Messaging\FlashMessageQueue
;
21 use TYPO3\CMS\Core\Messaging\FlashMessageService
;
22 use TYPO3\CMS\Core\Registry
;
23 use TYPO3\CMS\Core\Utility\GeneralUtility
;
24 use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication
;
27 * This class creates and manages instances of the various form protection
30 * This class provides only static methods. It can not be instantiated.
32 * Usage for the back-end form protection:
35 * $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
38 * Usage for the install tool form protection:
41 * $formProtection = \TYPO3\CMS\Core\FormProtection\FormProtectionFactory::get();
44 class FormProtectionFactory
47 * created instances of form protections using the type as array key
49 * @var array<AbstractFormProtection>
51 protected static $instances = [];
54 * Private constructor to prevent instantiation.
56 private function __construct()
61 * Gets a form protection instance for the requested type or class.
63 * If there already is an existing instance of the requested $classNameOrType, the
64 * existing instance will be returned. If no $classNameOrType is provided, the factory
65 * detects the scope and returns the appropriate form protection object.
67 * @param string $classNameOrType Name of a form protection class, or one
68 * of the pre-defined form protection types:
69 * frontend, backend, installtool
70 * @param array|mixed[] $constructorArguments Arguments for the class-constructor
71 * @return \TYPO3\CMS\Core\FormProtection\AbstractFormProtection the requested instance
73 public static function get($classNameOrType = 'default', ...$constructorArguments)
75 if (isset(self
::$instances[$classNameOrType])) {
76 return self
::$instances[$classNameOrType];
78 if ($classNameOrType === 'default' ||
$classNameOrType === 'installtool' ||
$classNameOrType === 'frontend' ||
$classNameOrType === 'backend') {
79 $classNameAndConstructorArguments = self
::getClassNameAndConstructorArgumentsByType($classNameOrType);
80 self
::$instances[$classNameOrType] = self
::createInstance(...$classNameAndConstructorArguments);
82 self
::$instances[$classNameOrType] = self
::createInstance($classNameOrType, ...$constructorArguments);
84 return self
::$instances[$classNameOrType];
88 * Returns the class name and parameters depending on the given type.
89 * If the type cannot be used currently, protection is disabled.
91 * @param string $type Valid types: default, installtool, frontend, backend. "default" makes an autodetection on the current state
92 * @return array Array of arguments
94 protected static function getClassNameAndConstructorArgumentsByType($type)
96 if (self
::isInstallToolSession() && ($type === 'default' ||
$type === 'installtool')) {
97 $classNameAndConstructorArguments = [
98 InstallToolFormProtection
::class
100 } elseif (self
::isFrontendSession() && ($type === 'default' ||
$type === 'frontend')) {
101 $classNameAndConstructorArguments = [
102 FrontendFormProtection
::class,
103 $GLOBALS['TSFE']->fe_user
105 } elseif (self
::isBackendSession() && ($type === 'default' ||
$type === 'backend')) {
106 $classNameAndConstructorArguments = [
107 BackendFormProtection
::class,
109 GeneralUtility
::makeInstance(Registry
::class),
110 self
::getMessageClosure(
112 GeneralUtility
::makeInstance(FlashMessageService
::class)->getMessageQueueByIdentifier(),
113 (bool
)(TYPO3_REQUESTTYPE
& TYPO3_REQUESTTYPE_AJAX
)
117 // failed to use preferred type, disable form protection
118 $classNameAndConstructorArguments = [
119 DisabledFormProtection
::class
122 return $classNameAndConstructorArguments;
126 * Check if we are in the install tool
130 protected static function isInstallToolSession()
132 return TYPO3_REQUESTTYPE
& TYPO3_REQUESTTYPE_INSTALL
;
136 * Checks if a user is logged in and the session is active.
140 protected static function isBackendSession()
142 return isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof BackendUserAuthentication
&& isset($GLOBALS['BE_USER']->user
['uid']);
146 * Checks if a frontend user is logged in and the session is active.
150 protected static function isFrontendSession()
152 return TYPO3_MODE
=== 'FE' && is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->fe_user
instanceof FrontendUserAuthentication
&& isset($GLOBALS['TSFE']->fe_user
->user
['uid']);
156 * @param LanguageService $languageService
157 * @param FlashMessageQueue $messageQueue
158 * @param bool $isAjaxCall
159 * @internal Only public to be used in tests
162 public static function getMessageClosure(LanguageService
$languageService, FlashMessageQueue
$messageQueue, $isAjaxCall)
164 return function () use ($languageService, $messageQueue, $isAjaxCall) {
165 /** @var FlashMessage $flashMessage */
166 $flashMessage = GeneralUtility
::makeInstance(
168 $languageService->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:error.formProtection.tokenInvalid'),
173 $messageQueue->enqueue($flashMessage);
178 * Creates an instance for the requested class $className
179 * and stores it internally.
181 * @param string $className
182 * @param array|mixed[] $constructorArguments
183 * @throws \InvalidArgumentException
184 * @return AbstractFormProtection
186 protected static function createInstance($className, ...$constructorArguments)
188 if (!class_exists($className)) {
189 throw new \
InvalidArgumentException('$className must be the name of an existing class, but actually was "' . $className . '".', 1285352962);
191 $instance = GeneralUtility
::makeInstance($className, ...$constructorArguments);
192 if (!$instance instanceof AbstractFormProtection
) {
193 throw new \
InvalidArgumentException('$className must be a subclass of ' . AbstractFormProtection
::class . ', but actually was "' . $className . '".', 1285353026);
199 * Sets the instance that will be returned by get() for a specific class
202 * Note: This function is intended for testing purposes only.
205 * @param string $classNameOrType
206 * @param AbstractFormProtection $instance
208 public static function set($classNameOrType, AbstractFormProtection
$instance)
210 self
::$instances[$classNameOrType] = $instance;
214 * Purges all existing instances.
216 * This function is particularly useful when cleaning up in unit testing.
218 public static function purgeInstances()
220 foreach (self
::$instances as $key => $instance) {
221 unset(self
::$instances[$key]);