Skip to content

Commit

Permalink
Merge pull request #401 from ohader/csp
Browse files Browse the repository at this point in the history
🛠️  [TASK] Handle Content-Security-Policy headers of TYPO3 v12
  • Loading branch information
lochmueller committed Nov 15, 2023
2 parents a990aea + 7f6c18f commit 7bf0ed5
Show file tree
Hide file tree
Showing 10 changed files with 79 additions and 39 deletions.
18 changes: 17 additions & 1 deletion Classes/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
use SFC\Staticfilecache\Generator\PhpGenerator;
use SFC\Staticfilecache\Generator\PlainGenerator;
use SFC\Staticfilecache\Hook\DatamapHook;
use SFC\Staticfilecache\Hook\LogoffFrontendUser;
use SFC\Staticfilecache\Service\ConfigurationService;
use SFC\Staticfilecache\Service\HttpPush\FontHttpPush;
use SFC\Staticfilecache\Service\HttpPush\ImageHttpPush;
Expand All @@ -39,6 +38,7 @@
use SFC\Staticfilecache\Service\ObjectFactoryService;
use TYPO3\CMS\Core\Cache\Backend\NullBackend;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Information\Typo3Version;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Utility\ExtensionUtility;

Expand All @@ -50,6 +50,7 @@ class Configuration extends StaticFileCacheObject
public const EXTENSION_KEY = 'staticfilecache';

protected ConfigurationService $configurationService;
protected Typo3Version $typo3version;

/**
* Configuration constructor.
Expand All @@ -60,6 +61,7 @@ class Configuration extends StaticFileCacheObject
public function __construct()
{
$this->configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
$this->typo3version = GeneralUtility::makeInstance(Typo3Version::class);
}

/**
Expand All @@ -72,6 +74,7 @@ public function extLocalconf(): void
->registerCachingFramework()
->registerGenerators()
->registerHttpPushServices()
->adjustSystemSettings()
;
}

Expand All @@ -88,6 +91,10 @@ public function extTables(): void
*/
protected function registerBackendModule(): self
{
// see `Configuration/Backend/Modules.php` (since TYPO3 v12)
if ($this->typo3version->getMajorVersion() >= 12) {
return $this;
}
ExtensionUtility::registerModule(
'Staticfilecache',
'web',
Expand Down Expand Up @@ -217,4 +224,13 @@ protected function registerHttpPushServices(): self

return $this;
}

protected function adjustSystemSettings(): self
{
if ($this->typo3version->getMajorVersion() >= 12) {
// aim for cacheable frontend responses when using TYPO3's `Content-Security-Policy` behavior
$GLOBALS['TYPO3_CONF_VARS']['FE']['contentSecurityPolicy']['preferCacheableResponse'] = true;
}
return $this;
}
}
45 changes: 23 additions & 22 deletions Classes/Controller/BackendController.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

use TYPO3\CMS\Core\Messaging\AbstractMessage;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use SFC\Staticfilecache\Domain\Repository\PageRepository;
use SFC\Staticfilecache\Domain\Repository\QueueRepository;
use SFC\Staticfilecache\Service\CacheService;
Expand All @@ -18,9 +17,7 @@
use TYPO3\CMS\Backend\Template\ModuleTemplateFactory;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
use TYPO3\CMS\Core\Http\HtmlResponse;
use TYPO3\CMS\Core\Log\LogManager;
use TYPO3\CMS\Core\Messaging\FlashMessage;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Mvc\Controller\ActionController;
Expand All @@ -44,24 +41,21 @@ public function __construct(QueueService $queueService, ModuleTemplateFactory $m

public function listAction(string $filter = ''): ResponseInterface
{
$moduleTemplate = $this->moduleTemplateFactory->create($this->request);

$filter = $this->setFilter($filter);
$this->view->assignMultiple([
$viewVariables = [
'rows' => $this->getCachePagesEntries($filter),
'filter' => $filter,
'pageId' => $this->getCurrentUid(),
'backendDisplayMode' => $this->getDisplayMode(),
]);
];

$moduleTemplate->setContent($this->view->render());
return new HtmlResponse($moduleTemplate->renderContent());
return $this->createModuleTemplate()

Check failure on line 52 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.0, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().

Check failure on line 52 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.1, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().

Check failure on line 52 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.2, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().
->assignMultiple($viewVariables)
->renderResponse('Backend/List');
}

public function boostAction(bool $run = false): ResponseInterface
{
$moduleTemplate = $this->moduleTemplateFactory->create($this->request);

$configurationService = GeneralUtility::makeInstance(ConfigurationService::class);
$queueRepository = GeneralUtility::makeInstance(QueueRepository::class);
if ($run) {
Expand All @@ -77,33 +71,33 @@ public function boostAction(bool $run = false): ResponseInterface

$this->addFlashMessage('Run ' . \count($items) . ' entries', 'Runner', AbstractMessage::OK, true);
}
$this->view->assignMultiple([
$viewVariables = [
'enable' => (bool) $configurationService->get('boostMode'),
'open' => \count($queueRepository->findOpen(99999999)),
'old' => \count($queueRepository->findOldUids()),
]);
];

$moduleTemplate->setContent($this->view->render());
return new HtmlResponse($moduleTemplate->renderContent());
return $this->createModuleTemplate()

Check failure on line 80 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.0, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().

Check failure on line 80 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.1, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().

Check failure on line 80 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.2, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().
->assignMultiple($viewVariables)
->renderResponse('Backend/Boost');
}

public function supportAction(): ResponseInterface
{
$moduleTemplate = $this->moduleTemplateFactory->create($this->request);

$htaccessConfigurationService = GeneralUtility::makeInstance(HtaccessConfigurationService::class);
$environmentService = GeneralUtility::makeInstance(EnvironmentService::class);
$this->view->assignMultiple([
$viewVariables = [
'foundHtaccess' => $htaccessConfigurationService->foundConfigurationInHtaccess(),
'htaccessPaths' => $htaccessConfigurationService->getHtaccessPaths(),
'missingModules' => $htaccessConfigurationService->getMissingApacheModules(),
'useCrawler' => ExtensionManagementUtility::isLoaded('crawler'),
'envInfoLink' => $environmentService->getLink(),
'envInfoMarkdown' => $environmentService->getMarkdown(),
]);
];

$moduleTemplate->setContent($this->view->render());
return new HtmlResponse($moduleTemplate->renderContent());
return $this->createModuleTemplate()

Check failure on line 98 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.0, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().

Check failure on line 98 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.1, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().

Check failure on line 98 in Classes/Controller/BackendController.php

View workflow job for this annotation

GitHub Actions / build (8.2, 11)

Call to an undefined method TYPO3\CMS\Backend\Template\ModuleTemplate::assignMultiple().
->assignMultiple($viewVariables)
->renderResponse('Backend/Boost');
}

/**
Expand Down Expand Up @@ -193,6 +187,13 @@ protected function getDisplayMode(): string
*/
protected function getCurrentUid(): int
{
return (int) GeneralUtility::_GET('id');
return (int)($this->request->getQueryParams()['id'] ?? 0);
}

protected function createModuleTemplate(): ModuleTemplate
{
return $this->moduleTemplateFactory->create($this->request)
->setFlashMessageQueue($this->getFlashMessageQueue())
->setModuleClass('tx-staticfilecache');
}
}
15 changes: 15 additions & 0 deletions Classes/ViewHelpers/Format/StripEmptyVerticalSpacesViewHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
declare(strict_types=1);

namespace SFC\Staticfilecache\ViewHelpers\Format;

use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;

class StripEmptyVerticalSpacesViewHelper extends AbstractViewHelper
{
public function render(): string
{
$content = $this->renderChildren();
return preg_replace('#^\h*\v#ms', '', $content);
}
}
4 changes: 0 additions & 4 deletions Resources/Private/Layouts/Backend.html

This file was deleted.

4 changes: 2 additions & 2 deletions Resources/Private/Partials/Backend/ListEntry.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<tr>
<td>
<f:format.raw>{row.title}</f:format.raw> <i>[{row.uid}]</i>
{row.title -> f:sanitize.html()} <i>[{row.uid}]</i>
</td>
<td><a href="{row.identifier}">{row.identifier}</a>
<td><a href="{row.identifier}" target="_blank">{row.identifier}</a>
<f:if condition="{row.cached}">
<f:then>
<core:icon identifier="status-status-permission-granted"/>
Expand Down
2 changes: 1 addition & 1 deletion Resources/Private/Templates/Backend/Boost.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<f:layout name="Backend"/>
<f:layout name="Module"/>

<f:section name="Content">

Expand Down
2 changes: 1 addition & 1 deletion Resources/Private/Templates/Backend/List.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<f:layout name="Backend"/>
<f:layout name="Module"/>

<f:section name="Content">

Expand Down
2 changes: 1 addition & 1 deletion Resources/Private/Templates/Backend/Support.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<f:layout name="Backend"/>
<f:layout name="Module"/>

<f:section name="Content">

Expand Down
22 changes: 17 additions & 5 deletions Resources/Private/Templates/Htaccess.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
{escaping off}
{namespace sfc=SFC\Staticfilecache\ViewHelpers}
ForceType {contentType}
<sfc:format.stripEmptyVerticalSpaces>
<f:if condition="{sendCacheControlHeader}">
<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType {contentType} {mode}{lifetime}
</IfModule>
</f:if>

<f:if condition="{sendCacheControlHeaderRedirectAfterCacheTimeout}">
<IfModule mod_rewrite.c>
RewriteEngine On
Expand All @@ -22,9 +25,18 @@
</f:if>

<f:if condition="{headers}">
<IfModule mod_headers.c>
<f:for each="{headers}" key="name" as="value">
Header set {name} "{value}"
</f:for>
</IfModule>
<IfModule mod_headers.c>
<f:for each="{headers}" key="name" as="value">
Header set {name} "{value}"
<f:if condition="{name} == 'Content-Security-Policy'">
<f:comment><!--
see https://httpd.apache.org/docs/2.4/mod/mod_headers.html
`%t` results in `t=[unixtime in microseconds]`, thus `&t=` needs to be stripped
--></f:comment>
Header edit Content-Security-Policy (@http-reporting\?csp=report&requestTime=)\d+ $1@t&%t
Header edit Content-Security-Policy (@http-reporting\?csp=report&requestTime=)@t&t=(\d+) $1$2
</f:if>
</f:for>
</IfModule>
</f:if>
</sfc:format.stripEmptyVerticalSpaces>
4 changes: 2 additions & 2 deletions ext_conf_template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ backendDisplayMode = both
debugHeaders = 0

# cat=basic; type=string; label=Valid .htaccess headers: List of headers that are transferred to the .htaccess configuration. E.g. if you use config.additionalHeaders.xxx you can add this headers here. Please change this configuration only, if you know what you do. "Content-Type" is recommended. Note: Content-Type will be added automatically.
validHtaccessHeaders = Content-Type,Content-Language,Link,X-SFC-Tags
validHtaccessHeaders = Content-Type,Content-Language,Content-Security-Policy,Link,X-SFC-Tags

# cat=basic; type=string; label=Valid fallback middleware headers: List of headers that are transferred to the xxx.config.json file. E.g. if you use config.additionalHeaders.xxx and you have useFallbackMiddleware set to true, you can add this headers here. Please change this configuration only, if you know what you do. "Content-Type" is recommended. Note: Content-Type will be added automatically.
validFallbackHeaders = Content-Type,Content-Language,Link,X-SFC-Tags
validFallbackHeaders = Content-Type,Content-Language,Content-Security-Policy,Link,X-SFC-Tags

# cat=basic; type=boolean; label=Disable StaticFileCache in development: When checked, the StaticFileCache won't be generated if in development application context.
disableInDevelopment = 0
Expand Down

0 comments on commit 7bf0ed5

Please sign in to comment.