]> BookStack Code Mirror - bookstack/blob - app/Util/CspService.php
Added test for logical-theme-system command registration
[bookstack] / app / Util / CspService.php
1 <?php
2
3 namespace BookStack\Util;
4
5 use Illuminate\Support\Str;
6 use Symfony\Component\HttpFoundation\Response;
7
8 class CspService
9 {
10     /** @var string */
11     protected $nonce;
12
13     public function __construct(string $nonce = '')
14     {
15         $this->nonce = $nonce ?: Str::random(24);
16     }
17
18     /**
19      * Get the nonce value for CSP.
20      */
21     public function getNonce(): string
22     {
23         return $this->nonce;
24     }
25
26     /**
27      * Sets CSP 'script-src' headers to restrict the forms of script that can
28      * run on the page.
29      */
30     public function setScriptSrc(Response $response)
31     {
32         if (config('app.allow_content_scripts')) {
33             return;
34         }
35
36         $parts = [
37             'http:',
38             'https:',
39             '\'nonce-' . $this->nonce . '\'',
40             '\'strict-dynamic\'',
41         ];
42
43         $value = 'script-src ' . implode(' ', $parts);
44         $response->headers->set('Content-Security-Policy', $value, false);
45     }
46
47     /**
48      * Sets CSP "frame-ancestors" headers to restrict the hosts that BookStack can be
49      * iframed within. Also adjusts the cookie samesite options so that cookies will
50      * operate in the third-party context.
51      */
52     public function setFrameAncestors(Response $response)
53     {
54         $iframeHosts = $this->getAllowedIframeHosts();
55         array_unshift($iframeHosts, "'self'");
56         $cspValue = 'frame-ancestors ' . implode(' ', $iframeHosts);
57         $response->headers->set('Content-Security-Policy', $cspValue, false);
58     }
59
60     /**
61      * Check if the user has configured some allowed iframe hosts.
62      */
63     public function allowedIFrameHostsConfigured(): bool
64     {
65         return count($this->getAllowedIframeHosts()) > 0;
66     }
67
68     /**
69      * Sets CSP 'object-src' headers to restrict the types of dynamic content
70      * that can be embedded on the page.
71      */
72     public function setObjectSrc(Response $response)
73     {
74         if (config('app.allow_content_scripts')) {
75             return;
76         }
77
78         $response->headers->set('Content-Security-Policy', 'object-src \'self\'', false);
79     }
80
81     /**
82      * Sets CSP 'base-uri' headers to restrict what base tags can be set on
83      * the page to prevent manipulation of relative links.
84      */
85     public function setBaseUri(Response $response)
86     {
87         $response->headers->set('Content-Security-Policy', 'base-uri \'self\'', false);
88     }
89
90     protected function getAllowedIframeHosts(): array
91     {
92         $hosts = config('app.iframe_hosts', '');
93
94         return array_filter(explode(' ', $hosts));
95     }
96 }