From 83fee32ac0477004349d565f26444b3cdfde7b1b Mon Sep 17 00:00:00 2001 From: Dave Mc Nicoll Date: Fri, 25 Feb 2022 15:33:40 +0000 Subject: [PATCH] - Added CSRF through form processing --- src/Form/UiInput.php | 2 +- src/Method/Form.php | 2 +- src/Method/FormContext.php | 24 ++++++++++++++++++++++-- src/Method/FormHandler.php | 34 +++++++--------------------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/Form/UiInput.php b/src/Form/UiInput.php index d3812ff..78b507b 100644 --- a/src/Form/UiInput.php +++ b/src/Form/UiInput.php @@ -43,7 +43,7 @@ class UiInput extends UiElement implements Extension { } if ($attributes['class'] ?? false) { - $attributes['class'] .= " {$this->attributes['class']}"; + $attributes['class'] = implode(" ", array_merge((array) $attributes['class'], (array) $this->attributes['class'])); unset($this->attributes['class']); } diff --git a/src/Method/Form.php b/src/Method/Form.php index e1796ec..d7ce65c 100644 --- a/src/Method/Form.php +++ b/src/Method/Form.php @@ -34,6 +34,6 @@ class Form implements Extension { public function formClass(FormInterface $form, ? FormContext $formContext = null) : FormHandler { - return new FormHandler($this->request, $form, $formContext); + return new FormHandler($formContext ? $formContext->request : $this->request, $form, $formContext); } } diff --git a/src/Method/FormContext.php b/src/Method/FormContext.php index edd266a..676f16c 100644 --- a/src/Method/FormContext.php +++ b/src/Method/FormContext.php @@ -9,7 +9,7 @@ class FormContext implements FormContextInterface { public string $formName; - public bool $formSent; + public bool $formSent = false; public bool $formExecuted = false; @@ -18,6 +18,8 @@ class FormContext implements FormContextInterface public array $files = []; public array $messages = []; + + public bool $skipCsrf = false; public ServerRequestInterface $request; @@ -54,7 +56,25 @@ class FormContext implements FormContextInterface public function formSent() : bool { - return $this->formSent; + $valid = true; + + if ( ! $this->skipCsrf && ($this->formName ?? false) ) { + $token = $this->get('picea-ui-form')[$this->formName] ?? false; + + if ( $token ) { + if ($this->validateCsrfToken) { + $valid = in_array($token, $_SESSION["picea-ui.form:{$this->formName}"] ?? []); + } + else { + $valid = (bool) $token; + } + } + else { + $valid = false; + } + } + + return $this->formSent = $valid; } public function __set($key, $value) diff --git a/src/Method/FormHandler.php b/src/Method/FormHandler.php index e6210e7..4b1cd07 100644 --- a/src/Method/FormHandler.php +++ b/src/Method/FormHandler.php @@ -5,6 +5,9 @@ namespace Picea\Ui\Method; use Psr\Http\Message\ServerRequestInterface; class FormHandler { + const DEFAULT_METHODS = [ + "DELETE", "PATCH", "POST", "PUT", + ]; public bool $sent = false; @@ -18,6 +21,8 @@ class FormHandler { protected FormInterface $form; + public array $acceptedMethods = self::DEFAULT_METHODS; + public function __construct(ServerRequestInterface $request, FormInterface $form, ? FormContextInterface $context = null) { $this->request = $request; @@ -33,37 +38,14 @@ class FormHandler { $this->request->context = $this->context; - $this->formSent(); $this->initialize(); } - - public function formSent() : void - { - if ( false !== $this->context->formSent = $this->sent ) { - if ( $this->context->formName ?? false ) { - $sent = false; - - $token = $this->context->{'picea-ui-form'}[$this->context->formName] ?? false; - - if ( $token ) { - if ($this->validateCsrfToken) { - $sent = in_array($token, $_SESSION["picea-ui.form:{$this->context->formName}"] ?? []); - } - else { - $sent = (bool) $token; - } - } - - $this->sent = $this->context->formSent = $sent; - } - } - } protected function initialize() : void { $this->form->initialize($this->context); - if ( $this->sent ) { + if ( $this->sent && $this->context->formSent() ) { if ( $this->form->validate($this->context) ) { $this->executionStatus = $this->form->execute($this->context); } @@ -72,9 +54,7 @@ class FormHandler { protected function requestSent() : bool { - return in_array($this->request->getMethod(), [ - "DELETE", "PATCH", "POST", "PUT", - ]); + return in_array(strtoupper($this->request->getMethod()), array_map('strtoupper', $this->acceptedMethods)); } protected function honeyPot() : bool