4
4
5
5
namespace Hyde \RealtimeCompiler \Http ;
6
6
7
+ use BadMethodCallException ;
7
8
use Desilva \Microserve \Request ;
8
9
use Desilva \Microserve \Response ;
9
10
use Desilva \Microserve \JsonResponse ;
@@ -76,6 +77,14 @@ protected function authorizePostRequest(): void
76
77
if (! $ this ->isRequestMadeFromLocalhost ()) {
77
78
throw new HttpException (403 , "Refusing to serve request from address {$ _SERVER ['REMOTE_ADDR ' ]} (must be on localhost) " );
78
79
}
80
+
81
+ if ($ this ->withSession ) {
82
+ if (! $ this ->validateCSRFToken ($ this ->request ->get ('_token ' ))) {
83
+ throw new HttpException (403 , 'Invalid CSRF token ' );
84
+ } else {
85
+ $ this ->expireCSRFToken ();
86
+ }
87
+ }
79
88
}
80
89
81
90
protected function isRequestMadeFromLocalhost (): bool
@@ -91,6 +100,41 @@ protected function isRequestMadeFromLocalhost(): bool
91
100
return in_array ($ requestIp , $ allowedIps , true );
92
101
}
93
102
103
+ protected function generateCSRFToken (): string
104
+ {
105
+ if (session_status () !== PHP_SESSION_ACTIVE ) {
106
+ throw new BadMethodCallException ('Session not started ' );
107
+ }
108
+
109
+ if (empty ($ _SESSION ['csrf_token ' ])) {
110
+ $ _SESSION ['csrf_token ' ] = bin2hex (random_bytes (32 ));
111
+ }
112
+
113
+ return $ _SESSION ['csrf_token ' ];
114
+ }
115
+
116
+ protected function validateCSRFToken (?string $ suppliedToken ): bool
117
+ {
118
+ if (session_status () !== PHP_SESSION_ACTIVE ) {
119
+ throw new BadMethodCallException ('Session not started ' );
120
+ }
121
+
122
+ if ($ suppliedToken === null ) {
123
+ return false ;
124
+ }
125
+
126
+ return ! empty ($ _SESSION ['csrf_token ' ]) && hash_equals ($ _SESSION ['csrf_token ' ], $ suppliedToken );
127
+ }
128
+
129
+ protected function expireCSRFToken (): void
130
+ {
131
+ if (session_status () !== PHP_SESSION_ACTIVE ) {
132
+ throw new BadMethodCallException ('Session not started ' );
133
+ }
134
+
135
+ unset($ _SESSION ['csrf_token ' ]);
136
+ }
137
+
94
138
protected function writeToConsole (string $ message , string $ context = 'dashboard ' ): void
95
139
{
96
140
if (isset ($ this ->console )) {
0 commit comments