- Added CSRF through form processing

This commit is contained in:
Dave Mc Nicoll 2022-02-25 15:33:40 +00:00
parent 97f1f67af1
commit 83fee32ac0
4 changed files with 31 additions and 31 deletions

View File

@ -43,7 +43,7 @@ class UiInput extends UiElement implements Extension {
} }
if ($attributes['class'] ?? false) { 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']); unset($this->attributes['class']);
} }

View File

@ -34,6 +34,6 @@ class Form implements Extension {
public function formClass(FormInterface $form, ? FormContext $formContext = null) : FormHandler 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);
} }
} }

View File

@ -9,7 +9,7 @@ class FormContext implements FormContextInterface
{ {
public string $formName; public string $formName;
public bool $formSent; public bool $formSent = false;
public bool $formExecuted = false; public bool $formExecuted = false;
@ -18,6 +18,8 @@ class FormContext implements FormContextInterface
public array $files = []; public array $files = [];
public array $messages = []; public array $messages = [];
public bool $skipCsrf = false;
public ServerRequestInterface $request; public ServerRequestInterface $request;
@ -54,7 +56,25 @@ class FormContext implements FormContextInterface
public function formSent() : bool 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) public function __set($key, $value)

View File

@ -5,6 +5,9 @@ namespace Picea\Ui\Method;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
class FormHandler { class FormHandler {
const DEFAULT_METHODS = [
"DELETE", "PATCH", "POST", "PUT",
];
public bool $sent = false; public bool $sent = false;
@ -18,6 +21,8 @@ class FormHandler {
protected FormInterface $form; protected FormInterface $form;
public array $acceptedMethods = self::DEFAULT_METHODS;
public function __construct(ServerRequestInterface $request, FormInterface $form, ? FormContextInterface $context = null) public function __construct(ServerRequestInterface $request, FormInterface $form, ? FormContextInterface $context = null)
{ {
$this->request = $request; $this->request = $request;
@ -33,37 +38,14 @@ class FormHandler {
$this->request->context = $this->context; $this->request->context = $this->context;
$this->formSent();
$this->initialize(); $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 protected function initialize() : void
{ {
$this->form->initialize($this->context); $this->form->initialize($this->context);
if ( $this->sent ) { if ( $this->sent && $this->context->formSent() ) {
if ( $this->form->validate($this->context) ) { if ( $this->form->validate($this->context) ) {
$this->executionStatus = $this->form->execute($this->context); $this->executionStatus = $this->form->execute($this->context);
} }
@ -72,9 +54,7 @@ class FormHandler {
protected function requestSent() : bool protected function requestSent() : bool
{ {
return in_array($this->request->getMethod(), [ return in_array(strtoupper($this->request->getMethod()), array_map('strtoupper', $this->acceptedMethods));
"DELETE", "PATCH", "POST", "PUT",
]);
} }
protected function honeyPot() : bool protected function honeyPot() : bool