summaryrefslogtreecommitdiffstats
path: root/vendor/ipl/web/src/Common
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ipl/web/src/Common')
-rw-r--r--vendor/ipl/web/src/Common/BaseTarget.php33
-rw-r--r--vendor/ipl/web/src/Common/Card.php55
-rw-r--r--vendor/ipl/web/src/Common/CsrfCounterMeasure.php48
-rw-r--r--vendor/ipl/web/src/Common/FormUid.php59
-rw-r--r--vendor/ipl/web/src/Common/RedirectOption.php41
-rw-r--r--vendor/ipl/web/src/Common/StateBadges.php184
6 files changed, 420 insertions, 0 deletions
diff --git a/vendor/ipl/web/src/Common/BaseTarget.php b/vendor/ipl/web/src/Common/BaseTarget.php
new file mode 100644
index 0000000..db9be28
--- /dev/null
+++ b/vendor/ipl/web/src/Common/BaseTarget.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace ipl\Web\Common;
+
+/**
+ * @method \ipl\Html\Attributes getAttributes()
+ */
+trait BaseTarget
+{
+ /**
+ * Get the data-base-target attribute
+ *
+ * @return string|null
+ */
+ public function getBaseTarget()
+ {
+ return $this->getAttributes()->get('data-base-target')->getValue();
+ }
+
+ /**
+ * Set the data-base-target attribute
+ *
+ * @param string $target
+ *
+ * @return $this
+ */
+ public function setBaseTarget($target)
+ {
+ $this->getAttributes()->set('data-base-target', $target);
+
+ return $this;
+ }
+}
diff --git a/vendor/ipl/web/src/Common/Card.php b/vendor/ipl/web/src/Common/Card.php
new file mode 100644
index 0000000..e62bab5
--- /dev/null
+++ b/vendor/ipl/web/src/Common/Card.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace ipl\Web\Common;
+
+use ipl\Html\BaseHtmlElement;
+use ipl\Html\Html;
+
+abstract class Card extends BaseHtmlElement
+{
+ protected $tag = 'section';
+
+ abstract protected function assembleBody(BaseHtmlElement $body);
+
+ abstract protected function assembleFooter(BaseHtmlElement $footer);
+
+ abstract protected function assembleHeader(BaseHtmlElement $header);
+
+ protected function createBody()
+ {
+ $body = Html::tag('div', ['class' => 'card-body']);
+
+ $this->assembleBody($body);
+
+ return $body;
+ }
+
+ protected function createFooter()
+ {
+ $footer = Html::tag('div', ['class' => 'card-footer']);
+
+ $this->assembleFooter($footer);
+
+ return $footer;
+ }
+
+ protected function createHeader()
+ {
+ $header = Html::tag('div', ['class' => 'card-header']);
+
+ $this->assembleHeader($header);
+
+ return $header;
+ }
+
+ protected function assemble()
+ {
+ $this->addAttributes(['class' => 'card']);
+
+ $this->add([
+ $this->createHeader(),
+ $this->createBody(),
+ $this->createFooter()
+ ]);
+ }
+}
diff --git a/vendor/ipl/web/src/Common/CsrfCounterMeasure.php b/vendor/ipl/web/src/Common/CsrfCounterMeasure.php
new file mode 100644
index 0000000..348c4ee
--- /dev/null
+++ b/vendor/ipl/web/src/Common/CsrfCounterMeasure.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace ipl\Web\Common;
+
+use ipl\Html\Contract\FormElement;
+use ipl\Html\Form;
+
+trait CsrfCounterMeasure
+{
+ /**
+ * Create a form element to counter measure CSRF attacks
+ *
+ * @param string $uniqueId A unique ID that persists through different requests
+ *
+ * @return FormElement
+ */
+ protected function createCsrfCounterMeasure($uniqueId)
+ {
+ $hashAlgo = in_array('sha3-256', hash_algos(), true) ? 'sha3-256' : 'sha256';
+
+ $seed = random_bytes(16);
+ $token = base64_encode($seed) . '|' . hash($hashAlgo, $uniqueId . $seed);
+
+ /** @var Form $this */
+ return $this->createElement(
+ 'hidden',
+ 'CSRFToken',
+ [
+ 'ignore' => true,
+ 'required' => true,
+ 'value' => $token,
+ 'validators' => ['Callback' => function ($token) use ($uniqueId, $hashAlgo) {
+ if (strpos($token, '|') === false) {
+ die('Invalid CSRF token provided');
+ }
+
+ list($seed, $hash) = explode('|', $token);
+
+ if ($hash !== hash($hashAlgo, $uniqueId . base64_decode($seed))) {
+ die('Invalid CSRF token provided');
+ }
+
+ return true;
+ }]
+ ]
+ );
+ }
+}
diff --git a/vendor/ipl/web/src/Common/FormUid.php b/vendor/ipl/web/src/Common/FormUid.php
new file mode 100644
index 0000000..8453dd2
--- /dev/null
+++ b/vendor/ipl/web/src/Common/FormUid.php
@@ -0,0 +1,59 @@
+<?php
+
+namespace ipl\Web\Common;
+
+use ipl\Html\Form;
+use ipl\Html\Contract\FormElement;
+use LogicException;
+
+trait FormUid
+{
+ protected $uidElementName = 'uid';
+
+ /**
+ * Create a form element to make this form distinguishable from others
+ *
+ * You'll have to define a name for the form for this to work.
+ *
+ * @return FormElement
+ */
+ protected function createUidElement()
+ {
+ /** @var Form $this */
+ $element = $this->createElement('hidden', $this->uidElementName);
+ $element->getAttributes()->registerAttributeCallback('value', function () {
+ /** @var Form $this */
+ return $this->getAttributes()->get('name')->getValue();
+ });
+
+ return $element;
+ }
+
+ /**
+ * Get whether the form has been sent
+ *
+ * A form is considered sent if the request's method equals the form's method
+ * and the sent UID is the form's UID.
+ *
+ * @return bool
+ */
+ public function hasBeenSent()
+ {
+ if (! parent::hasBeenSent()) {
+ return false;
+ } elseif ($this->getMethod() === 'GET') {
+ // Get forms are unlikely to require a UID. If they do, change this.
+ return true;
+ }
+
+ /** @var Form $this */
+ $name = $this->getAttributes()->get('name')->getValue();
+ if (! $name) {
+ throw new LogicException('Form has no name');
+ }
+
+ $values = $this->getRequest()->getParsedBody();
+
+ return isset($values[$this->uidElementName]) && $values[$this->uidElementName] === $name;
+ }
+}
diff --git a/vendor/ipl/web/src/Common/RedirectOption.php b/vendor/ipl/web/src/Common/RedirectOption.php
new file mode 100644
index 0000000..0d73ef8
--- /dev/null
+++ b/vendor/ipl/web/src/Common/RedirectOption.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace ipl\Web\Common;
+
+use ipl\Html\Contract\FormElement;
+use ipl\Html\Form;
+use LogicException;
+
+trait RedirectOption
+{
+ /**
+ * Create a form element to retrieve the redirect target upon form submit
+ *
+ * @return FormElement
+ */
+ protected function createRedirectOption()
+ {
+ /** @var Form $this */
+ return $this->createElement('hidden', 'redirect');
+ }
+
+ /**
+ * @see Form::getRedirectUrl()
+ */
+ public function getRedirectUrl()
+ {
+ /** @var Form $this */
+ $redirectOption = $this->getValue('redirect');
+ if (! $redirectOption) {
+ return parent::getRedirectUrl();
+ }
+
+ if (! $this->hasElement('CSRFToken') || ! $this->getElement('CSRFToken')->isValid()) {
+ throw new LogicException(
+ 'It is not safe to accept redirect targets from submit values without CSRF protection'
+ );
+ }
+
+ return $redirectOption;
+ }
+}
diff --git a/vendor/ipl/web/src/Common/StateBadges.php b/vendor/ipl/web/src/Common/StateBadges.php
new file mode 100644
index 0000000..5898492
--- /dev/null
+++ b/vendor/ipl/web/src/Common/StateBadges.php
@@ -0,0 +1,184 @@
+<?php
+
+namespace ipl\Web\Common;
+
+use Icinga\Data\Filter\Filter;
+use ipl\Html\BaseHtmlElement;
+use ipl\Html\Html;
+use ipl\Stdlib\BaseFilter;
+use ipl\Web\Filter\QueryString;
+use ipl\Web\Url;
+use ipl\Web\Widget\Link;
+use ipl\Web\Widget\StateBadge;
+
+abstract class StateBadges extends BaseHtmlElement
+{
+ use BaseFilter;
+
+ /** @var object $item */
+ protected $item;
+
+ /** @var string */
+ protected $type;
+
+ /** @var string Prefix */
+ protected $prefix;
+
+ /** @var Url Badge link */
+ protected $url;
+
+ protected $tag = 'ul';
+
+ protected $defaultAttributes = ['class' => 'state-badges'];
+
+ /**
+ * Create a new widget for state badges
+ *
+ * @param object $item
+ */
+ public function __construct($item)
+ {
+ $this->item = $item;
+ $this->type = $this->getType();
+ $this->prefix = $this->getPrefix();
+ $this->url = $this->getBaseUrl();
+ }
+
+ /**
+ * Get the badge base URL
+ *
+ * @return Url
+ */
+ abstract protected function getBaseUrl(): Url;
+
+ /**
+ * Get the type of the items
+ *
+ * @return string
+ */
+ abstract protected function getType(): string;
+
+ /**
+ * Get the prefix for accessing state information
+ *
+ * @return string
+ */
+ abstract protected function getPrefix(): string;
+
+ /**
+ * Get the integer of the given state text
+ *
+ * @param string $state
+ *
+ * @return int
+ */
+ abstract protected function getStateInt(string $state): int;
+
+ /**
+ * Get the badge URL
+ *
+ * @return Url
+ */
+ public function getUrl(): Url
+ {
+ return $this->url;
+ }
+
+ /**
+ * Set the badge URL
+ *
+ * @param Url $url
+ *
+ * @return $this
+ */
+ public function setUrl(Url $url): self
+ {
+ $this->url = $url;
+
+ return $this;
+ }
+
+ /**
+ * Create a badge link
+ *
+ * @param $content
+ * @param array $params
+ *
+ * @return Link
+ */
+ public function createLink($content, array $params = null): Link
+ {
+ $url = clone $this->getUrl();
+
+ if (! empty($params)) {
+ $url->getParams()->mergeValues($params);
+ }
+
+ if ($this->hasBaseFilter()) {
+ $url->addFilter(Filter::fromQueryString(QueryString::render($this->getBaseFilter())));
+ }
+
+ return new Link($content, $url);
+ }
+
+ /**
+ * Create a state bade
+ *
+ * @param string $state
+ *
+ * @return ?BaseHtmlElement
+ */
+ protected function createBadge(string $state)
+ {
+ $key = $this->prefix . "_{$state}";
+
+ if (isset($this->item->$key) && $this->item->$key) {
+ return Html::tag('li', $this->createLink(
+ new StateBadge($this->item->$key, $state),
+ [$this->type . '.state.soft_state' => $this->getStateInt($state)]
+ ));
+ }
+
+ return null;
+ }
+
+ /**
+ * Create a state group
+ *
+ * @param string $state
+ *
+ * @return ?BaseHtmlElement
+ */
+ protected function createGroup(string $state)
+ {
+ $content = [];
+ $handledKey = $this->prefix . "_{$state}_handled";
+ $unhandledKey = $this->prefix . "_{$state}_unhandled";
+
+ if (isset($this->item->$unhandledKey) && $this->item->$unhandledKey) {
+ $content[] = Html::tag('li', $this->createLink(
+ new StateBadge($this->item->$unhandledKey, $state),
+ [
+ $this->type . '.state.soft_state' => $this->getStateInt($state),
+ $this->type . '.state.is_handled' => 'n'
+ ]
+ ));
+ }
+
+ if (isset($this->item->$handledKey) && $this->item->$handledKey) {
+ $content[] = Html::tag('li', $this->createLink(
+ new StateBadge($this->item->$handledKey, $state, true),
+ [
+ $this->type . '.state.soft_state' => $this->getStateInt($state),
+ $this->type . '.state.is_handled' => 'y'
+ ]
+ ));
+ }
+
+ if (empty($content)) {
+ return null;
+ }
+
+ return Html::tag('li', Html::tag('ul', $content));
+ }
+}