Skip to content

Commit 663491e

Browse files
authored
Merge pull request #944 from cakephp/fix-csp-nonce
Use cspScriptNonce when it is available
2 parents d4c7d71 + caa7d6d commit 663491e

File tree

4 files changed

+48
-9
lines changed

4 files changed

+48
-9
lines changed

Diff for: src/Middleware/DebugKitMiddleware.php

+1-1
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
}

Diff for: src/ToolbarService.php

+10-3
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();

Diff for: tests/TestCase/Middleware/DebugKitMiddlewareTest.php

+33-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ 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');
53+
$this->skipIf($connection->getDriver() instanceof Sqlite, 'This test fails in CI with sqlite');
5454
$this->oldConfig = Configure::read('DebugKit');
5555
$this->restore = $GLOBALS['__PHPUNIT_BOOTSTRAP'];
5656
unset($GLOBALS['__PHPUNIT_BOOTSTRAP']);
@@ -132,6 +132,38 @@ public function testInvokeSaveData()
132132
$this->assertTextEquals($expected, $body);
133133
}
134134

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

Diff for: tests/TestCase/ToolbarServiceTest.php

+4-4
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ public function testInjectScriptsLastBodyTag()
303303
$bar = new ToolbarService($this->events, []);
304304
$bar->loadPanels();
305305
$row = $bar->saveData($request, $response);
306-
$response = $bar->injectScripts($row, $response);
306+
$response = $bar->injectScripts($row, $request, $response);
307307

308308
$timeStamp = filemtime(Plugin::path('DebugKit') . 'webroot' . DS . 'js' . DS . 'main.js');
309309

@@ -335,7 +335,7 @@ public function testInjectScriptsFileBodies()
335335
$bar = new ToolbarService($this->events, []);
336336
$row = new RequestEntity(['id' => 'abc123']);
337337

338-
$result = $bar->injectScripts($row, $response);
338+
$result = $bar->injectScripts($row, $request, $response);
339339
$this->assertInstanceOf('Cake\Http\Response', $result);
340340
$this->assertSame(file_get_contents(__FILE__), '' . $result->getBody());
341341
$this->assertTrue($result->hasHeader('X-DEBUGKIT-ID'), 'Should have a tracking id');
@@ -361,7 +361,7 @@ public function testInjectScriptsStreamBodies()
361361
$bar = new ToolbarService($this->events, []);
362362
$row = new RequestEntity(['id' => 'abc123']);
363363

364-
$result = $bar->injectScripts($row, $response);
364+
$result = $bar->injectScripts($row, $request, $response);
365365
$this->assertInstanceOf('Cake\Http\Response', $result);
366366
$this->assertSame('I am a teapot!', (string)$response->getBody());
367367
}
@@ -385,7 +385,7 @@ public function testInjectScriptsNoModifyResponse()
385385
$bar->loadPanels();
386386

387387
$row = $bar->saveData($request, $response);
388-
$response = $bar->injectScripts($row, $response);
388+
$response = $bar->injectScripts($row, $request, $response);
389389
$this->assertTextEquals('{"some":"json"}', (string)$response->getBody());
390390
$this->assertTrue($response->hasHeader('X-DEBUGKIT-ID'), 'Should have a tracking id');
391391
}

0 commit comments

Comments
 (0)