- Implemented CSRF check, some bugfixes also included
This commit is contained in:
parent
362184f81f
commit
97f1f67af1
|
@ -177,8 +177,10 @@ class UiElement implements \ArrayAccess, \Iterator, \JsonSerializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ( !is_numeric($key) ) {
|
else if ( !is_numeric($key) ) {
|
||||||
# will output something like <tag $key=$value></tag>
|
$value = htmlspecialchars($value);
|
||||||
$attributesList[] = strpos($value, '"') !== false ? "$key='$value'" : "$key=\"$value\"";
|
|
||||||
|
# will output something like <tag $key="$value"></tag>
|
||||||
|
$attributesList[] = "$key=\"$value\"";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
# will output something like <tag $value></tag>
|
# will output something like <tag $value></tag>
|
||||||
|
@ -231,7 +233,7 @@ class UiElement implements \ArrayAccess, \Iterator, \JsonSerializable {
|
||||||
public function html($set = null) {
|
public function html($set = null) {
|
||||||
if ($set !== null) {
|
if ($set !== null) {
|
||||||
$this->content = $set;
|
$this->content = $set;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -285,8 +287,18 @@ class UiElement implements \ArrayAccess, \Iterator, \JsonSerializable {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'style' :
|
case 'style' :
|
||||||
foreach($value as $var => $val) {
|
if ( is_string($value) )
|
||||||
$this->css($var, $val);
|
{
|
||||||
|
foreach(array_filter(explode(";", $value)) as $vars) {
|
||||||
|
list($key, $value) = explode(':', $vars);
|
||||||
|
|
||||||
|
$this->css($key, $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ( is_array($value) ) {
|
||||||
|
foreach($value as $var => $val) {
|
||||||
|
$this->css($var, $val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ class UiPopup extends UiElement implements Extension {
|
||||||
public string $tag = "div";
|
public string $tag = "div";
|
||||||
|
|
||||||
public array $attributes = [
|
public array $attributes = [
|
||||||
'class' => 'ui-popup',
|
'class' => 'ui-popup',
|
||||||
];
|
];
|
||||||
|
|
||||||
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token) : string
|
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token) : string
|
||||||
|
|
|
@ -54,7 +54,7 @@ class UiForm extends UiElement implements Extension {
|
||||||
public function buildHtml(string $method = "get", string $name = "", string $action = "", array $attributes = []) : string
|
public function buildHtml(string $method = "get", string $name = "", string $action = "", array $attributes = []) : string
|
||||||
{
|
{
|
||||||
$method = strtolower($method);
|
$method = strtolower($method);
|
||||||
|
|
||||||
$this->option('tag-type', 'single');
|
$this->option('tag-type', 'single');
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,11 +66,23 @@ class UiForm extends UiElement implements Extension {
|
||||||
$this->attributes([ 'method' => $method, 'action' => $action ] + $attributes);
|
$this->attributes([ 'method' => $method, 'action' => $action ] + $attributes);
|
||||||
|
|
||||||
if ( $method !== "get" ) {
|
if ( $method !== "get" ) {
|
||||||
$this->append( ( new UiHidden() )->attributes([ 'name' =>"picea-ui-form[$name]", 'value' => md5( $name . microtime() ) ]) );
|
$token = md5( $name . microtime());
|
||||||
|
$key = "picea-ui.form:{$name}";
|
||||||
|
|
||||||
|
if (count($_SESSION[$key] ?? []) > 100) {
|
||||||
|
array_shift($_SESSION[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$_SESSION[$key][] = $token;
|
||||||
|
|
||||||
|
$this->append( ( new UiHidden() )->attributes([
|
||||||
|
'name' => "picea-ui-form[$name]",
|
||||||
|
'value' => $token,
|
||||||
|
]));
|
||||||
|
|
||||||
$this->attributes([ 'enctype' => "multipart/form-data" ]);
|
$this->attributes([ 'enctype' => "multipart/form-data" ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render() . PHP_EOL;
|
return $this->render() . PHP_EOL;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,7 +43,7 @@ class UiInput extends UiElement implements Extension {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($attributes['class'] ?? false) {
|
if ($attributes['class'] ?? false) {
|
||||||
$attributes['class'] = implode(" ", array_merge((array) $attributes['class'], (array) $this->attributes['class']));
|
$attributes['class'] .= " {$this->attributes['class']}";
|
||||||
unset($this->attributes['class']);
|
unset($this->attributes['class']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace Picea\Ui\Form;
|
||||||
|
|
||||||
class UiTextarea extends UiInput {
|
class UiTextarea extends UiInput {
|
||||||
|
|
||||||
public string $token = "ui.textarea";
|
public array $tokens = [ "ui.textarea", "ui.textarea.raw" ];
|
||||||
|
|
||||||
public string $tag = "textarea";
|
public string $tag = "textarea";
|
||||||
|
|
||||||
|
@ -14,8 +14,27 @@ class UiTextarea extends UiInput {
|
||||||
|
|
||||||
public array $options = [];
|
public array $options = [];
|
||||||
|
|
||||||
|
protected bool $echoRaw = false;
|
||||||
|
|
||||||
|
public function parse(/*\Picae\Compiler\Context*/ &$context, ?string $arguments, string $token) : string
|
||||||
|
{
|
||||||
|
if ($token === 'ui.textarea.raw') {
|
||||||
|
$this->echoRaw = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sprintf("<?php echo ( new \\" . static::class . "() )->echoRaw(%s)->buildHtml($arguments) ?>", $this->echoRaw ? 'true' : 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected function setValue($value) : void
|
protected function setValue($value) : void
|
||||||
{
|
{
|
||||||
$this->html($value);
|
$this->echoRaw ? $this->html($value) : $this->text($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function echoRaw(bool $set) : self
|
||||||
|
{
|
||||||
|
$this->echoRaw = $set;
|
||||||
|
|
||||||
|
return $this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,22 +32,6 @@ class Form implements Extension {
|
||||||
$context->pushFunction("form", [ $this, 'formClass' ]);
|
$context->pushFunction("form", [ $this, 'formClass' ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function form_csrf(string $field, string $value) {
|
|
||||||
$values = $this->session("View.form.csrf.$field") ?: [];
|
|
||||||
|
|
||||||
# keeps 20 (from config) latest CSRF key for this form into session,
|
|
||||||
# allowing more than one tab opened and preventing information loss
|
|
||||||
if ( count($values) >= 20 ) {
|
|
||||||
#array_shift($values);
|
|
||||||
}
|
|
||||||
|
|
||||||
$values[] = $value;
|
|
||||||
|
|
||||||
$this->session("View.form.csrf.$field", $values);
|
|
||||||
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
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($this->request, $form, $formContext);
|
||||||
|
|
|
@ -5,8 +5,11 @@ namespace Picea\Ui\Method;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
class FormHandler {
|
class FormHandler {
|
||||||
|
|
||||||
public bool $sent = false;
|
public bool $sent = false;
|
||||||
|
|
||||||
|
public bool $validateCsrfToken = true;
|
||||||
|
|
||||||
public ? bool $executionStatus = null;
|
public ? bool $executionStatus = null;
|
||||||
|
|
||||||
public FormContext $context;
|
public FormContext $context;
|
||||||
|
@ -38,7 +41,20 @@ class FormHandler {
|
||||||
{
|
{
|
||||||
if ( false !== $this->context->formSent = $this->sent ) {
|
if ( false !== $this->context->formSent = $this->sent ) {
|
||||||
if ( $this->context->formName ?? false ) {
|
if ( $this->context->formName ?? false ) {
|
||||||
$this->sent = $this->context->formSent = (bool) ( $this->request->getParsedBody()['picea-ui-form'][$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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,8 +66,6 @@ class FormHandler {
|
||||||
if ( $this->sent ) {
|
if ( $this->sent ) {
|
||||||
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);
|
||||||
|
|
||||||
$this->context->formExecuted = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue