From 187494cd50f503d5e5998e8bdb987b6156cf8c05 Mon Sep 17 00:00:00 2001 From: Dirk Heilig Date: Wed, 11 Oct 2023 00:04:02 +0200 Subject: [PATCH] add multi user setup --- Readme.md | 16 +++++++++-- htdocs/index.php | 71 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/Readme.md b/Readme.md index 60e8e05..ca3898f 100644 --- a/Readme.md +++ b/Readme.md @@ -9,12 +9,23 @@ This is a restic connector for kumar. It allows you to check if you backups did Just run the container, ideally using compose and expose port 80, maybe use something like traffic to make it https. You could add a volume to /var/www/data to persist the data. This is not necessary, but a fresh container will not report functional backups until you reported something. -If it's nor prevented on a network level for the world to submit data, you might whant to set RKC_USER and RKC_PASS to prevent random people from submitting data. +If it's not prevented on a network level for the world to submit data, you might want to use basic auth to prevent random people from submitting data. You need to use these credentials when reporting to the webservice. +### authentication + +For backwards compatibility you can have a single user / repo setup by setting the ENV-vars `RKC_USER` and `RKC_PASS`. +You should not use this, anymore on new setups. +Instead, you should use the new multi-user setup. +You have a single env-var for every user. +The name of the env-var is `RKC_USER_`, the value is the password. +eg. to have 2 users, alice with the passwort secret and bob with the password hunter2, you would set the env-vars `RKC_USER_ALICE` and `RKC_USER_BOB` to `secret` and `hunter2`, respectively. +usernames only support alphanumeric characters and underscores and minus, they are case-insensitive. +There are no restrictions on passwords. + ### Reporting -To report your you need to post the output of `restic snapshots` to the webservice, eg: +To report your snapshots, you need to post the output of `restic snapshots` to the webservice, eg: ```bash restic snapshots | curl -X POST -d @- http://restic_kumar_reporter/ @@ -31,6 +42,7 @@ when RKC_USER and RKC_PASS are set. ### Checking with kumar Just point kumar to your webservice. +You need to add an query parameter ?u= and the username used. The Output looks something like this: ``` diff --git a/htdocs/index.php b/htdocs/index.php index 5190e13..99ab80c 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -1,21 +1,55 @@ $v) { + if (preg_match("/^RKC_USER_(.*)$/", $k, $m)) { + if ($mode === "SINGLE_AUTH") { + header("HTTP/1.0 500 Internal Server Error"); + echo "single auth and multi auth is used at the same time"; exit(); } + $mode = "MULTI_AUTH"; + $u = $m[1]; + if (!preg_match("/^[a-zA-Z0-9_-]+$/", $k)) { + header("HTTP/1.0 500 Internal Server Error"); + echo "invalid username, only a-zA-Z0-9 and _- are allowed"; + exit(); + } + $credentials[strtolower($u)] = $v; } +} + +if ($_SERVER["REQUEST_METHOD"] === "POST") { + if ( + checkAuth( + strtolower($_SERVER["PHP_AUTH_USER"] ?? null), + $_SERVER["PHP_AUTH_PW"] ?? null, + $credentials, + $mode + ) === false + ) { + header('WWW-Authenticate: Basic realm="RKC"'); + header("HTTP/1.0 401 Unauthorized"); + echo "You are not authorized to access this page."; + exit(); + } + $fileName = $_SERVER["PHP_AUTH_USER"] . ".json"; $resticData = file_get_contents("php://input"); $resticData = explode("\n", $resticData); @@ -51,15 +85,22 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") { } ksort($backups); file_put_contents( - "/var/www/data/backups.json", + "/var/www/data/$fileName", json_encode($backups, JSON_UNESCAPED_SLASHES + JSON_PRETTY_PRINT) ); exit(); } +$fileName = $_GET["user"]; +if (!isset($credentials[$fileName])) { + header("HTTP/1.0 404 Not Found"); + echo "user not found"; + exit(); +} +$fileName .= ".json"; header("Content-Type: text/plain"); $maxAge = isset($_GET["maxage"]) ? intval($_GET["maxage"]) : 28; $maxAge = $maxAge * 60 * 60; -$backups = json_decode(file_get_contents("/var/www/data/backups.json"), true); +$backups = json_decode(file_get_contents("/var/www/data/$fileName"), true); echo "BACKUP|HOST|PATH|STATUS\n"; foreach ($backups as $backupName => $backupTime) { echo "BACKUP|$backupName|";