Completed
Pull Request — master (#35)
by
unknown
01:22
created

Policy::addNonceForDirective()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\Csp\Policies;
4
5
use Spatie\Csp\Value;
6
use Spatie\Csp\Directive;
7
use Illuminate\Http\Request;
8
use Spatie\Csp\Exceptions\InvalidDirective;
9
use Symfony\Component\HttpFoundation\Response;
10
11
abstract class Policy
12
{
13
    protected $directives = [];
14
15
    protected $reportOnly = false;
16
17
    abstract public function configure();
18
19
    /**
20
     * @param string $directive
21
     * @param string|array $values
22
     *
23
     * @return \Spatie\Csp\Policies\Policy
24
     *
25
     * @throws \Spatie\Csp\Exceptions\InvalidDirective
26
     */
27
    public function addDirective(string $directive, $values): self
28
    {
29
        $this->guardAgainstInvalidDirectives($directive);
30
31
        $rules = array_flatten(array_map(function ($values) {
32
            return array_filter(explode(' ', $values), function ($value) {
33
                return !empty($value);
34
            });
35
        }, array_wrap($values)));
36
37
        foreach ($rules as $rule) {
38
            $sanitizedValue = $this->sanitizeValue($rule);
39
40
            if (! in_array($sanitizedValue, $this->directives[$directive] ?? [])) {
41
                $this->directives[$directive][] = $sanitizedValue;
42
            }
43
        }
44
45
        return $this;
46
    }
47
48
    public function reportOnly(): self
49
    {
50
        $this->reportOnly = true;
51
52
        return $this;
53
    }
54
55
    public function enforce(): self
56
    {
57
        $this->reportOnly = false;
58
59
        return $this;
60
    }
61
62
    public function reportTo(string $uri): self
63
    {
64
        $this->directives['report-uri'] = [$uri];
65
66
        return $this;
67
    }
68
69
    public function shouldBeApplied(Request $request, Response $response): bool
0 ignored issues
show
Unused Code introduced by
The parameter $request is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $response is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
70
    {
71
        return config('csp.enabled');
72
    }
73
74
    public function addNonceForDirective(string $directive): self
75
    {
76
        return $this->addDirective($directive, "'nonce-".app('csp-nonce')."'");
77
    }
78
79
    public function applyTo(Response $response)
80
    {
81
        $this->configure();
82
83
        $headerName = $this->reportOnly
84
            ? 'Content-Security-Policy-Report-Only'
85
            : 'Content-Security-Policy';
86
87
        if ($response->headers->has($headerName)) {
88
            return;
89
        }
90
91
        $response->headers->set($headerName, (string) $this);
92
    }
93
94
    public function __toString()
95
    {
96
        return collect($this->directives)
97
            ->map(function (array $values, string $directive) {
98
                $valueString = implode(' ', $values);
99
100
                return "{$directive} {$valueString}";
101
            })
102
            ->implode(';');
103
    }
104
105
    protected function guardAgainstInvalidDirectives(string $directive)
106
    {
107
        if (! Directive::isValid($directive)) {
108
            throw InvalidDirective::notSupported($directive);
109
        }
110
    }
111
112
    protected function isHash(string $value): bool
113
    {
114
        $acceptableHashingAlgorithms = [
115
          'sha256',
116
          'sha384',
117
          'sha512',
118
        ];
119
120
        return in_array(explode('-', $value)[0], $acceptableHashingAlgorithms);
121
    }
122
123
    protected function sanitizeValue(string $value): string
124
    {
125
        $specialDirectiveValues = [
126
            Value::NONE,
127
            Value::REPORT_SAMPLE,
128
            Value::SELF,
129
            Value::STRICT_DYNAMIC,
130
            Value::UNSAFE_EVAL,
131
            Value::UNSAFE_INLINE,
132
        ];
133
134
        if (in_array($value, $specialDirectiveValues) || $this->isHash($value)) {
135
            return "'{$value}'";
136
        }
137
138
        return $value;
139
    }
140
}
141