‪TYPO3CMS  ‪main
PolicyProvider.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Psr\EventDispatcher\EventDispatcherInterface;
21 use Psr\Http\Message\ServerRequestInterface;
22 use Psr\Http\Message\UriInterface;
31 
37 final class ‪PolicyProvider
38 {
39  protected const ‪REPORTING_URI = '@http-reporting';
40 
41  public function ‪__construct(
42  private readonly ‪RequestId $requestId,
43  private readonly ‪SiteFinder $siteFinder,
44  private readonly ‪PolicyRegistry $policyRegistry,
45  private readonly EventDispatcherInterface $eventDispatcher,
46  private readonly ‪MutationRepository $mutationRepository,
47  private readonly ‪BackendEntryPointResolver $backendEntryPointResolver,
48  ) {}
49 
53  public function ‪provideFor(‪Scope $scope): ‪Policy
54  {
55  // @todo add policy cache per scope
56  $defaultPolicy = new ‪Policy();
57  $mutationCollections = iterator_to_array(
58  $this->mutationRepository->findByScope($scope),
59  false
60  );
61  // add temporary(!) mutations that were collected during processing this request
62  if ($this->policyRegistry->hasMutationCollections()) {
63  $mutationCollections = array_merge(
64  $mutationCollections,
65  $this->policyRegistry->getMutationCollections()
66  );
67  }
68  // apply all mutations to current policy
69  $currentPolicy = $defaultPolicy->mutate(...$mutationCollections);
70  // allow other components to modify the current policy individually via PSR-14 event
71  $event = new ‪PolicyMutatedEvent($scope, $defaultPolicy, $currentPolicy, ...$mutationCollections);
72  $this->eventDispatcher->dispatch($event);
73  return $event->getCurrentPolicy();
74  }
75 
76  public function ‪getReportingUrlFor(‪Scope $scope, ServerRequestInterface $request): ?UriInterface
77  {
78  $value = ‪$GLOBALS['TYPO3_CONF_VARS'][$scope->type->abbreviate()]['contentSecurityPolicyReportingUrl'] ?? null;
79  if (!empty($value) && is_string($value)) {
80  try {
81  return new ‪Uri($value);
82  } catch (\InvalidArgumentException) {
83  return null;
84  }
85  }
86  $uriBase = $this->‪getDefaultReportingUriBase($scope, $request);
87  return $uriBase->withQuery($uriBase->getQuery() . '&requestTime=' . $this->requestId->microtime);
88  }
89 
93  public function ‪getDefaultReportingUriBase(‪Scope $scope, ServerRequestInterface $request, bool $absolute = true): UriInterface
94  {
95  $normalizedParams = $request->getAttribute('normalizedParams') ?? ‪NormalizedParams::createFromRequest($request);
96  // resolve URI from current site language or site default language in frontend scope
97  if ($scope->‪isFrontendSite()) {
98  $site = $this->‪resolveSite($scope);
99  $siteLanguage = $request->getAttribute('siteLanguage');
100  $siteLanguage = $siteLanguage instanceof ‪SiteLanguage ? $siteLanguage : $site->getDefaultLanguage();
101  $uri = $siteLanguage->‪getBase();
102  $uri = $uri->withPath(rtrim($uri->getPath(), '/') . '/');
103  // otherwise fall back to current request URI
104  } else {
105  $uri = new ‪Uri($normalizedParams->getSitePath());
106  }
107  // add backend entryPoint route prefix in backend scope
108  if ($scope->type->isBackend()) {
109  $uri = $this->backendEntryPointResolver->getUriFromRequest($request);
110  }
111  // prefix current require scheme, host, port in case it's not given
112  if ($absolute && ($uri->getScheme() === '' || $uri->getHost() === '')) {
113  $current = new ‪Uri($normalizedParams->getSiteUrl());
114  $uri = $uri
115  ->withScheme($current->getScheme())
116  ->withHost($current->getHost())
117  ->withPort($current->getPort());
118  } elseif (!$absolute && $uri->getScheme() !== '' && $uri->getHost() !== '') {
119  $uri = $uri->withScheme('')->withHost('')->withPort(null);
120  }
121  // `/en/@http-reporting?csp=report` (relative)
122  // `https://ip12.anyhost.it:8443/en/@http-reporting?csp=report` (absolute)
123  return $uri->withPath($uri->getPath() . self::REPORTING_URI)->withQuery('csp=report');
124  }
125 
126  private function ‪resolveSite(‪Scope $scope): ‪Site
127  {
128  return $scope->site ?? $this->siteFinder->getSiteByIdentifier($scope->siteIdentifier);
129  }
130 }
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyRegistry
Definition: PolicyRegistry.php:28
‪TYPO3\CMS\Core\Site\SiteFinder
Definition: SiteFinder.php:31
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Policy
Definition: Policy.php:31
‪TYPO3\CMS\Core\Http\Uri
Definition: Uri.php:30
‪TYPO3\CMS\Core\Site\Entity\Site
Definition: Site.php:42
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage
Definition: SiteLanguage.php:27
‪TYPO3\CMS\Core\Site\Entity\SiteLanguage\getBase
‪getBase()
Definition: SiteLanguage.php:179
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Event\PolicyMutatedEvent
Definition: PolicyMutatedEvent.php:26
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider\REPORTING_URI
‪const REPORTING_URI
Definition: PolicyProvider.php:39
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationRepository
Definition: MutationRepository.php:29
‪TYPO3\CMS\Core\Core\RequestId
Definition: RequestId.php:26
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider\getReportingUrlFor
‪getReportingUrlFor(Scope $scope, ServerRequestInterface $request)
Definition: PolicyProvider.php:76
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope
Definition: Scope.php:30
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy
Definition: ConsumableNonce.php:18
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider\__construct
‪__construct(private readonly RequestId $requestId, private readonly SiteFinder $siteFinder, private readonly PolicyRegistry $policyRegistry, private readonly EventDispatcherInterface $eventDispatcher, private readonly MutationRepository $mutationRepository, private readonly BackendEntryPointResolver $backendEntryPointResolver,)
Definition: PolicyProvider.php:41
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:25
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope\isFrontendSite
‪isFrontendSite()
Definition: Scope.php:126
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider\getDefaultReportingUriBase
‪getDefaultReportingUriBase(Scope $scope, ServerRequestInterface $request, bool $absolute=true)
Definition: PolicyProvider.php:93
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider\provideFor
‪provideFor(Scope $scope)
Definition: PolicyProvider.php:53
‪TYPO3\CMS\Core\Http\NormalizedParams\createFromRequest
‪static static createFromRequest(ServerRequestInterface $request, array $systemConfiguration=null)
Definition: NormalizedParams.php:840
‪TYPO3\CMS\Core\Routing\BackendEntryPointResolver
Definition: BackendEntryPointResolver.php:29
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider
Definition: PolicyProvider.php:38
‪TYPO3\CMS\Core\Http\NormalizedParams
Definition: NormalizedParams.php:38
‪TYPO3\CMS\Core\Security\ContentSecurityPolicy\PolicyProvider\resolveSite
‪resolveSite(Scope $scope)
Definition: PolicyProvider.php:126