22
33namespace ipl \Web \Common ;
44
5+ use Error ;
56use ipl \Html \Contract \FormElement ;
6- use ipl \Html \Form ;
7+ use ipl \Html \FormElement \ HiddenElement ;
78
89trait CsrfCounterMeasure
910{
1011 /**
11- * Create a form element to counter measure CSRF attacks
12+ * Create a form element to countermeasure CSRF attacks
1213 *
1314 * @param string $uniqueId A unique ID that persists through different requests
1415 *
@@ -21,28 +22,35 @@ protected function createCsrfCounterMeasure($uniqueId)
2122 $ seed = random_bytes (16 );
2223 $ token = base64_encode ($ seed ) . '| ' . hash ($ hashAlgo , $ uniqueId . $ seed );
2324
24- /** @var Form $this */
25- return $ this ->createElement (
26- 'hidden ' ,
27- 'CSRFToken ' ,
28- [
29- 'ignore ' => true ,
30- 'required ' => true ,
31- 'value ' => $ token ,
32- 'validators ' => ['Callback ' => function ($ token ) use ($ uniqueId , $ hashAlgo ) {
33- if (strpos ($ token , '| ' ) === false ) {
34- die ('Invalid CSRF token provided ' );
35- }
36-
37- list ($ seed , $ hash ) = explode ('| ' , $ token );
38-
39- if ($ hash !== hash ($ hashAlgo , $ uniqueId . base64_decode ($ seed ))) {
40- die ('Invalid CSRF token provided ' );
41- }
42-
43- return true ;
44- }]
45- ]
46- );
25+ $ options = [
26+ 'ignore ' => true ,
27+ 'required ' => true ,
28+ 'validators ' => ['Callback ' => function ($ token ) use ($ uniqueId , $ hashAlgo ) {
29+ if (empty ($ token ) || strpos ($ token , '| ' ) === false ) {
30+ throw new Error ('Invalid CSRF token provided ' );
31+ }
32+
33+ list ($ seed , $ hash ) = explode ('| ' , $ token );
34+
35+ if ($ hash !== hash ($ hashAlgo , $ uniqueId . base64_decode ($ seed ))) {
36+ throw new Error ('Invalid CSRF token provided ' );
37+ }
38+
39+ return true ;
40+ }]
41+ ];
42+
43+ $ element = new class ('CSRFToken ' , $ options ) extends HiddenElement {
44+ public function hasValue (): bool
45+ {
46+ return true ; // The validator must run even if the value is empty
47+ }
48+ };
49+
50+ $ element ->getAttributes ()->registerAttributeCallback ('value ' , function () use ($ token ) {
51+ return $ token ;
52+ });
53+
54+ return $ element ;
4755 }
4856}
0 commit comments