|
4 | 4 |
|
5 | 5 | namespace Flowpack\ContentSecurityPolicy\Factory; |
6 | 6 |
|
| 7 | +use Flowpack\ContentSecurityPolicy\Exceptions\DirectivesNormalizerException; |
7 | 8 | use Flowpack\ContentSecurityPolicy\Exceptions\InvalidDirectiveException; |
| 9 | +use Flowpack\ContentSecurityPolicy\Helpers\DirectivesNormalizer; |
8 | 10 | use Flowpack\ContentSecurityPolicy\Model\Nonce; |
9 | 11 | use Flowpack\ContentSecurityPolicy\Model\Policy; |
10 | 12 | use Neos\Flow\Annotations as Flow; |
| 13 | +use Psr\Log\LoggerInterface; |
11 | 14 |
|
12 | 15 | /** |
13 | 16 | * @Flow\Scope("singleton") |
14 | 17 | */ |
15 | 18 | class PolicyFactory |
16 | 19 | { |
17 | 20 | /** |
18 | | - * @param string[][] $defaultDirectives |
19 | | - * @param string[][] $customDirectives |
| 21 | + * @Flow\InjectConfiguration(path="throw-invalid-directive-exception") |
| 22 | + */ |
| 23 | + protected bool $throwInvalidDirectiveException; |
| 24 | + |
| 25 | + /** |
| 26 | + * @Flow\Inject |
| 27 | + */ |
| 28 | + protected LoggerInterface $logger; |
| 29 | + |
| 30 | + /** |
| 31 | + * @Flow\Inject |
| 32 | + * |
| 33 | + */ |
| 34 | + |
| 35 | + /** |
| 36 | + * @param array<string, array<string|int, string|bool>> $defaultDirectives |
| 37 | + * @param array<string, array<string|int, string|bool>> $customDirectives |
20 | 38 | * @throws InvalidDirectiveException |
| 39 | + * @throws DirectivesNormalizerException |
21 | 40 | */ |
22 | 41 | public function create(Nonce $nonce, array $defaultDirectives, array $customDirectives): Policy |
23 | 42 | { |
24 | | - $resultDirectives = $defaultDirectives; |
25 | | - foreach ($customDirectives as $key => $customDirective) { |
| 43 | + $normalizedDefaultDirectives = DirectivesNormalizer::normalize($defaultDirectives, $this->logger); |
| 44 | + $normalizedCustomDirectives = DirectivesNormalizer::normalize($customDirectives, $this->logger); |
| 45 | + |
| 46 | + $resultDirectives = $normalizedDefaultDirectives; |
| 47 | + foreach ($normalizedCustomDirectives as $key => $customDirective) { |
26 | 48 | if (array_key_exists($key, $resultDirectives)) { |
27 | 49 | $resultDirectives[$key] = array_merge($resultDirectives[$key], $customDirective); |
28 | 50 | } else { |
29 | 51 | // Custom directive is not present in default, still needs to be added. |
30 | 52 | $resultDirectives[$key] = $customDirective; |
31 | 53 | } |
32 | | - |
33 | 54 | $resultDirectives[$key] = array_unique($resultDirectives[$key]); |
34 | 55 | } |
35 | 56 |
|
36 | 57 | $policy = new Policy(); |
37 | 58 | $policy->setNonce($nonce); |
38 | 59 |
|
39 | 60 | foreach ($resultDirectives as $directive => $values) { |
40 | | - $policy->addDirective($directive, $values); |
| 61 | + try { |
| 62 | + $policy->addDirective($directive, $values); |
| 63 | + } catch (InvalidDirectiveException $e |
| 64 | + ) { |
| 65 | + if ($this->throwInvalidDirectiveException) { |
| 66 | + // For development we want to make sure directives are configured correctly. |
| 67 | + throw $e; |
| 68 | + } else { |
| 69 | + // In production we just log the error and continue. If a directive is invalid, we still |
| 70 | + // want to apply the rest of the policy. |
| 71 | + $this->logger->critical($e->getMessage()); |
| 72 | + continue; |
| 73 | + } |
| 74 | + } |
41 | 75 | } |
42 | 76 |
|
43 | 77 | return $policy; |
|
0 commit comments