diff options
author | 2024-01-25 18:20:02 +0100 | |
---|---|---|
committer | 2024-01-25 18:20:02 +0100 | |
commit | e58c867a82f4c884eaeda93519ed8464d052837c (patch) | |
tree | 481e222f4b2f6987a89eae1f5ed8d2255d8223d4 /lib | |
parent | d08d13f2c87b24fadb92e31c50dedc6e56c3c088 (diff) | |
download | rss-bridge-e58c867a82f4c884eaeda93519ed8464d052837c.tar.gz rss-bridge-e58c867a82f4c884eaeda93519ed8464d052837c.tar.zst rss-bridge-e58c867a82f4c884eaeda93519ed8464d052837c.zip |
feat: token authentication (#3927)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/BridgeCard.php | 39 | ||||
-rw-r--r-- | lib/RssBridge.php | 18 | ||||
-rw-r--r-- | lib/http.php | 14 |
3 files changed, 49 insertions, 22 deletions
diff --git a/lib/BridgeCard.php b/lib/BridgeCard.php index 6b812740..e5456f33 100644 --- a/lib/BridgeCard.php +++ b/lib/BridgeCard.php @@ -2,14 +2,7 @@ final class BridgeCard { - /** - * Render bridge card - * - * @param class-string<BridgeAbstract> $bridgeClassName The bridge name - * @param bool $isActive Indicates if the bridge is active or not - * @return string The bridge card - */ - public static function render($bridgeClassName, $isActive = true) + public static function render(string $bridgeClassName, Request $request): string { $bridgeFactory = new BridgeFactory(); @@ -47,19 +40,21 @@ final class BridgeCard <h2><a href="{$uri}">{$name}</a></h2> <p class="description">{$description}</p> + <input type="checkbox" class="showmore-box" id="showmore-{$bridgeClassName}" /> <label class="showmore" for="showmore-{$bridgeClassName}">Show more</label> CARD; - // If we don't have any parameter for the bridge, we print a generic form to load it. + $token = $request->attribute('token'); + if (count($contexts) === 0) { // The bridge has zero parameters - $card .= self::renderForm($bridgeClassName, $isActive); + $card .= self::renderForm($bridgeClassName, '', [], $token); } elseif (count($contexts) === 1 && array_key_exists('global', $contexts)) { // The bridge has a single context with key 'global' - $card .= self::renderForm($bridgeClassName, $isActive, '', $contexts['global']); + $card .= self::renderForm($bridgeClassName, '', $contexts['global'], $token); } else { // The bridge has one or more contexts (named or unnamed) foreach ($contexts as $contextName => $contextParameters) { @@ -77,7 +72,7 @@ final class BridgeCard $card .= '<h5>' . $contextName . '</h5>' . PHP_EOL; } - $card .= self::renderForm($bridgeClassName, $isActive, $contextName, $contextParameters); + $card .= self::renderForm($bridgeClassName, $contextName, $contextParameters, $token); } } @@ -99,17 +94,21 @@ final class BridgeCard private static function renderForm( string $bridgeClassName, - bool $isActive = false, - string $contextName = '', - array $contextParameters = [] + string $contextName, + array $contextParameters, + ?string $token ) { $form = <<<EOD - <form method="GET" action="?"> + <form method="GET" action="?" class="bridge-form"> <input type="hidden" name="action" value="display" /> <input type="hidden" name="bridge" value="{$bridgeClassName}" /> - EOD; + if ($token) { + // todo: maybe escape the token? + $form .= sprintf('<input type="hidden" name="token" value="%s" />', $token); + } + if (!empty($contextName)) { $form .= sprintf('<input type="hidden" name="context" value="%s" />', $contextName); } @@ -167,11 +166,7 @@ final class BridgeCard $form .= '</div>'; } - if ($isActive) { - $form .= '<button type="submit" name="format" formtarget="_blank" value="Html">Generate feed</button>'; - } else { - $form .= '<span style="font-weight: bold;">Inactive</span>'; - } + $form .= '<button type="submit" name="format" formtarget="_blank" value="Html">Generate feed</button>'; return $form . '</form>' . PHP_EOL; } diff --git a/lib/RssBridge.php b/lib/RssBridge.php index c8d11596..1bb5f5ea 100644 --- a/lib/RssBridge.php +++ b/lib/RssBridge.php @@ -47,6 +47,7 @@ final class RssBridge ]), 503); } + // HTTP Basic auth check if (Configuration::getConfig('authentication', 'enable')) { if (Configuration::getConfig('authentication', 'password') === '') { return new Response('The authentication password cannot be the empty string', 500); @@ -71,6 +72,23 @@ final class RssBridge // At this point the username and password was correct } + // Add token as attribute to request + $request = $request->withAttribute('token', $request->get('token')); + + // Token authentication check + if (Configuration::getConfig('authentication', 'token')) { + if (! $request->attribute('token')) { + return new Response(render(__DIR__ . '/../templates/token.html.php', [ + 'message' => '', + ]), 401); + } + if (! hash_equals(Configuration::getConfig('authentication', 'token'), $request->attribute('token'))) { + return new Response(render(__DIR__ . '/../templates/token.html.php', [ + 'message' => 'Invalid token', + ]), 401); + } + } + $action = $request->get('action', 'Frontpage'); $actionName = strtolower($action) . 'Action'; $actionName = implode(array_map('ucfirst', explode('-', $actionName))); diff --git a/lib/http.php b/lib/http.php index d53909b4..e4f9bf48 100644 --- a/lib/http.php +++ b/lib/http.php @@ -170,6 +170,7 @@ final class Request { private array $get; private array $server; + private array $attributes; private function __construct() { @@ -180,6 +181,7 @@ final class Request $self = new self(); $self->get = $_GET; $self->server = $_SERVER; + $self->attributes = []; return $self; } @@ -200,6 +202,18 @@ final class Request return $this->server[$key] ?? $default; } + public function withAttribute(string $name, $value = true): self + { + $clone = clone $this; + $clone->attributes[$name] = $value; + return $clone; + } + + public function attribute(string $key, $default = null) + { + return $this->attributes[$key] ?? $default; + } + public function toArray(): array { return $this->get; |