diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 190c4c77c..679c8b995 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -1365,7 +1365,7 @@ public function getContext() /** * @return Nette\Http\IRequest */ - protected function getHttpRequest() + public function getHttpRequest() { return $this->httpRequest; } @@ -1374,7 +1374,7 @@ protected function getHttpRequest() /** * @return Nette\Http\IResponse */ - protected function getHttpResponse() + public function getHttpResponse() { return $this->httpResponse; } diff --git a/src/Bridges/ApplicationLatte/TemplateFactory.php b/src/Bridges/ApplicationLatte/TemplateFactory.php index 0895552c1..b41fd84c5 100644 --- a/src/Bridges/ApplicationLatte/TemplateFactory.php +++ b/src/Bridges/ApplicationLatte/TemplateFactory.php @@ -103,6 +103,8 @@ public function createTemplate(UI\Control $control = NULL) $latte->addProvider('uiControl', $control); $latte->addProvider('uiPresenter', $presenter); $latte->addProvider('snippetBridge', new Nette\Bridges\ApplicationLatte\SnippetBridge($control)); + $nonce = preg_match('#\s\'nonce-([\w+/]+=*)\'#', $presenter->getHttpResponse()->getHeader('Content-Security-Policy'), $m) ? $m[1] : NULL; + $latte->addProvider('uiNonce', $nonce); } $latte->addProvider('cacheStorage', $this->cacheStorage); diff --git a/src/Bridges/ApplicationLatte/UIMacros.php b/src/Bridges/ApplicationLatte/UIMacros.php index 62710d4b8..3b9cea703 100644 --- a/src/Bridges/ApplicationLatte/UIMacros.php +++ b/src/Bridges/ApplicationLatte/UIMacros.php @@ -21,6 +21,7 @@ * - {link destination ...} control link * - {plink destination ...} presenter link * - {snippet ?} ... {/snippet ?} control snippet + * - n:once */ class UIMacros extends Latte\Macros\MacroSet { @@ -41,6 +42,7 @@ public static function install(Latte\Compiler $compiler) $me->addMacro('ifCurrent', [$me, 'macroIfCurrent'], '}'); // deprecated; use n:class="$presenter->linkCurrent ? ..." $me->addMacro('extends', [$me, 'macroExtends']); $me->addMacro('layout', [$me, 'macroExtends']); + $me->addMacro('nonce', NULL, NULL, 'echo $this->global->uiNonce ? " nonce=\"{$this->global->uiNonce}\"" : "";'); } diff --git a/tests/Bridges.Latte/TemplateFactory.nonce.phpt b/tests/Bridges.Latte/TemplateFactory.nonce.phpt new file mode 100644 index 000000000..c8822cf5a --- /dev/null +++ b/tests/Bridges.Latte/TemplateFactory.nonce.phpt @@ -0,0 +1,36 @@ +shouldReceive('create')->andReturn($latte); + +$response = Mockery::mock(Nette\Http\Response::class); +$response->shouldReceive('getHeader')->with('Content-Security-Policy')->andReturn("hello 'nonce-abcd123==' world"); + +$presenter = Mockery::mock(UI\Presenter::class); +$presenter->shouldReceive('getPresenter')->andReturn($presenter); +$presenter->shouldReceive('getHttpResponse')->andReturn($response); +$presenter->shouldIgnoreMissing(); + +$factory = new ApplicationLatte\TemplateFactory($latteFactory); +$factory->createTemplate($presenter); + +$latte->setLoader(new Latte\Loaders\StringLoader); + +Assert::match( + '', + $latte->renderToString('') +);