]> BookStack Code Mirror - bookstack/commitdiff
CSP: Updated handling of drawio URL to consider port
authorDan Brown <redacted>
Sun, 14 Jul 2024 15:06:18 +0000 (16:06 +0100)
committerDan Brown <redacted>
Sun, 14 Jul 2024 15:06:18 +0000 (16:06 +0100)
Previously if a custom port was used in the DRAWIO option it would not
be considered in the CSP handling, which would block loading.

Added test to cover.
For #5107

app/Util/CspService.php
tests/SecurityHeaderTest.php

index 227ec8e0b3db683d0b17d98c3139feac406bc371..4262b5c98f8071828eacc073d92d9522b7beabbe 100644 (file)
@@ -133,18 +133,30 @@ class CspService
 
     protected function getAllowedIframeSources(): array
     {
-        $sources = config('app.iframe_sources', '');
-        $hosts = array_filter(explode(' ', $sources));
+        $sources = explode(' ', config('app.iframe_sources', ''));
+        $sources[] = $this->getDrawioHost();
 
-        // Extract drawing service url to allow embedding if active
+        return array_filter($sources);
+    }
+
+    /**
+     * Extract the host name of the configured drawio URL for use in CSP.
+     * Returns empty string if not in use.
+     */
+    protected function getDrawioHost(): string
+    {
         $drawioConfigValue = config('services.drawio');
-        if ($drawioConfigValue) {
-            $drawioSource = is_string($drawioConfigValue) ? $drawioConfigValue : 'https://embed.diagrams.net/';
-            $drawioSourceParsed = parse_url($drawioSource);
-            $drawioHost = $drawioSourceParsed['scheme'] . '://' . $drawioSourceParsed['host'];
-            $hosts[] = $drawioHost;
+        if (!$drawioConfigValue) {
+            return '';
+        }
+
+        $drawioSource = is_string($drawioConfigValue) ? $drawioConfigValue : 'https://embed.diagrams.net/';
+        $drawioSourceParsed = parse_url($drawioSource);
+        $drawioHost = $drawioSourceParsed['scheme'] . '://' . $drawioSourceParsed['host'];
+        if (isset($drawioSourceParsed['port'])) {
+            $drawioHost .= ':' . $drawioSourceParsed['port'];
         }
 
-        return $hosts;
+        return $drawioHost;
     }
 }
index d369e695c516a8fc2d0093b9bbc0afc39f66a650..5d354e5539e9dcdd27bb05df788a61510c162068 100644 (file)
@@ -139,6 +139,18 @@ class SecurityHeaderTest extends TestCase
         $this->assertEquals('frame-src \'self\' https://example.com https://diagrams.example.com', $scriptHeader);
     }
 
+    public function test_frame_src_csp_header_drawio_host_includes_port_if_existing()
+    {
+        config()->set([
+            'app.iframe_sources' => 'https://example.com',
+            'services.drawio'    => 'https://diagrams.example.com:8080/testing?cat=dog',
+        ]);
+
+        $resp = $this->get('/');
+        $scriptHeader = $this->getCspHeader($resp, 'frame-src');
+        $this->assertEquals('frame-src \'self\' https://example.com https://diagrams.example.com:8080', $scriptHeader);
+    }
+
     public function test_cache_control_headers_are_set_on_responses()
     {
         // Public access