11
11
12
12
use Nette ;
13
13
use Nette \PhpGenerator \Helpers ;
14
+ use Nette \Schema \Expect ;
14
15
15
16
16
17
/**
17
18
* HTTP extension for Nette DI.
18
19
*/
19
20
class HttpExtension extends Nette \DI \CompilerExtension
20
21
{
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
-
34
22
/** @var bool */
35
23
private $ cliMode ;
36
24
@@ -41,25 +29,42 @@ public function __construct(bool $cliMode = false)
41
29
}
42
30
43
31
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
+
44
49
public function loadConfiguration ()
45
50
{
46
51
$ builder = $ this ->getContainerBuilder ();
47
- $ config = $ this ->validateConfig ( $ this -> defaults ) ;
52
+ $ config = $ this ->config ;
48
53
49
54
$ builder ->addDefinition ($ this ->prefix ('requestFactory ' ))
50
55
->setFactory (Nette \Http \RequestFactory::class)
51
- ->addSetup ('setProxy ' , [$ config[ ' proxy ' ] ]);
56
+ ->addSetup ('setProxy ' , [$ config-> proxy ]);
52
57
53
58
$ builder ->addDefinition ($ this ->prefix ('request ' ))
54
59
->setFactory ('@Nette\Http\RequestFactory::createHttpRequest ' );
55
60
56
61
$ response = $ builder ->addDefinition ($ this ->prefix ('response ' ))
57
62
->setFactory (Nette \Http \Response::class);
58
63
59
- if (isset ( $ config[ ' cookieSecure ' ]) ) {
60
- $ value = $ config[ ' cookieSecure ' ] === 'auto '
64
+ if ($ config-> cookieSecure !== null ) {
65
+ $ value = $ config-> cookieSecure === 'auto '
61
66
? $ builder ::literal ('$this->getService(?)->isSecured() ' , [$ this ->prefix ('request ' )])
62
- : ( bool ) $ config[ ' cookieSecure ' ] ;
67
+ : $ config-> cookieSecure ;
63
68
$ response ->addSetup ('$cookieSecure ' , [$ value ]);
64
69
}
65
70
@@ -78,11 +83,11 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
78
83
}
79
84
80
85
$ 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 );
83
88
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 ;
86
91
if ($ frames === false ) {
87
92
$ frames = 'DENY ' ;
88
93
} elseif (preg_match ('#^https?:# ' , $ frames )) {
@@ -93,10 +98,10 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
93
98
94
99
$ code = [];
95
100
foreach (['csp ' , 'cspReportOnly ' ] as $ key ) {
96
- if (empty ($ config[ $ key] )) {
101
+ if (empty ($ config-> $ key )) {
97
102
continue ;
98
103
}
99
- $ value = self ::buildPolicy ($ config[ $ key] );
104
+ $ value = self ::buildPolicy ($ config-> $ key );
100
105
if (strpos ($ value , "'nonce' " )) {
101
106
$ code [0 ] = '$cspNonce = base64_encode(random_bytes(16)); ' ;
102
107
$ value = Nette \DI \ContainerBuilder::literal (
@@ -107,8 +112,8 @@ public function afterCompile(Nette\PhpGenerator\ClassType $class)
107
112
$ headers ['Content-Security-Policy ' . ($ key === 'csp ' ? '' : '-Report-Only ' )] = $ value ;
108
113
}
109
114
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 );
112
117
}
113
118
114
119
$ code [] = Helpers::formatArgs ('$response = $this->getService(?); ' , [$ this ->prefix ('response ' )]);
0 commit comments