Skip to content

Commit 89ce62f

Browse files
committed
Use cspScriptNonce when it is available
This allows debugkit to work in CSP controlled environments. Fixes #943
1 parent d4c7d71 commit 89ce62f

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

src/Middleware/DebugKitMiddleware.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,6 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
6969
return $response;
7070
}
7171

72-
return $this->service->injectScripts($row, $response);
72+
return $this->service->injectScripts($row, $request, $response);
7373
}
7474
}

src/ToolbarService.php

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
use DebugKit\Panel\PanelRegistry;
2626
use PDOException;
2727
use Psr\Http\Message\ResponseInterface;
28+
use Psr\Http\Message\ServerRequestInterface;
2829

2930
/**
3031
* Used to create the panels and inject a toolbar into
@@ -337,10 +338,11 @@ public function getToolbarUrl()
337338
* contains HTML and there is a </body> tag.
338339
*
339340
* @param \DebugKit\Model\Entity\Request $row The request data to inject.
341+
* @param \Psr\Http\Message\ServerRequestInterface $request The request to augment.
340342
* @param \Psr\Http\Message\ResponseInterface $response The response to augment.
341343
* @return \Psr\Http\Message\ResponseInterface The modified response
342344
*/
343-
public function injectScripts($row, ResponseInterface $response)
345+
public function injectScripts($row, ServerRequestInterface $request, ResponseInterface $response)
344346
{
345347
$response = $response->withHeader('X-DEBUGKIT-ID', (string)$row->id);
346348
if (strpos($response->getHeaderLine('Content-Type'), 'html') === false) {
@@ -357,13 +359,18 @@ public function injectScripts($row, ResponseInterface $response)
357359
if ($pos === false) {
358360
return $response;
359361
}
362+
$nonce = $request->getAttribute('cspScriptNonce');
363+
if ($nonce) {
364+
$nonce = sprintf(' nonce="%s"', $nonce);
365+
}
360366

361367
$url = Router::url('/', true);
362368
$script = sprintf(
363-
'<script id="__debug_kit_script" data-id="%s" data-url="%s" type="module" src="%s"></script>',
369+
'<script id="__debug_kit_script" data-id="%s" data-url="%s" type="module" src="%s"%s></script>',
364370
$row->id,
365371
$url,
366-
Router::url($this->getToolbarUrl())
372+
Router::url($this->getToolbarUrl()),
373+
$nonce
367374
);
368375
$contents = substr($contents, 0, $pos) . $script . substr($contents, $pos);
369376
$body->rewind();

tests/TestCase/Middleware/DebugKitMiddlewareTest.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ public function setUp(): void
5050
parent::setUp();
5151

5252
$connection = ConnectionManager::get('test');
53-
$this->skipIf($connection->getDriver() instanceof Sqlite, 'Schema insertion/removal breaks SQLite');
5453
$this->oldConfig = Configure::read('DebugKit');
5554
$this->restore = $GLOBALS['__PHPUNIT_BOOTSTRAP'];
5655
unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
@@ -132,6 +131,38 @@ public function testInvokeSaveData()
132131
$this->assertTextEquals($expected, $body);
133132
}
134133

134+
/**
135+
* Ensure data is saved for HTML requests
136+
*
137+
* @return void
138+
*/
139+
public function testInvokeInjectCspNonce()
140+
{
141+
$request = new ServerRequest([
142+
'url' => '/articles',
143+
'environment' => ['REQUEST_METHOD' => 'GET'],
144+
]);
145+
$request = $request->withAttribute('cspScriptNonce', 'csp-nonce');
146+
147+
$response = new Response([
148+
'statusCode' => 200,
149+
'type' => 'text/html',
150+
'body' => '<html><title>test</title><body><p>some text</p></body>',
151+
]);
152+
153+
$handler = $this->handler();
154+
$handler->expects($this->once())
155+
->method('handle')
156+
->willReturn($response);
157+
158+
$middleware = new DebugKitMiddleware();
159+
$response = $middleware->process($request, $handler);
160+
$this->assertInstanceOf(Response::class, $response, 'Should return the response');
161+
162+
$body = (string)$response->getBody();
163+
$this->assertStringContainsString('nonce="csp-nonce"', $body);
164+
}
165+
135166
/**
136167
* Ensure that streaming results are tracked, but not modified.
137168
*

0 commit comments

Comments
 (0)