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