From ba18c13747364891a4e778744809a5f6ed83de97 Mon Sep 17 00:00:00 2001
From: Miraty
Date: Thu, 6 Oct 2022 13:12:04 +0200
Subject: [PATCH] Use a token to link account to external resource
---
fn/common.php | 24 +++++++++++++++++++++++
pages/ht/add-http-dns.php | 41 ++++++++++++++++++++++++++-------------
pages/ns/zone-add.php | 22 +++++++++++++++------
3 files changed, 68 insertions(+), 19 deletions(-)
diff --git a/fn/common.php b/fn/common.php
index 79db585..1b66bbb 100644
--- a/fn/common.php
+++ b/fn/common.php
@@ -136,3 +136,27 @@ function equalArrays($a, $b) {
function linkToDocs($ref, $title) {
return '' . $title . '';
}
+
+/*
+ This token authenticates the user to the server through a public communication (the DNS).
+ It is therefore also designed to keep private:
+ - the user's id
+ - that a same user used a token multiple times (by using a unique salt for each token)
+*/
+define('SECRET_KEY_FILE', sys_get_temp_dir() . '/Niver.key');
+if (!file_exists(SECRET_KEY_FILE)) {
+ $original_umask = umask(0077);
+ file_put_contents(SECRET_KEY_FILE, random_bytes(32));
+ umask($original_umask);
+}
+define('SECRET_KEY', file_get_contents(SECRET_KEY_FILE));
+function getAuthToken() {
+ $salt = bin2hex(random_bytes(4));
+ $hash = hash_hmac('sha256', $salt . ($_SESSION['username'] ?? ''), SECRET_KEY);
+ return $salt . '-' . substr($hash, 0, 32);
+}
+function checkAuthToken($salt, $hash) {
+ $correctProof = substr(hash_hmac('sha256', $salt . $_SESSION['username'], SECRET_KEY), 0, 32);
+ if (hash_equals($correctProof, $hash) !== true)
+ output(403, 'Preuve incorrecte');
+}
diff --git a/pages/ht/add-http-dns.php b/pages/ht/add-http-dns.php
index 362b9bc..4fda659 100644
--- a/pages/ht/add-http-dns.php
+++ b/pages/ht/add-http-dns.php
@@ -16,16 +16,24 @@ if (processForm()) {
$remoteAaaaRecords = dns_get_record($_POST['domain'], DNS_AAAA);
if (is_array($remoteAaaaRecords) !== true)
- output(403, 'Ce domaine n\'existe pas.');
+ output(500, 'Erreur lors de la récupération de l\'enregistrement AAAA.');
if (equalArrays([CONF['ht']['ipv6_address']], array_column($remoteAaaaRecords, 'ipv6')) !== true)
output(403, 'Ce domaine doit avoir pour unique enregistrement AAAA ' . CONF['ht']['ipv6_address'] . '
.');
$remoteARecords = dns_get_record($_POST['domain'], DNS_A);
if (is_array($remoteARecords) !== true)
- output(403, 'Ce domaine n\'existe pas.');
+ output(500, 'Erreur lors de la récupération de l\'enregistrement A.');
if (equalArrays([CONF['ht']['ipv4_address']], array_column($remoteARecords, 'ip')) !== true)
output(403, 'Ce domaine doit avoir pour unique enregistrement A ' . CONF['ht']['ipv4_address'] . '
.');
+ $remoteTXTRecords = dns_get_record($_POST['domain'], DNS_TXT);
+ if (is_array($remoteTXTRecords) !== true)
+ output(500, 'Erreur lors de la récupération de l\'enregistrement TXT.');
+ if (preg_match('/\nauth-owner=([0-9a-f]{8})-([0-9a-f]{32})\n/', "\n" . implode("\n", array_column($remoteTXTRecords, 'txt')) . "\n", $matches) !== 1)
+ output(403, 'Aucun enregistrement TXT au format correct trouvé.');
+
+ checkAuthToken($matches[1], $matches[2]);
+
rateLimit();
addSite($_SESSION['username'], $_POST['dir'], $_POST['domain'], "dns", "http");
@@ -57,6 +65,8 @@ if (processForm()) {
output(200, 'Accès HTTP par domaine ajouté sur ce dossier !');
}
+$proof = getAuthToken();
+
?>
@@ -64,19 +74,24 @@ if (processForm()) {
- Le domaine doit contenir ces enregistrements :
-
- AAAA
- -
-
= CONF['ht']['ipv6_address'] ?>
-
- A
- -
-
= CONF['ht']['ipv4_address'] ?>
-
-
+ La présence des enregistrements ci-après sera vérifiée lors du traitement de ce formulaire.
+
+ AAAA
+ -
+
= CONF['ht']['ipv6_address'] ?>
+
+ A
+ -
+
= CONF['ht']['ipv4_address'] ?>
+
+ TXT
+ -
+
auth-owner== $proof ?>
+
+
+