Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🛠️ [TASK] Handle Content-Security-Policy headers of TYPO3 v12 #401

Merged
merged 3 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 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 @@

$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 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
Loading