Security::getContentSecurityPolicy()   B
last analyzed

Complexity

Conditions 5
Paths 10

Size

Total Lines 28
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 5.0061

Importance

Changes 0
Metric Value
dl 0
loc 28
ccs 15
cts 16
cp 0.9375
rs 8.439
c 0
b 0
f 0
cc 5
eloc 17
nc 10
nop 1
crap 5.0061
1
<?php
2
3
namespace BrainExe\Core\Middleware;
4
5
use BrainExe\Core\Annotations\Inject;
6
use BrainExe\Core\Annotations\Middleware;
7
use Symfony\Component\HttpFoundation\Request;
8
use Symfony\Component\HttpFoundation\Response;
9
10
/**
11
 * @Middleware("Middleware.Security")
12
 */
13
class Security extends AbstractMiddleware
14
{
15
16
    /**
17
     * @var string[]
18
     */
19
    private $allowedUrls;
20
21
    /**
22
     * @var bool
23
     */
24
    private $debug;
25
26
    /**
27
     * @Inject({"%application.allowed_urls%", "%debug%"})
28
     * @param array $allowedUrls
29
     * @param bool $debug
30
     */
31 3
    public function __construct(array $allowedUrls, bool $debug)
32
    {
33 3
        $this->allowedUrls = $allowedUrls;
34 3
        $this->debug       = $debug;
35 3
    }
36
37
    /**
38
     * {@inheritdoc}
39
     */
40 3
    public function processResponse(Request $request, Response $response)
41
    {
42 3
        if (!$request->isXmlHttpRequest()) {
43 2
            $response->headers->set('Content-Security-Policy', $this->getContentSecurityPolicy($request));
44 2
            $response->headers->set('X-Frame-Options', 'DENY');
45 2
            $response->headers->set('X-Content-Type-Options', 'nosniff');
46 2
            $response->headers->set('X-XSS-Protection', '1');
47
48 2
            if ($request->isSecure()) {
49 2
                $response->headers->set('Strict-Transport-Security', 'max-age=31536000 ; includeSubDomains');
50
            }
51
        }
52 3
    }
53
54
    /**
55
     * @param Request $request
56
     * @return string
57
     */
58 2
    protected function getContentSecurityPolicy(Request $request) : string
59
    {
60 2
        $connectSrc = [];
61 2
        $connectSrc[] = "'self'";
62
63 2
        foreach ($this->allowedUrls as $url) {
64 2
            $port = parse_url($url, PHP_URL_PORT);
65 2
            $host = parse_url($url, PHP_URL_HOST) ?: $request->getHost();
66
67 2
            if ($port) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $port of type integer|false is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
68 1
                $host .= ':' . $port;
69
            }
70 2
            $connectSrc[] = $host;
71
        }
72
73
        $parts = [
74 2
            sprintf('default-src \'self\''),
75 2
            'img-src *',
76 2
            'style-src \'self\' \'unsafe-inline\'',
77 2
            sprintf('connect-src %s', implode(' ', $connectSrc)),
78
        ];
79
80 2
        if ($this->debug) {
81
            $parts[] = 'script * ';
82
        }
83
84 2
        return implode('; ', $parts);
85
    }
86
}
87