Commit 4f913d95 authored by Benni Mack's avatar Benni Mack
Browse files

[TASK] Avoid usages of TYPO3_MODE

All code that is using the constant TYPO3_MODE is hard to test,
as this needs to be encapsulated into various places. All testing framework
places run with TYPO3_MODE=FE which makes it impossible to even
consider making parts of the testing framework compatible running a pure
Frontend-based request in the future.

On top, the constant covers up cross-dependency between core dependencies
(whereas $GLOBALS[TSFE]->fe_user is actually a dependency to EXT:frontend).

Another testing-helper in Extbase's EnvironmentService allows to switch
within Extbase to simulate Frontend behaviour.

Resolves: #91521
Releases: master, 10.4
Change-Id: I85a34029e399b40d0780f907480f9059bfdb0edb
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/64633


Tested-by: default avatarTYPO3com <noreply@typo3.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
parent a104a8d9
......@@ -255,7 +255,7 @@ class ModuleTemplate
{
$this->pageRenderer->loadRequireJsModule('bootstrap');
if (TYPO3_MODE === 'BE' && $this->getBackendUserAuthentication() && !empty($this->getBackendUserAuthentication()->user)) {
if ($this->getBackendUserAuthentication() && !empty($this->getBackendUserAuthentication()->user)) {
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/ContextHelp');
$this->pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/DocumentHeader');
}
......
......@@ -125,7 +125,7 @@ class AuthenticationService extends AbstractAuthenticationService
// Get a hashed password instance for the hash stored in db of this user
$invalidPasswordHashException = null;
try {
$hashInstance = $saltFactory->get($passwordHashInDatabase, TYPO3_MODE);
$hashInstance = $saltFactory->get($passwordHashInDatabase, $this->pObj->loginType);
} catch (InvalidPasswordHashException $invalidPasswordHashException) {
// Could not find a responsible hash algorithm for given password. This is unusual since other
// authentication services would usually be called before this one with higher priority. We thus log
......@@ -140,7 +140,7 @@ class AuthenticationService extends AbstractAuthenticationService
// An instance of the currently configured salted password mechanism
// Don't catch InvalidPasswordHashException here: Only install tool should handle those configuration failures
$defaultHashInstance = $saltFactory->getDefaultHashInstance(TYPO3_MODE);
$defaultHashInstance = $saltFactory->getDefaultHashInstance($this->pObj->loginType);
// We found a hash class that can handle this type of hash
$isValidPassword = $hashInstance->checkPassword($submittedPassword, $passwordHashInDatabase);
......@@ -163,7 +163,7 @@ class AuthenticationService extends AbstractAuthenticationService
if (!$isValidPassword) {
// Failed login attempt - wrong password
$this->writeLogMessage(TYPO3_MODE . ' Authentication failed - wrong password for username \'%s\'', $submittedUsername);
$this->writeLogMessage($this->pObj->loginType . ' Authentication failed - wrong password for username \'%s\'', $submittedUsername);
$message = 'Login-attempt from ###IP###, username \'%s\', password not accepted!';
$this->writelog(SystemLogType::LOGIN, SystemLogLoginAction::ATTEMPT, SystemLogErrorClassification::SECURITY_NOTICE, 1, $message, [$submittedUsername]);
$this->logger->info(sprintf($message, $submittedUsername));
......@@ -191,7 +191,7 @@ class AuthenticationService extends AbstractAuthenticationService
}
// Responsible, authentication ok, domain lock ok. Log successful login and return 'auth ok, do NOT check other services'
$this->writeLogMessage(TYPO3_MODE . ' Authentication successful for username \'%s\'', $submittedUsername);
$this->writeLogMessage($this->pObj->loginType . ' Authentication successful for username \'%s\'', $submittedUsername);
return 200;
}
......@@ -361,7 +361,7 @@ class AuthenticationService extends AbstractAuthenticationService
if (!empty($params)) {
$message = vsprintf($message, $params);
}
if (TYPO3_MODE === 'FE') {
if ($this->pObj->loginType === 'FE') {
$timeTracker = GeneralUtility::makeInstance(TimeTracker::class);
$timeTracker->setTSlogMessage($message);
}
......
......@@ -19,6 +19,7 @@ use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Database\Query\Restriction\FrontendRestrictionContainer;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Implements the repository for record collections.
......@@ -221,13 +222,13 @@ class RecordCollectionRepository
}
/**
* Function to return the current TYPO3_MODE.
* Function to return the current TYPO3_MODE (FE/BE) based on $GLOBALS[TSFE].
* This function can be mocked in unit tests to be able to test frontend behaviour.
*
* @return string
*/
protected function getEnvironmentMode()
protected function getEnvironmentMode(): string
{
return TYPO3_MODE;
return ($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController ? 'FE' : 'BE';
}
}
......@@ -23,6 +23,7 @@ use TYPO3\CMS\Core\Messaging\FlashMessageService;
use TYPO3\CMS\Core\Registry;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* This class creates and manages instances of the various form protection
......@@ -150,7 +151,7 @@ class FormProtectionFactory
*/
protected static function isFrontendSession()
{
return TYPO3_MODE === 'FE' && is_object($GLOBALS['TSFE']) && $GLOBALS['TSFE']->fe_user instanceof FrontendUserAuthentication && isset($GLOBALS['TSFE']->fe_user->user['uid']);
return ($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController && $GLOBALS['TSFE']->fe_user instanceof FrontendUserAuthentication && isset($GLOBALS['TSFE']->fe_user->user['uid']);
}
/**
......
......@@ -19,6 +19,8 @@ use TYPO3\CMS\Core\Authentication\AbstractUserAuthentication;
use TYPO3\CMS\Core\Exception;
use TYPO3\CMS\Core\Messaging\Renderer\FlashMessageRendererInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\Authentication\FrontendUserAuthentication;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* A class which collects and renders flash messages.
......@@ -200,7 +202,10 @@ class FlashMessageQueue extends \SplQueue implements \JsonSerializable
*/
protected function getUserByContext()
{
return TYPO3_MODE === 'BE' ? $GLOBALS['BE_USER'] : $GLOBALS['TSFE']->fe_user;
if (($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController && $GLOBALS['TSFE']->fe_user instanceof FrontendUserAuthentication) {
return $GLOBALS['TSFE']->fe_user;
}
return $GLOBALS['BE_USER'];
}
/**
......
......@@ -22,6 +22,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
use TYPO3\CMS\Extbase\Persistence\RepositoryInterface;
use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController;
/**
* Abstract repository implementing the basic repository methods
......@@ -292,13 +293,13 @@ abstract class AbstractRepository implements RepositoryInterface, SingletonInter
}
/**
* Function to return the current TYPO3_MODE.
* Function to return the current TYPO3_MODE based on $GLOBALS['TSFE'].
* This function can be mocked in unit tests to be able to test frontend behaviour.
*
* @return string
*/
protected function getEnvironmentMode()
{
return TYPO3_MODE;
return ($GLOBALS['TSFE'] ?? null) instanceof TypoScriptFrontendController ? 'FE' : 'BE';
}
}
......@@ -9,7 +9,5 @@ defined('TYPO3_MODE') or die();
$GLOBALS['TYPO3_CONF_VARS']['FE']['debug'] = false;
// Register hooks for frontend test
if (TYPO3_MODE === 'FE') {
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Core/TypoScript/TemplateService']['runThroughTemplatesPostProcessing']['FunctionalTest'] =
\TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Hook\TypoScriptInstructionModifier::class . '->apply';
}
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['Core/TypoScript/TemplateService']['runThroughTemplatesPostProcessing']['FunctionalTest'] =
\TYPO3\TestingFramework\Core\Functional\Framework\Frontend\Hook\TypoScriptInstructionModifier::class . '->apply';
......@@ -136,6 +136,7 @@ class AuthenticationServiceTest extends UnitTestCase
{
$subject = new AuthenticationService();
$pObjProphecy = $this->prophesize(AbstractUserAuthentication::class);
$pObjProphecy->loginType = 'BE';
$loggerProphecy = $this->prophesize(Logger::class);
$subject->setLogger($loggerProphecy->reveal());
$subject->initAuth(
......@@ -164,6 +165,7 @@ class AuthenticationServiceTest extends UnitTestCase
{
$subject = new AuthenticationService();
$pObjProphecy = $this->prophesize(AbstractUserAuthentication::class);
$pObjProphecy->loginType = 'BE';
$loggerProphecy = $this->prophesize(Logger::class);
$subject->setLogger($loggerProphecy->reveal());
$subject->initAuth(
......@@ -193,6 +195,7 @@ class AuthenticationServiceTest extends UnitTestCase
{
$subject = new AuthenticationService();
$pObjProphecy = $this->prophesize(AbstractUserAuthentication::class);
$pObjProphecy->loginType = 'BE';
$loggerProphecy = $this->prophesize(Logger::class);
$subject->setLogger($loggerProphecy->reveal());
$subject->initAuth(
......@@ -222,6 +225,7 @@ class AuthenticationServiceTest extends UnitTestCase
{
$subject = new AuthenticationService();
$pObjProphecy = $this->prophesize(AbstractUserAuthentication::class);
$pObjProphecy->loginType = 'BE';
$loggerProphecy = $this->prophesize(Logger::class);
$subject->setLogger($loggerProphecy->reveal());
$subject->initAuth(
......
......@@ -25,6 +25,11 @@ use TYPO3\CMS\Core\SingletonInterface;
*/
class EnvironmentService implements SingletonInterface
{
/**
* @var bool|null
*/
protected $isFrontendMode;
/**
* Detects if TYPO3_MODE is defined and its value is "FE"
*
......@@ -32,6 +37,10 @@ class EnvironmentService implements SingletonInterface
*/
public function isEnvironmentInFrontendMode(): bool
{
$this->initialize();
if ($this->isFrontendMode !== null) {
return $this->isFrontendMode;
}
return (defined('TYPO3_MODE') && TYPO3_MODE === 'FE') ?: false;
}
......@@ -42,6 +51,27 @@ class EnvironmentService implements SingletonInterface
*/
public function isEnvironmentInBackendMode(): bool
{
return (defined('TYPO3_MODE') && TYPO3_MODE === 'BE') ?: false;
return !$this->isEnvironmentInFrontendMode();
}
protected function initialize(): void
{
if ($this->isFrontendMode !== null) {
return;
}
if (defined('TYPO3_MODE')) {
$this->isFrontendMode = TYPO3_MODE === 'FE';
}
}
/**
* A helper method for tests to simulate TYPO3_MODE behavior, should only be used within TYPO3 Core
*
* @param bool $isFrontendMode
* @internal only used for testing purposes and can be removed at any time.
*/
public function setFrontendMode(bool $isFrontendMode): void
{
$this->isFrontendMode = $isFrontendMode;
}
}
......@@ -1008,7 +1008,7 @@ class FormRuntime implements RootRenderableInterface, \ArrayAccess
$pageId = 0;
$languageId = (int)GeneralUtility::makeInstance(Context::class)->getPropertyFromAspect('language', 'id', 0);
if (TYPO3_MODE === 'FE') {
if ($this->getTypoScriptFrontendController() !== null) {
$pageId = $this->getTypoScriptFrontendController()->id;
}
......@@ -1088,10 +1088,10 @@ class FormRuntime implements RootRenderableInterface, \ArrayAccess
}
/**
* @return TypoScriptFrontendController
* @return TypoScriptFrontendController|null
*/
protected function getTypoScriptFrontendController(): TypoScriptFrontendController
protected function getTypoScriptFrontendController(): ?TypoScriptFrontendController
{
return $GLOBALS['TSFE'];
return $GLOBALS['TSFE'] ?? null;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment