From 30d67a65466976c90e94c571834d041cc4d8fb5e Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Fri, 23 Sep 2022 13:03:51 +0100 Subject: [PATCH] feature: multiple tokens exposed with comma separated meta content (#174) closes #44 --- src/HTMLDocumentProtector.php | 25 ++++++++++++---------- test/phpunit/HTMLDocumentProtectorTest.php | 13 +++++++++++ 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/HTMLDocumentProtector.php b/src/HTMLDocumentProtector.php index 4e8ca9d..6c2b7d5 100644 --- a/src/HTMLDocumentProtector.php +++ b/src/HTMLDocumentProtector.php @@ -52,17 +52,24 @@ public function protect( string $tokenSharing = self::ONE_TOKEN_PER_PAGE ):string { $forms = $this->document->forms; + $tokenArray = []; - if($forms->length > 0) { - $token = $this->tokenStore->generateNewToken(); - $this->tokenStore->saveToken($token); + $token = null; + if($forms->length > 0) { foreach($forms as $form) { $formMethod = $form->getAttribute("method"); if(strtolower($formMethod) !== "post") { continue; } + if($tokenSharing === self::ONE_TOKEN_PER_FORM + || is_null($token)) { + $token = $this->tokenStore->generateNewToken(); + $this->tokenStore->saveToken($token); + array_push($tokenArray, $token); + } + $csrfElement = $this->document->createElement( "input" ); @@ -82,16 +89,13 @@ public function protect( $csrfElement, $form->firstChild ); - - if($tokenSharing === self::ONE_TOKEN_PER_FORM) { - $token = $this->tokenStore->generateNewToken(); - $this->tokenStore->saveToken($token); - } } } - else { + + if(is_null($token)) { $token = $this->tokenStore->generateNewToken(); $this->tokenStore->saveToken($token); + array_push($tokenArray, $token); } $meta = $this->document->querySelector( @@ -123,8 +127,7 @@ public function protect( $head->appendChild($meta); } - $meta->setAttribute("content", $token); - + $meta->setAttribute("content", implode(",", $tokenArray)); return $token; } diff --git a/test/phpunit/HTMLDocumentProtectorTest.php b/test/phpunit/HTMLDocumentProtectorTest.php index 22c51f3..a8bc9d6 100644 --- a/test/phpunit/HTMLDocumentProtectorTest.php +++ b/test/phpunit/HTMLDocumentProtectorTest.php @@ -253,6 +253,19 @@ public function testProtect_metaTagAlreadyExists():void { self::assertNotEquals($originalValue, $metaTag->content); } + public function testProtect_metaTagMultipleForms():void { + $document = new HTMLDocument(self::THREE_FORMS); + $sut = new HTMLDocumentProtector($document, new ArrayTokenStore()); + $sut->protect(HTMLDocumentProtector::ONE_TOKEN_PER_FORM); + + $nodeList = $document->querySelectorAll("head meta[name='" . HTMLDocumentProtector::TOKEN_NAME . "']"); +// There should still only be 1 meta tag... + self::assertCount(1, $nodeList); +// ... but the tag's content should have two values (one per POST form). + $tokenArray = explode(",", $nodeList[0]->content); + self::assertCount(2, $tokenArray); + } + public function testProtect_differentTokenName() { $sut = new HTMLDocumentProtector(new HTMLDocument(self::HAS_META_ALREADY), new ArrayTokenStore()); $tokenName = HTMLDocumentProtector::TOKEN_NAME;