Skip to content

Commit d71f649

Browse files
committed
TASK: add tests
1 parent d8731f9 commit d71f649

16 files changed

+537
-51
lines changed

.github/workflows/ci.yml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
name: CI
2+
3+
on: [ push ]
4+
5+
jobs:
6+
phpunit:
7+
runs-on: ubuntu-latest
8+
9+
steps:
10+
- uses: actions/checkout@v3
11+
12+
- uses: php-actions/composer@v6
13+
14+
- name: PHPUnit Tests
15+
uses: php-actions/phpunit@v4
16+
with:
17+
php_extensions: xdebug
18+
bootstrap: vendor/autoload.php
19+
configuration: phpunit.xml
20+
coverage_text: true
21+
env:
22+
XDEBUG_MODE: coverage

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
composer.lock
33
vendor
44
Packages
5+
.phpunit.cache

Classes/Command/CspConfigCommandController.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class CspConfigCommandController extends CommandController
2424
*/
2525
protected Nonce $nonce;
2626

27+
/**
28+
* @Flow\Inject
29+
*/
30+
protected PolicyFactory $policyFactory;
31+
2732
/**
2833
* @Flow\InjectConfiguration(path="content-security-policy")
2934
* @var mixed[]
@@ -39,13 +44,13 @@ class CspConfigCommandController extends CommandController
3944
public function showCommand(): void
4045
{
4146
try {
42-
$backendPolicy = PolicyFactory::create(
47+
$backendPolicy = $this->policyFactory->create(
4348
$this->nonce,
4449
$this->configuration['backend'],
4550
$this->configuration['custom-backend']
4651
);
4752

48-
$frontendPolicy = PolicyFactory::create(
53+
$frontendPolicy = $this->policyFactory->create(
4954
$this->nonce,
5055
$this->configuration['default'],
5156
$this->configuration['custom']

Classes/Factory/PolicyFactory.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,19 @@
77
use Flowpack\ContentSecurityPolicy\Exceptions\InvalidDirectiveException;
88
use Flowpack\ContentSecurityPolicy\Model\Nonce;
99
use Flowpack\ContentSecurityPolicy\Model\Policy;
10+
use Neos\Flow\Annotations as Flow;
1011

12+
/**
13+
* @Flow\Scope("singleton")
14+
*/
1115
class PolicyFactory
1216
{
1317
/**
18+
* @param string[][] $defaultDirective
19+
* @param string[][] $customDirective
1420
* @throws InvalidDirectiveException
1521
*/
16-
public static function create(Nonce $nonce, array $defaultDirective, array $customDirective): Policy
22+
public function create(Nonce $nonce, array $defaultDirective, array $customDirective): Policy
1723
{
1824
$directiveCollections = [$defaultDirective, $customDirective];
1925
$defaultDirective = array_shift($directiveCollections);

Classes/Helpers/TagHelper.php

+12-15
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66

77
class TagHelper
88
{
9-
public const NONCE = 'nonce';
10-
119
public static function tagHasAttribute(
1210
string $tag,
1311
string $name,
@@ -18,15 +16,15 @@ public static function tagHasAttribute(
1816
self::buildMatchAttributeNameReqex($name),
1917
$tag
2018
);
21-
} else {
22-
return ! ! preg_match(
23-
self::buildMatchAttributeNameWithSpecificValueReqex(
24-
$name,
25-
$value
26-
),
27-
$tag
28-
);
2919
}
20+
21+
return ! ! preg_match(
22+
self::buildMatchAttributeNameWithSpecificValueReqex(
23+
$name,
24+
$value
25+
),
26+
$tag
27+
);
3028
}
3129

3230
public static function tagChangeAttributeValue(
@@ -63,9 +61,9 @@ function ($hits) use ($name, $value) {
6361
$value.
6462
'"'.
6563
$hits["end"];
66-
} else {
67-
return $hits["start"].' '.$name.$hits["end"];
6864
}
65+
66+
return $hits["start"].' '.$name.$hits["end"];
6967
},
7068
$tag
7169
);
@@ -82,9 +80,8 @@ private static function buildMatchEndOfOpeningTagReqex(): string
8280
return '/(?<start><[a-z]+.*?)(?<end>>|\/>)/';
8381
}
8482

85-
private static function buildMatchAttributeNameWithAnyValueReqex(
86-
string $name
87-
): string {
83+
private static function buildMatchAttributeNameWithAnyValueReqex(string $name): string
84+
{
8885
$nameQuoted = self::escapeReqexCharsInString($name);
8986

9087
return '/(?<pre><.*? )(?<name>'.

Classes/Http/CspHeaderMiddleware.php

+13-6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
class CspHeaderMiddleware implements MiddlewareInterface
2222
{
23+
private const NONCE = 'nonce';
24+
2325
/**
2426
* @Flow\InjectConfiguration(path="enabled")
2527
*/
@@ -35,6 +37,11 @@ class CspHeaderMiddleware implements MiddlewareInterface
3537
*/
3638
protected Nonce $nonce;
3739

40+
/**
41+
* @Flow\Inject
42+
*/
43+
protected PolicyFactory $policyFactory;
44+
3845
/**
3946
* @Flow\InjectConfiguration(path="content-security-policy")
4047
* @var mixed[]
@@ -47,7 +54,7 @@ class CspHeaderMiddleware implements MiddlewareInterface
4754
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
4855
{
4956
$response = $handler->handle($request);
50-
if (!$this->enabled) {
57+
if (! $this->enabled) {
5158
return $response;
5259
}
5360

@@ -79,14 +86,14 @@ private function getPolicyByCurrentContext(ServerRequestInterface $request): Pol
7986
* Neos\Neos\Domain\Service\ContentContext at this point as it throws an error.
8087
*/
8188
if (str_starts_with($request->getUri()->getPath(), '/neos')) {
82-
return PolicyFactory::create(
89+
return $this->policyFactory->create(
8390
$this->nonce,
8491
$this->configuration['backend'],
8592
$this->configuration['custom-backend']
8693
);
8794
}
8895

89-
return PolicyFactory::create(
96+
return $this->policyFactory->create(
9097
$this->nonce,
9198
$this->configuration['default'],
9299
$this->configuration['custom']
@@ -101,11 +108,11 @@ private function addNonceToTags(string $markup): string
101108
return $this->checkTagAndReplaceUsingACallback($tagNames, $markup, function (
102109
$tagMarkup,
103110
) {
104-
if (TagHelper::tagHasAttribute($tagMarkup, TagHelper::NONCE)) {
105-
return TagHelper::tagChangeAttributeValue($tagMarkup, TagHelper::NONCE, $this->nonce->getValue());
111+
if (TagHelper::tagHasAttribute($tagMarkup, self::NONCE)) {
112+
return TagHelper::tagChangeAttributeValue($tagMarkup, self::NONCE, $this->nonce->getValue());
106113
}
107114

108-
return TagHelper::tagAddAttribute($tagMarkup, TagHelper::NONCE, $this->nonce->getValue());
115+
return TagHelper::tagAddAttribute($tagMarkup, self::NONCE, $this->nonce->getValue());
109116
});
110117
}
111118

Classes/Model/Nonce.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ public function getValue(): string
2929
return $this->value;
3030
}
3131

32-
public function __toString()
32+
public function __toString(): string
3333
{
34-
return $this->value;
34+
return $this->getValue();
3535
}
3636

3737
/**

Classes/Model/Policy.php

+11-25
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,9 @@ public function setNonce(Nonce $nonce): Policy
4040
return $this;
4141
}
4242

43-
public function isReportOnly(): bool
44-
{
45-
return $this->reportOnly;
46-
}
47-
4843
public function getSecurityHeaderKey(): string
4944
{
50-
if ($this->isReportOnly()) {
45+
if ($this->reportOnly) {
5146
return self::SECURITY_HEADER_KEY_REPORT_ONLY;
5247
}
5348

@@ -59,10 +54,16 @@ public function getDirectives(): array
5954
return $this->directives;
6055
}
6156

57+
public function hasNonceDirectiveValue(): bool
58+
{
59+
return $this->hasNonceDirectiveValue;
60+
}
61+
6262
/**
63+
* @param string[] $values
6364
* @throws InvalidDirectiveException
6465
*/
65-
public function addDirective(string $directive, $values): self
66+
public function addDirective(string $directive, array $values): self
6667
{
6768
if (! Directive::isValidDirective($directive)) {
6869
throw new InvalidDirectiveException($directive);
@@ -74,16 +75,6 @@ public function addDirective(string $directive, $values): self
7475
return $this;
7576
}
7677

77-
public function getNonce(): Nonce
78-
{
79-
return $this->nonce;
80-
}
81-
82-
public function hasNonceDirectiveValue(): bool
83-
{
84-
return $this->hasNonceDirectiveValue;
85-
}
86-
8778
public function __toString(): string
8879
{
8980
$directives = $this->getDirectives();
@@ -95,26 +86,21 @@ public function __toString(): string
9586
return "$directive $value";
9687
}, $directives, $keys);
9788

98-
return implode(';', $items).';';
89+
return implode('; ', $items).';';
9990
}
10091

10192
private function sanitizeValue(string $value): string
10293
{
103-
if ($this->isSpecialValue($value)) {
94+
if (in_array($value, self::SPECIAL_DIRECTIVES)) {
10495
return "'$value'";
10596
}
10697

10798
if ($value === '{nonce}') {
10899
$this->hasNonceDirectiveValue = true;
109100

110-
return "'nonce-".$this->getNonce()->getValue()."'";
101+
return "'nonce-".$this->nonce->getValue()."'";
111102
}
112103

113104
return $value;
114105
}
115-
116-
private function isSpecialValue(string $directive): bool
117-
{
118-
return in_array($directive, self::SPECIAL_DIRECTIVES);
119-
}
120106
}
+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Unit\Factory;
6+
7+
use Flowpack\ContentSecurityPolicy\Factory\PolicyFactory;
8+
use Flowpack\ContentSecurityPolicy\Model\Directive;
9+
use Flowpack\ContentSecurityPolicy\Model\Nonce;
10+
use Flowpack\ContentSecurityPolicy\Model\Policy;
11+
use PHPUnit\Framework\Attributes\CoversClass;
12+
use PHPUnit\Framework\Attributes\UsesClass;
13+
use PHPUnit\Framework\TestCase;
14+
15+
#[CoversClass(PolicyFactory::class)]
16+
#[UsesClass(Policy::class)]
17+
#[UsesClass(Directive::class)]
18+
class PolicyFactoryTest extends TestCase
19+
{
20+
public function testCreateShouldReturnPolicy(): void
21+
{
22+
$policyFactory = new PolicyFactory();
23+
$nonceMock = $this->createMock(Nonce::class);
24+
25+
$defaultDirective = [
26+
'base-uri' => [
27+
'self',
28+
],
29+
'script-src' => [
30+
'self',
31+
],
32+
];
33+
$customDirective = [
34+
'script-src' => [
35+
'{nonce}',
36+
],
37+
];
38+
39+
$expected = [
40+
'base-uri' => [
41+
"'self'",
42+
],
43+
'script-src' => [
44+
"'self'",
45+
"'nonce-'",
46+
],
47+
];
48+
49+
$result = $policyFactory->create($nonceMock, $defaultDirective, $customDirective);
50+
51+
self::assertSame($expected, $result->getDirectives());
52+
}
53+
}

0 commit comments

Comments
 (0)