1111
1212use Nette ;
1313use Nette \PhpGenerator \Helpers ;
14+ use Nette \Schema \Expect ;
1415
1516
1617/**
1718 * HTTP extension for Nette DI.
1819 */
1920class HttpExtension extends Nette \DI \CompilerExtension
2021{
21- public $ defaults = [
22- 'proxy ' => [],
23- 'headers ' => [
24- 'X-Powered-By ' => 'Nette Framework 3 ' ,
25- 'Content-Type ' => 'text/html; charset=utf-8 ' ,
26- ],
27- 'frames ' => 'SAMEORIGIN ' , // X-Frame-Options
28- 'csp ' => [], // Content-Security-Policy
29- 'cspReportOnly ' => [], // Content-Security-Policy-Report-Only
30- 'featurePolicy ' => [], // Feature-Policy
31- 'cookieSecure ' => 'auto ' , // true|false|auto Whether the cookie is available only through HTTPS
32- ];
33-
3422 /** @var bool */
3523 private $ cliMode ;
3624
@@ -41,25 +29,42 @@ public function __construct(bool $cliMode = false)
4129 }
4230
4331
32+ public function getConfigSchema (): Nette \Schema \Schema
33+ {
34+ return Expect::structure ([
35+ 'proxy ' => Expect::arrayOf ('string ' )->dynamic (),
36+ 'headers ' => Expect::arrayOf ('scalar|null ' )->default ([
37+ 'X-Powered-By ' => 'Nette Framework 3 ' ,
38+ 'Content-Type ' => 'text/html; charset=utf-8 ' ,
39+ ]),
40+ 'frames ' => Expect::anyOf (Expect::string (), Expect::bool (), null )->default ('SAMEORIGIN ' ), // X-Frame-Options
41+ 'csp ' => Expect::arrayOf ('array|scalar|null ' ), // Content-Security-Policy
42+ 'cspReportOnly ' => Expect::arrayOf ('array|scalar|null ' ), // Content-Security-Policy-Report-Only
43+ 'featurePolicy ' => Expect::arrayOf ('array|scalar|null ' ), // Feature-Policy
44+ 'cookieSecure ' => Expect::anyOf (null , true , false , 'auto ' ), // true|false|auto Whether the cookie is available only through HTTPS
45+ ]);
46+ }
47+
48+
4449 public function loadConfiguration ()
4550 {
4651 $ builder = $ this ->getContainerBuilder ();
47- $ config = $ this ->validateConfig ( $ this -> defaults ) ;
52+ $ config = $ this ->config ;
4853
4954 $ builder ->addDefinition ($ this ->prefix ('requestFactory ' ))
5055 ->setFactory (Nette \Http \RequestFactory::class)
51- ->addSetup ('setProxy ' , [$ config[ ' proxy ' ] ]);
56+ ->addSetup ('setProxy ' , [$ config-> proxy ]);
5257
5358 $ builder ->addDefinition ($ this ->prefix ('request ' ))
5459 ->setFactory ('@Nette\Http\RequestFactory::createHttpRequest ' );
5560
5661 $ response = $ builder ->addDefinition ($ this ->prefix ('response ' ))
5762 ->setFactory (Nette \Http \Response::class);
5863
59- if (isset ( $ config[ ' cookieSecure ' ]) ) {
60- $ value = $ config[ ' cookieSecure ' ] === 'auto '
64+ if ($ config-> cookieSecure !== null ) {
65+ $ value = $ config-> cookieSecure === 'auto '
6166 ? $ builder ::literal ('$this->getService(?)->isSecured() ' , [$ this ->prefix ('request ' )])
62- : ( bool ) $ config[ ' cookieSecure ' ] ;
67+ : $ config-> cookieSecure ;
6368 $ response ->addSetup ('$cookieSecure ' , [$ value ]);
6469 }
6570
@@ -78,11 +83,11 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
7883 }
7984
8085 $ initialize = $ class ->getMethod ('initialize ' );
81- $ config = $ this ->getConfig () ;
82- $ headers = array_map ('strval ' , $ config[ ' headers ' ] );
86+ $ config = $ this ->config ;
87+ $ headers = array_map ('strval ' , $ config-> headers );
8388
84- if (isset ($ config[ ' frames ' ] ) && $ config[ ' frames ' ] !== true && !isset ($ headers ['X-Frame-Options ' ])) {
85- $ frames = $ config[ ' frames ' ] ;
89+ if (isset ($ config-> frames ) && $ config-> frames !== true && !isset ($ headers ['X-Frame-Options ' ])) {
90+ $ frames = $ config-> frames ;
8691 if ($ frames === false ) {
8792 $ frames = 'DENY ' ;
8893 } elseif (preg_match ('#^https?:# ' , $ frames )) {
@@ -93,10 +98,10 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
9398
9499 $ code = [];
95100 foreach (['csp ' , 'cspReportOnly ' ] as $ key ) {
96- if (empty ($ config[ $ key] )) {
101+ if (empty ($ config-> $ key )) {
97102 continue ;
98103 }
99- $ value = self ::buildPolicy ($ config[ $ key] );
104+ $ value = self ::buildPolicy ($ config-> $ key );
100105 if (strpos ($ value , "'nonce' " )) {
101106 $ code [0 ] = '$cspNonce = base64_encode(random_bytes(16)); ' ;
102107 $ value = Nette \DI \ContainerBuilder::literal (
@@ -107,8 +112,8 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
107112 $ headers ['Content-Security-Policy ' . ($ key === 'csp ' ? '' : '-Report-Only ' )] = $ value ;
108113 }
109114
110- if (!empty ($ config[ ' featurePolicy ' ] )) {
111- $ headers ['Feature-Policy ' ] = self ::buildPolicy ($ config[ ' featurePolicy ' ] );
115+ if (!empty ($ config-> featurePolicy )) {
116+ $ headers ['Feature-Policy ' ] = self ::buildPolicy ($ config-> featurePolicy );
112117 }
113118
114119 $ code [] = Helpers::formatArgs ('$response = $this->getService(?); ' , [$ this ->prefix ('response ' )]);
0 commit comments