aboutsummaryrefslogtreecommitdiff
path: root/Psso/Challenge.php
diff options
context:
space:
mode:
Diffstat (limited to 'Psso/Challenge.php')
-rw-r--r--Psso/Challenge.php59
1 files changed, 59 insertions, 0 deletions
diff --git a/Psso/Challenge.php b/Psso/Challenge.php
new file mode 100644
index 0000000..72100ce
--- /dev/null
+++ b/Psso/Challenge.php
@@ -0,0 +1,59 @@
+<?php
+namespace Psso;
+
+abstract class Challenge {
+ public protected(set) Context $context;
+ protected array $inputs = [];
+ public protected(set) string $serial;
+
+ protected function __construct(Context $context) {
+ $this->context = $context;
+ $this->serial = base64_encode(random_bytes(9));
+ }
+
+ public static function create(Context $context): ?static {
+ return new static($context);
+ }
+
+ public abstract function getInputs(): array;
+
+ public abstract function validate(
+ AuthProvider $provider, array $inputData
+ ): ChallengeResult;
+
+ public function addAsHtml(\SimpleXMLElement $parent): void {
+ $form = $parent->addChild('form');
+ $form->addAttribute('method', 'post');
+ foreach ($this->getInputs() as $input) {
+ $input->addAsHtml($form);
+ $this->inputs[$input->serial] = $input;
+ }
+ $serial = $form->addChild('input');
+ $serial->addAttribute('type', 'hidden');
+ $serial->addAttribute('name', 'challenge');
+ $serial->addAttribute('value', $this->serial);
+ $submit = $form->addChild('button', L('challenge.continue'));
+ }
+
+ public function findInput(string $serial): ?Input {
+ return $this->inputs[$serial] ?? null;
+ }
+
+ protected static function requireInterface(
+ AuthProvider $provider, string $interface
+ ): void {
+ if (!($provider instanceof $interface)) {
+ throw new \InvalidArgumentException(
+ "Provider must implement $interface"
+ );
+ };
+ }
+
+ protected static function requireKnownUser(Context $context): void {
+ if (!isset($context->user)) {
+ throw new \RuntimeException(
+ 'Unknown user, but known user required for ' . static::class
+ );
+ }
+ }
+}