diff --git a/src/Panel/Document.php b/src/Panel/Document.php index 29c9bfb60a..42aaa665db 100644 --- a/src/Panel/Document.php +++ b/src/Panel/Document.php @@ -291,8 +291,19 @@ public static function response(array $fiber) 'panelUrl' => $uri->path()->toString(true) . '/', ]); + $frameAncestorsOption = $kirby->option('panel.frameAncestors'); + if ($frameAncestorsOption === true) { + $frameAncestors = "'self'"; + } elseif (is_array($frameAncestorsOption)) { + $frameAncestors = "'self' " . implode(' ', $frameAncestorsOption); + } elseif (is_string($frameAncestorsOption)) { + $frameAncestors = $frameAncestorsOption; + } else { + $frameAncestors = "'none'"; + } + return new Response($body, 'text/html', $code, [ - 'Content-Security-Policy' => "frame-ancestors 'none'" + 'Content-Security-Policy' => 'frame-ancestors ' . $frameAncestors ]); } } diff --git a/tests/Panel/DocumentTest.php b/tests/Panel/DocumentTest.php index e540877f8a..40f2d951a9 100644 --- a/tests/Panel/DocumentTest.php +++ b/tests/Panel/DocumentTest.php @@ -356,4 +356,97 @@ public function testResponse(): void $this->assertSame("frame-ancestors 'none'", $response->header('Content-Security-Policy')); $this->assertNotNull($response->body()); } + + /** + * @covers ::response + */ + public function testResponseFrameAncestorsSelf(): void + { + $this->app = $this->app->clone([ + 'options' => [ + 'panel' => [ + 'frameAncestors' => true + ] + ] + ]); + + // create panel dist files first to avoid redirect + Document::link($this->app); + + // get panel response + $response = Document::response([ + 'test' => 'Test' + ]); + + $this->assertInstanceOf('\Kirby\Http\Response', $response); + $this->assertSame(200, $response->code()); + $this->assertSame('text/html', $response->type()); + $this->assertSame('UTF-8', $response->charset()); + $this->assertSame("frame-ancestors 'self'", $response->header('Content-Security-Policy')); + $this->assertNotNull($response->body()); + } + + /** + * @covers ::response + */ + public function testResponseFrameAncestorsArray(): void + { + $this->app = $this->app->clone([ + 'options' => [ + 'panel' => [ + 'frameAncestors' => ['*.example.com', 'https://example.com'] + ] + ] + ]); + + // create panel dist files first to avoid redirect + Document::link($this->app); + + // get panel response + $response = Document::response([ + 'test' => 'Test' + ]); + + $this->assertInstanceOf('\Kirby\Http\Response', $response); + $this->assertSame(200, $response->code()); + $this->assertSame('text/html', $response->type()); + $this->assertSame('UTF-8', $response->charset()); + $this->assertSame( + "frame-ancestors 'self' *.example.com https://example.com", + $response->header('Content-Security-Policy') + ); + $this->assertNotNull($response->body()); + } + + /** + * @covers ::response + */ + public function testResponseFrameAncestorsString(): void + { + $this->app = $this->app->clone([ + 'options' => [ + 'panel' => [ + 'frameAncestors' => '*.example.com https://example.com' + ] + ] + ]); + + // create panel dist files first to avoid redirect + Document::link($this->app); + + // get panel response + $response = Document::response([ + 'test' => 'Test' + ]); + + $this->assertInstanceOf('\Kirby\Http\Response', $response); + $this->assertSame(200, $response->code()); + $this->assertSame('text/html', $response->type()); + $this->assertSame('UTF-8', $response->charset()); + $this->assertSame( + 'frame-ancestors *.example.com https://example.com', + $response->header('Content-Security-Policy') + ); + $this->assertNotNull($response->body()); + } }