diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:38:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 12:38:04 +0000 |
commit | 1ff5c35de5dbd70a782875a91dd2232fd01b002b (patch) | |
tree | 77d9ce5e1bf78b3e6ef79f8f6e7861e2ced3c09b /vendor/ipl/web/src/Common | |
parent | Initial commit. (diff) | |
download | icinga-php-library-upstream.tar.xz icinga-php-library-upstream.zip |
Adding upstream version 0.10.1.upstream/0.10.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ipl/web/src/Common')
-rw-r--r-- | vendor/ipl/web/src/Common/BaseTarget.php | 33 | ||||
-rw-r--r-- | vendor/ipl/web/src/Common/Card.php | 55 | ||||
-rw-r--r-- | vendor/ipl/web/src/Common/CsrfCounterMeasure.php | 48 | ||||
-rw-r--r-- | vendor/ipl/web/src/Common/FormUid.php | 59 | ||||
-rw-r--r-- | vendor/ipl/web/src/Common/RedirectOption.php | 41 | ||||
-rw-r--r-- | vendor/ipl/web/src/Common/StateBadges.php | 184 |
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)); + } +} |