Add Gemini support

This commit is contained in:
Miraty 2021-03-02 22:56:38 +01:00
parent 300efe4a04
commit 9ff2318b1b
21 changed files with 369 additions and 58 deletions

78
ht/gemini-domain.php Normal file
View file

@ -0,0 +1,78 @@
<?php require "../top.inc.php"; ?>
<p>
Ajouter un domaine sur un dossier de site<br>
Le domaine doit pointer vers ces adresses IP :<br>
IPv4 : 45.13.104.169<br>
IPv6 : 2a0b:cbc0:1103:2::106f
</p>
<form method="post">
<label for="domain">Domaine sur lequel répondre</label><br>
<input required="" placeholder="site.atope.art" id="domain" name="domain" type="text"><br>
<label for="dir">Dossier ciblé</label><br>
<select required="" name="dir" id="dir">
<option value="" disabled="" selected="">---</option>
<?php
$fsDirs = listFsDirs($_SESSION['username']);
$dbUsedDirs = listDbDirs($_SESSION['username'], "dns", "gemini");
$i = 0;
$j = 0;
$alreadyEnabledDirs = NULL;
$notYetEnabledDirs = NULL;
foreach ($fsDirs as $fsDir) {
if ($dbUsedDirs AND in_array($fsDir, $dbUsedDirs)) {
$alreadyEnabledDirs[$i] = $fsDir;
$i++;
} else {
$notYetEnabledDirs[$j] = $fsDir;
$j++;
}
}
if (!is_null($notYetEnabledDirs)) {
foreach ($notYetEnabledDirs as $dir) {
echo "<option value='" . $dir . "'>" . $dir . "</option>";
}
}
if (!is_null($alreadyEnabledDirs)) {
foreach ($alreadyEnabledDirs as $dir) {
echo "<option disabled='' value='" . $dir . "'>" . $dir . "</option>";
}
}
?>
</select>
<br>
<input value="Valider" type="submit">
</form>
<?php
if (isset($_POST['domain']) AND isset($_POST['dir']) AND isset($_SESSION['username'])) {
checkDomainFormat($_POST['domain']);
if (!in_array($_POST['dir'], $notYetEnabledDirs))
exit("ERROR : Wrong value for dir");
addSite($_SESSION['username'], $_POST['dir'], $_POST['domain'], "dns", "gemini");
$conf = "# START NIVERSITE
[" . $_POST['domain'] . "]
root=/srv/hyper/" . $_SESSION['username'] . "/hyper/" . $_POST['dir'] . "
# STOP NIVERSITE
";
file_put_contents("/etc/gmnisrv.ini", $conf, FILE_APPEND);
// Restart the gmnisrv daemon (as there is no reload support)
exec("sudo " . MANIVER_PATH . " restart-gmnisrv");
echo "Accès par domaine ajouté sur ce dossier !";
}
?>
<?php require "../bottom.inc.php"; ?>

89
ht/gemini-onion.php Normal file
View file

@ -0,0 +1,89 @@
<?php require "../top.inc.php"; ?>
<p>
Ajouter un accès en .onion sur un dossier
</p>
<form method="post">
<label for="dir">Dossier ciblé</label><br>
<select required="" name="dir" id="dir">
<option value="" disabled="" selected="">---</option>
<?php
$fsDirs = listFsDirs($_SESSION['username']);
$dbUsedDirs = listDbDirs($_SESSION['username'], "onion", "gemini");
$i = 0;
$j = 0;
$alreadyEnabledDirs = NULL;
$notYetEnabledDirs = NULL;
foreach ($fsDirs as $fsDir) {
if ($dbUsedDirs AND in_array($fsDir, $dbUsedDirs)) {
$alreadyEnabledDirs[$i] = $fsDir;
$i++;
} else {
$notYetEnabledDirs[$j] = $fsDir;
$j++;
}
}
if (!is_null($notYetEnabledDirs)) {
foreach ($notYetEnabledDirs as $dir) {
echo "<option value='" . $dir . "'>" . $dir . "</option>";
}
}
if (!is_null($alreadyEnabledDirs)) {
foreach ($alreadyEnabledDirs as $dir) {
echo "<option disabled='' value='" . $dir . "'>" . $dir . "</option>";
}
}
?>
</select>
<br>
<input value="Valider" type="submit">
</form>
<?php
if (isset($_POST['dir']) AND isset($_SESSION['username'])) {
if (!in_array($_POST['dir'], $notYetEnabledDirs))
exit("ERROR : Wrong value for dir");
// Generate a .onion address
$torConf = file_get_contents("/etc/tor/torrc");
$torConf = $torConf . "\nHiddenServiceDir /var/lib/tor/niver/" . $_POST['dir'] . "/\nHiddenServicePort 1965 [::1]:1965";
file_put_contents("/etc/tor/torrc", $torConf);
exec("sudo -u root " . MANIVER_PATH . " reload-tor", $output);
addNiverLog("Tor reloaded by " . $_SESSION['username'], $output);
// Copy generated address to a location readable by PHP
exec("sudo -u root " . MANIVER_PATH . " export-tor " . $_SESSION['username'] . " " . $_POST['dir'], $output);
addNiverLog("Tor data exported by " . $_SESSION['username'], $output);
// Get the address generated by Tor
$onion = file_get_contents("/srv/hyper/" . $_SESSION['username'] . "/hyper/" . $_POST['dir'] . "/hostname");
$onion = str_replace(array("\r","\n"), "", $onion);
// Store it in the database
addSite($_SESSION['username'], $_POST['dir'], $onion, "onion", "gemini");
$conf = "# START NIVERSITE
[" . $onion . "]
root=/srv/hyper/" . $_SESSION['username'] . "/hyper/" . $_POST['dir'] . "
# STOP NIVERSITE
";
file_put_contents("/etc/gmnisrv.ini", $conf, FILE_APPEND);
// Restart the gmnisrv daemon (as there is no reload support)
exec("sudo " . MANIVER_PATH . " restart-gmnisrv");
// Tell the user their site address
echo "<p>L'adresse de votre capsule Onion Gemini est :<br><a href='http://" . $onion . "'<code>http://" . $onion . "</code></a></p>";
}
?>
<?php require "../bottom.inc.php"; ?>

View file

@ -55,11 +55,11 @@ if (isset($_POST['dir']) AND isset($_SESSION['username'])) {
$torConf = $torConf . "\nHiddenServiceDir /var/lib/tor/niver/" . $_POST['dir'] . "/\nHiddenServicePort 80 [::1]:80";
file_put_contents("/etc/tor/torrc", $torConf);
exec("sudo -u root /root/maniver/target/debug/maniver reload-tor", $output);
exec("sudo -u root " . MANIVER_PATH . " reload-tor", $output);
addNiverLog("Tor reloaded by " . $_SESSION['username'], $output);
// Copy generated address to a location readable by PHP
exec("sudo -u root /root/maniver/target/debug/maniver export-tor " . $_SESSION['username'] . " " . $_POST['dir'], $output);
exec("sudo -u root " . MANIVER_PATH . " export-tor " . $_SESSION['username'] . " " . $_POST['dir'], $output);
addNiverLog("Tor data exported by " . $_SESSION['username'], $output);
// Get the address generated by Tor
@ -80,7 +80,7 @@ if (isset($_POST['dir']) AND isset($_SESSION['username'])) {
exec("sudo /root/maniver/target/debug/maniver reload-nginx");
// Tell the user their site address
echo "<p>L'adresse de votre site Onion est :<br><a href='http://" . $onion . "'<code>http://" . $onion . "</code></a></p>";
echo "<p>L'adresse de votre site Onion HTTP est :<br><a href='http://" . $onion . "'<code>http://" . $onion . "</code></a></p>";
}

View file

@ -1,4 +1,5 @@
<?php require "../top.inc.php"; ?>
<p>
Ajouter un domaine sur un dossier de site<br>
Le domaine doit pointer vers ces adresses IP :<br>
@ -64,9 +65,9 @@ if (isset($_POST['domain']) AND isset($_POST['dir']) AND isset($_SESSION['userna
$conf = preg_replace("#DIR#", $_POST['dir'], $conf);
$conf = preg_replace("#USER#", $_SESSION['username'], $conf);
file_put_contents("/etc/nginx/hyper.d/" . $_POST['domain'] . ".conf", $conf);
exec("sudo /root/maniver/target/debug/maniver reload-nginx");
exec("sudo " . MANIVER_PATH . " reload-nginx");
//certbot certonly --nginx -d testcrabe.atope.art
echo "Accès par domaine ajouté sur ce dossier !";
echo "Accès HTTP par domaine ajouté sur ce dossier !";
}
?>

View file

@ -5,7 +5,11 @@ Accéder à son espace SFTP, pour publier et mettre à jour ses sites
<h2><a class="htButton" href="http-onion">Accès HTTP en Onion</a></h2>
Un site HTML, accessible par Tor, avec une adresse en .onion
<h2><a class="htButton" href="https-domain">Accès HTTPS par DNS</a></h2>
Des pages HTML, accessible directement, par un nom de domaine
Un site HTML, accessible directement, par un nom de domaine
<h2><a class="htButton" href="gemini-onion">Accès Gemini en Onion</a></h2>
Une capsule Gemini, accessible par Tor, avec une adresse en .onion
<h2><a class="htButton" href="gemini-domain">Accès Gemini par DNS</a></h2>
Une capsule Gemini, accessible directement, par un nom de domaine
<h2><a class="htButton" href="le">Installer un certificat Let's Encrypt sur un domaine</a></h2>
<?php require "../bottom.inc.php"; ?>

View file

@ -14,7 +14,7 @@
if (isset($_POST['domain'])) {
exec("sudo /root/maniver/target/debug/maniver le-install " . $_POST['domain'], $output);
exec("sudo " . MANIVER_PATH . " le-install " . $_POST['domain'], $output);
echo "<pre>";
print_r($output);
echo "</pre>";

View file

@ -4,7 +4,7 @@
if ($_SESSION['sftp_enabled'] == false) { ?>
<p>
Pour que vous puissiez mettre en ligne votre site via <abbr title="SSH File Transfert Protocol">SFTP</abbr>, veuillez définir un mot de passe.
<br>Il ne pourra pas être modifié.
<br>Il sera loggué en clair dans le systèmee et il ne pourra pas être modifié.
</p>
<form method="post">
@ -19,9 +19,12 @@ if ($_SESSION['sftp_enabled'] == false) { ?>
if (isset($_SESSION['username']) AND isset($_POST['password'])) {
// Setup SFTP access
exec("sudo /root/maniver/target/debug/maniver setup-user " . $_SESSION['username'] . " " . $_POST['password']);
exec("sudo " . MANIVER_PATH . " setup-user " . $_SESSION['username'] . " " . $_POST['password'], $output);
addNiverLog($_SESSION['username'] . " enabled SFTP on their account", $output);
enableSftp($_SESSION['username']);
$_SESSION['sftp_enabled'] = true;
header('Location: ' . PREFIX . '/' . SERVICE . '/' . PAGE . '', true, 302);
exit();
}
} else if ($_SESSION['sftp_enabled'] == true) { ?>

View file

@ -10,6 +10,15 @@ function addNiverLog($message, $outputLines) {
file_put_contents(ROOT_PATH . "/niver.log", $logs, FILE_APPEND);
}
function checkAction($action) {
if ($action === "delete")
return "un";
else if ($action === "add")
return "";
else
exit("ERROR: wrong value for action");
}
function listUserZones($username) {
$db = new PDO('sqlite:' . DB_PATH);
$usernameArray[0] = $username;

View file

@ -4,23 +4,23 @@ if (strpos($_SERVER['PHP_SELF'], "inc.php") !== false)
function checkIpFormat($ip) {
if (!filter_var($ip, FILTER_VALIDATE_IP))
exit("Erreur : l'adresse IP n'est pas valide");
exit("ERROR: wrong IP address");
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE))
exit("Erreur : l'adresse IP est dans une plage privée");
exit("ERROR: IP address is on the private range");
if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE))
exit("Erreur : l'adresse IP est dans une plage réservée");
exit("ERROR: IP address is on the reserved range");
}
function checkAbsoluteDomainFormat($domain) {
// If the domain must end with a dot
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN) OR !preg_match("/^([a-z0-9]{1,63}\.){2,127}$/", $domain))
exit("Erreur : ce domaine n'est pas valide !");
exit("ERROR: wrong domain");
}
function checkDomainFormat($domain) {
// If the domain must end without a dot
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN) OR !preg_match("/^([a-z0-9]{1,63}\.){1,126}[a-z0-9]{1,63}$/", $domain))
exit("Erreur : ce domaine n'est pas valide !");
exit("ERROR: wrong domain");
}
function checkPasswordFormat($password) {

15
inc/html/ttl.ns.inc.php Normal file
View file

@ -0,0 +1,15 @@
<fieldset>
<legend><abbr title="Time To Live">TTL</abbr></legend>
<label for="ttl-value">Valeur</label>
<br>
<input id="ttl-value" list="ttls" name="ttl-value" size="10" type="number" min="300" max="604800" value="3600" placeholder="3600">
<br>
<label for="ttl-multiplier">Unité</label>
<br>
<select name="ttl-multiplier" id="ttl-multiplier">
<option value="1">seconde</option>
<option value="60">minute</option>
<option value="3600">heure</option>
<option value="86400">jour</option>
</select>
</fieldset>

View file

@ -2,8 +2,17 @@
if (strpos($_SERVER['PHP_SELF'], "inc.php") !== false)
exit("This file is meant to be included.");
function nsCheckZonePossession($zone) {
checkAbsoluteDomainFormat($zone);
function nsTtl($value, $multiplier) {
$ttl = $value * $multiplier;
if (!($ttl >= 300 AND $ttl <= 432000))
exit("Erreur : le TTL doit être compris entre 5 minutes et 5 jours (entre 300 et 432000 secondes)");
return $ttl;
}
function nsCheckZonePossession($submittedZone) {
checkAbsoluteDomainFormat($submittedZone);
$db = new PDO('sqlite:' . DB_PATH);
$username[0] = $_SESSION['username'];
@ -11,16 +20,13 @@ function nsCheckZonePossession($zone) {
$op = $db->prepare('SELECT zone FROM zones WHERE username = ?');
$op->execute($username);
$domain = $op->fetch()['zone'];
$dbZone = $op->fetch()['zone'];
while ($domain != NULL) {
if ($domain === $zone) {
$owned = true;
break;
}
$domain = $op->fetch()['zone'];
while ($dbZone != NULL) {
if ($dbZone === $submittedZone) return;
$dbZone = $op->fetch()['zone'];
}
if (!($owned === true))
exit("Erreur : Vous ne possédez pas ce domaine sur le serveur de noms !");
// If there is no entry in the database for the user matching the submitted zone
exit("ERROR: You don't own this zone on the nameserver");
}

View file

@ -22,6 +22,9 @@ switch (SERVICE) {
case "txt":
$page['title'] = "Enregistrement TXT";
break;
case "caa":
$page['title'] = "Enregistrement CAA";
break;
case "zone":
$page['title'] = "Ajouter une zone";
break;
@ -64,6 +67,9 @@ switch (SERVICE) {
case "password":
$page['title'] = "Changer le mot de passe";
break;
case "logout":
$page['title'] = "Déconnexion";
break;
}
break;
@ -73,8 +79,14 @@ switch (SERVICE) {
case "mkdir":
$page['title'] = "Créer un dossier de site";
break;
case "gemini-onion":
$page['title'] = "Accès Gemini en Onion";
break;
case "gemini-domain":
$page['title'] = "Accès Gemini par domaine";
break;
case "http-onion":
$page['title'] = "Accès HTTP en .onion";
$page['title'] = "Accès HTTP en Onion";
break;
case "https-domain":
$page['title'] = "Accès HTTPS par domaine";

View file

@ -12,3 +12,38 @@
status: exit code: 0
stdout:
stderr:
2021-02-27 19:32:34 poule enabled SFTP on their account
status: exit code: 0
stdout:
stderr:
2021-02-27 19:45:47 poireau enabled SFTP on their account
status: exit code: 0
stdout:
stderr:
sent username:password to chpasswd
chpasswd responded with:
status: exit code: 0
stdout:
stderr:
status: exit code: 0
stdout:
stderr:
status: exit code: 0
stdout:
stderr:
2021-02-27 19:59:45 Tor reloaded by poireau
2021-02-27 19:59:45 Tor data exported by poireau
status: exit code: 0
stdout:
stderr:
2021-02-27 20:06:30 Tor reloaded by poireau
2021-02-27 20:06:30 Tor data exported by poireau
status: exit code: 0
stdout:
stderr:

83
ns/caa.php Normal file
View file

@ -0,0 +1,83 @@
<?php include "../top.inc.php"; ?>
<form method="post">
<label for="action">Action</label>
<select name="action" id="action">
<option value="add">Ajouter</option>
<option value="delete">Retirer</option>
</select>
<br>
<label for="zone">Zone</label>
<br>
<select required="" name="zone" id="zone">
<option value="" disabled="" selected="">---</option>
<?php
$zones = listUserZones($_SESSION['username']);
foreach ($zones as $zone) {
echo "<option value='" . $zone . "'>" . $zone . "</option>";
}
?>
</select>
<br>
<?php require "../inc/html/ttl.ns.inc.php"; ?>
<br>
<label for="domain">Domaine</label>
<br>
<input id="domain" placeholder="monsite.atope.art." name="domain" type="text">
<br>
<label for="flag">Flag</label>
<br>
<input id="flag" min="0" max="127" placeholder="0" name="flag" type="number">
<br>
<label for="tag">Tag</label>
<br>
<input id="tag" minlenght="1" maxlength="128" pattern="^[a-z]{1,128}$" placeholder="issue" name="tag" type="text">
<br>
<label for="value">Valeur</label>
<br>
<input id="value" minlenght="3" maxlength="1024" pattern="^[a-z0-9.-]{3,1024}$" placeholder="letsencrypt.org" name="value" type="text">
<br>
<input value="Valider" type="submit">
</form>
<?php
if (
isset($_POST['zone'])
AND isset($_POST['domain'])
AND isset($_POST['ttl-value'])
AND isset($_POST['ttl-multiplier'])
AND isset($_POST['action'])
AND isset($_POST['flag'])
AND isset($_POST['tag'])
AND isset($_POST['value'])
AND isset($_SESSION['username'])
) {
if (!($_POST['flag'] >= 0 AND $_POST['flag'] <= 255))
exit("ERROR: Wrong value for flag");
if (!(preg_match("/^[a-z]{1,127}$/", $_POST['tag'])))
exit("ERROR: Wrong value for tag");
if (!(preg_match("/^[a-z0-9.-]{1,255}$/", $_POST['value'])))
exit("ERROR: Wrong value for value");
nsCheckZonePossession($_POST['zone']);
checkAbsoluteDomainFormat($_POST['domain']);
$action = checkAction($_POST['action']);
$ttl = nsTtl($_POST['ttl-value'], $_POST['ttl-multiplier']);
exec(KNOTC_PATH . " zone-begin " . $_POST['zone']);
exec(KNOTC_PATH . " zone-" . $action . "set " . $_POST['zone'] . " " . $_POST['domain'] . " " . $ttl . " IN CAA " . $_POST['flag'] . " " . $_POST['tag'] . " " . $_POST['value']);
exec(KNOTC_PATH . " zone-commit " . $_POST['zone']);
echo "Enregistrement ajouté";
}
?>
<?php include "../bottom.inc.php"; ?>

View file

@ -16,7 +16,7 @@ Mettre en place <abbr title="DNS-based Authentication of Named Entities">DANE</a
Indiquer les seules autorités de certifications autorisée à signer les domaines
<h2><a class="nsButton" href="srv">Enregistrement SRV</a></h2>
Indiquer un serveur pour un domaine
<h2><a class="nsButton" href="mx">Enregistrement <abbr title="Mail eXchange">MX</abbr></a></h2>
<h2><a class="nsButton" href="mx">Enregistrement <abbr title="Mail eXchanger">MX</abbr></a></h2>
Indiquer le serveur mail pour un domaine
<h2><a class="nsButton" href="loc">Enregistrement LOC</a></h2>
Indiquer la localisation physique d'un domaine

View file

@ -67,12 +67,7 @@ if (isset($_POST['domain']) AND isset($_POST['ip']) AND isset($_POST['zone']) AN
else
exit("Erreur inconnue sur le format de l'IP");
if ($_POST['action'] == "delete")
$action = "un";
else if ($_POST['action'] == "add")
$action = "";
else
exit("ERROR : Wrong value for action");
$action = checkAction($_POST['action']);
exec(KNOTC_PATH . " zone-begin " . $_POST['zone']);
exec(KNOTC_PATH . " zone-" . $action . "set " . $_POST['zone'] . " " . $_POST['domain'] . " 3600 " . $record . " " . $_POST['ip']);

View file

@ -40,12 +40,7 @@ if (isset($_POST['zone']) AND isset($_POST['domain']) AND isset($_POST['action']
checkAbsoluteDomainFormat($_POST['domain']);
checkAbsoluteDomainFormat($_POST['ns']);
if ($_POST['action'] == "delete")
$action = "un";
else if ($_POST['action'] == "add")
$action = "";
else
exit("Erreur : valeur invalide pour action");
$action = checkAction($_POST['action']);
exec(KNOTC_PATH . " zone-begin " . $_POST['zone']);
exec(KNOTC_PATH . " zone-" . $action . "set " . $_POST['zone'] . " " . $_POST['domain'] . " 3600 IN NS " . $_POST['ns']);

View file

@ -42,18 +42,13 @@ if (isset($_POST['zone']) AND isset($_POST['domain']) AND isset($_POST['action']
nsCheckZonePossession($_POST['zone']);
checkAbsoluteDomainFormat($_POST['domain']);
if ($_POST['action'] == "delete")
$action = "un";
else if ($_POST['action'] == "add")
$action = "";
else
exit("Erreur : valeur invalide pour action");
$action = checkAction($_POST['action']);
$test = ' 3600 IN TXT \"' . $_POST['txt'] . '\"';
echo $test;
exec(KNOTC_PATH . " zone-begin " . $_POST['zone']);
exec(KNOTC_PATH . " zone-" . $action . "set " . $_POST['zone'] . " " . $_POST['domain'] . ' 3600 IN TXT \"' . $_POST['txt'] . '\"');
exec(KNOTC_PATH . " zone-" . $action . "set " . $_POST['zone'] . " " . $_POST['domain'] . ' 3600 IN TXT \"' . $_POST['txt'] . '\"');
exec(KNOTC_PATH . " zone-commit " . $_POST['zone']);
echo "Enregistrement ajouté";
}

View file

@ -58,12 +58,7 @@ if (isset($_POST['action']) AND isset($_POST['subdomain']) AND isset($_POST['suf
else
exit("Unknown error about IP format");
if ($_POST['action'] == "delete")
$action = "un";
else if ($_POST['action'] == "add")
$action = "";
else
exit("ERROR : Wrong value for action");
$action = checkAction($_POST['action']);
// Remove anything before the first dot and the first dot itself
$suffix = regGetSuffix($_POST['suffix']);

View file

@ -39,12 +39,7 @@ if (isset($_POST['domain']) AND isset($_POST['action']) AND isset($_POST['ns'])
regCheckDomainPossession($_POST['domain']);
checkAbsoluteDomainFormat($_POST['ns']);
if ($_POST['action'] == "delete")
$action = "un";
else if ($_POST['action'] == "add")
$action = "";
else
exit("Erreur : valeur invalide pour action");
$action = checkAction($_POST['action']);
$suffix = regGetSuffix($_POST['domain']);

View file

@ -26,6 +26,7 @@ define("PAGE", basename($_SERVER['PHP_SELF'], '.php'));
define("DB_PATH", ROOT_PATH . "/db/niver.db");
define("KNOTC_PATH", "/usr/sbin/knotc");
define("KEYMGR_PATH", "/usr/sbin/keymgr");
define("MANIVER_PATH", "/root/maniver/target/release/maniver");
if (SERVICE != "auth" AND !isset($_SESSION['username'])) {
header('Location: ' . PREFIX . '/auth/login?redir=' . SERVICE . "/" . PAGE, true, 302);