Split pages/ between pg-act/ and pg-view/
This commit is contained in:
parent
9e27e479a2
commit
73c137aaba
95 changed files with 1486 additions and 1365 deletions
|
@ -49,9 +49,13 @@ function changePassword($id, $password) {
|
|||
->execute([':password' => hashPassword($password), ':id' => $id]);
|
||||
}
|
||||
|
||||
function logout() {
|
||||
function stopSession() {
|
||||
if (session_status() === PHP_SESSION_ACTIVE)
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
function logout() {
|
||||
stopSession();
|
||||
|
||||
header('Clear-Site-Data: "*"');
|
||||
|
||||
|
|
|
@ -1,37 +1,16 @@
|
|||
<?php
|
||||
|
||||
$final_message = NULL;
|
||||
|
||||
function output($code, $msg = '', $logs = ['']) {
|
||||
global $final_message;
|
||||
http_response_code($code);
|
||||
$shortCode = $code / 100 % 10;
|
||||
if ($shortCode === 5)
|
||||
error_log('Niver internal error: ' . strip_tags($msg) . implode(LF, $logs));
|
||||
$final_message = match ($shortCode) {
|
||||
2 => ($msg === '') ? '' : '<p><output><strong>Succès</strong> : <em>' . $msg . '</em></output></p>' . LF,
|
||||
4 => '<p><output><strong>Erreur utilisataire</strong> : <em>' . $msg . '</em></output></p>' . LF,
|
||||
5 => '<p><output><strong>Server error</strong>: The server encountered an error: <em>' . $msg . '</em></output></p>' . LF,
|
||||
};
|
||||
http_response_code($code);
|
||||
if ($shortCode === 5)
|
||||
error_log('Niver internal error: ' . strip_tags($msg) . implode(LF, $logs));
|
||||
if ($code !== 200)
|
||||
executePage();
|
||||
}
|
||||
|
||||
function processForm($requireLogin = true) {
|
||||
if (http_response_code() !== 200)
|
||||
return false;
|
||||
if ($_POST === []) {
|
||||
if ($requireLogin AND !isset($_SESSION['id']))
|
||||
echo '<p>Ce formulaire ne sera pas accepté car il faut <a class="auth" href="' . redirUrl('auth/login') . '">se connecter</a> avant.</p>';
|
||||
return false;
|
||||
}
|
||||
if ($requireLogin) {
|
||||
if (isset($_SESSION['id']) !== true)
|
||||
output(403, 'Vous devez être connecté·e à un compte pour effectuer cette action.');
|
||||
if (isset(query('select', 'users', ['id' => $_SESSION['id']], 'id')[0]) !== true)
|
||||
output(403, 'Ce compte n\'existe plus. Déconnectez-vous pour terminer cette session fantôme.');
|
||||
}
|
||||
return true;
|
||||
displayPage(['final_message' => $final_message]);
|
||||
}
|
||||
|
||||
function insert($table, $values) {
|
||||
|
|
14
fn/dns.php
14
fn/dns.php
|
@ -1,5 +1,19 @@
|
|||
<?php
|
||||
|
||||
function parseZoneFile($zone_content, $types, $filter_domain = false) {
|
||||
$parsed_zone_content = [];
|
||||
foreach(explode(LF, $zone_content) as $zone_line) {
|
||||
if ($zone_line === '' OR str_starts_with($zone_line, ';'))
|
||||
continue; // Ignore empty lines and comments
|
||||
$elements = preg_split('/[\t ]+/', $zone_line, 4);
|
||||
if ($filter_domain !== false AND !str_ends_with($elements[0], $filter_domain))
|
||||
continue; // Ignore records for other domains
|
||||
if (!in_array($elements[2], $types, true)) continue; // Ignore records generated by Knot
|
||||
array_push($parsed_zone_content, array_map('htmlspecialchars', $elements));
|
||||
}
|
||||
return $parsed_zone_content;
|
||||
}
|
||||
|
||||
function knotcConfExec($cmds) {
|
||||
exec(CONF['dns']['knotc_path'] . ' conf-begin', $output['begin'], $code['begin']);
|
||||
if ($code['begin'] !== 0)
|
||||
|
|
|
@ -44,8 +44,10 @@ function nsParseCommonRequirements() {
|
|||
return $values;
|
||||
}
|
||||
|
||||
function nsListUserZones($username) {
|
||||
return query('select', 'zones', ['username' => $username], 'zone');
|
||||
function nsListUserZones() {
|
||||
if (isset($_SESSION['id']))
|
||||
return query('select', 'zones', ['username' => $_SESSION['id']], 'zone');
|
||||
return [];
|
||||
}
|
||||
|
||||
function nsCheckZonePossession($zone) {
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
const SUBDOMAIN_REGEX = '^[a-z0-9]{4,63}$';
|
||||
|
||||
function regListUserDomains($username) {
|
||||
return query('select', 'registry', ['username' => $username], 'domain');
|
||||
function regListUserDomains() {
|
||||
if (isset($_SESSION['id']))
|
||||
return query('select', 'registry', ['username' => $_SESSION['id']], 'domain');
|
||||
return [];
|
||||
}
|
||||
|
||||
function regCheckDomainPossession($domain) {
|
||||
if (in_array($domain, regListUserDomains($_SESSION['id']), true) !== true)
|
||||
if (in_array($domain, regListUserDomains(), true) !== true)
|
||||
output(403, 'You don\'t own this domain.');
|
||||
}
|
||||
|
||||
|
|
|
@ -18,9 +18,8 @@
|
|||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach (nsListUserZones($_SESSION['id']) as $zone)
|
||||
echo "<option value='" . $zone . "'>" . $zone . "</option>";
|
||||
foreach (nsListUserZones() as $zone)
|
||||
echo "<option value='" . $zone . "'>" . $zone . "</option>";
|
||||
?>
|
||||
|
||||
</select>
|
||||
|
|
|
@ -12,10 +12,12 @@ define('PAGES', [
|
|||
'login' => [
|
||||
'title' => 'Se connecter',
|
||||
'description' => 'Démarrer une nouvelle session avec un compte existant',
|
||||
'require-login' => false,
|
||||
],
|
||||
'register' => [
|
||||
'title' => 'Créer un compte',
|
||||
'description' => 'Créer un nouveau compte Niver',
|
||||
'require-login' => false,
|
||||
'tokens_instance_cost' => 7200,
|
||||
],
|
||||
'unregister' => [
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
insert('approval-keys', ['key' => bin2hex(random_bytes(16))]);
|
||||
|
||||
if (processForm()) {
|
||||
|
||||
if ($_SESSION['type'] !== 'testing')
|
||||
output(403, 'Approbation impossible : votre compte est déjà approuvé.');
|
||||
|
||||
if (isset(query('select', 'approval-keys', ['key' => $_POST['key']], 'key')[0]) !== true)
|
||||
output(403, 'Approbation impossible : cette clé d\'approbation n\'est pas disponible. Elle a été mal saisie, a expiré ou a déjà été utilisée pour un autre compte.');
|
||||
|
||||
query('delete', 'approval-keys', ['key' => $_POST['key']]);
|
||||
|
||||
DB->prepare('UPDATE users SET type = "approved" WHERE id = :id')
|
||||
->execute([':id' => $_SESSION['id']]);
|
||||
|
||||
$_SESSION['type'] = 'approved';
|
||||
|
||||
insert('approval-keys', ['key' => bin2hex(random_bytes(16))]);
|
||||
|
||||
output(200, 'Compte approuvé.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Ce formulaire permet d'utiliser une clé d'approbation pour valider son compte. Une clé d'approbation est distribuée par l'administrataire sur demande.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="key">Clé d'approbation</label><br>
|
||||
<input required="" id="key" size="33" name="key" type="text" placeholder="27b81fbd8277b11ed1cf03d476cec503">
|
||||
<br>
|
||||
<input type="submit" value="Utiliser">
|
||||
</form>
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm(false)) {
|
||||
checkPasswordFormat($_POST['password']);
|
||||
|
||||
checkUsernameFormat($_POST['username']);
|
||||
|
||||
$username = hashUsername($_POST['username']);
|
||||
|
||||
if (usernameExists($username) !== true)
|
||||
output(403, 'Connexion impossible : ce compte n\'existe pas.');
|
||||
|
||||
$id = query('select', 'users', ['username' => $username], 'id')[0];
|
||||
|
||||
if (checkPassword($id, $_POST['password']) !== true)
|
||||
output(403, 'Connexion impossible : clé de passe invalide.');
|
||||
|
||||
$_SESSION['id'] = $id;
|
||||
$_SESSION['display-username'] = htmlspecialchars($_POST['username']);
|
||||
$_SESSION['type'] = query('select', 'users', ['id' => $id], 'type')[0];
|
||||
|
||||
if (outdatedPasswordHash($id))
|
||||
changePassword($id, $_POST['password']);
|
||||
|
||||
redir();
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>Pas de compte ? <a class="auth" href="register">En créer un</a></p>
|
||||
|
||||
<form method="post">
|
||||
<label for="username">Identifiant</label><br>
|
||||
<input required="" minlength="1" maxlength="1024" pattern="<?= USERNAME_REGEX ?>" id="username" name="username" type="text" placeholder="<?= PLACEHOLDER_USERNAME ?>">
|
||||
<br>
|
||||
|
||||
<label for="password">Clé de passe</label><br>
|
||||
<input required="" autocomplete="current-password" minlength="8" maxlength="1024" pattern="<?= PASSWORD_REGEX ?>" id="password" name="password" type="password" placeholder="<?= PLACEHOLDER_PASSWORD ?>">
|
||||
<br>
|
||||
|
||||
<input type="submit">
|
||||
</form>
|
|
@ -1,69 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm(false)) {
|
||||
checkPasswordFormat($_POST['password']);
|
||||
|
||||
checkUsernameFormat($_POST['username']);
|
||||
|
||||
$username = hashUsername($_POST['username']);
|
||||
|
||||
if (usernameExists($username) !== false)
|
||||
output(403, 'Ce nom de compte est déjà utilisé.');
|
||||
|
||||
rateLimit();
|
||||
|
||||
$id = hash('sha256', random_bytes(32));
|
||||
|
||||
insert('users', [
|
||||
'id' => $id,
|
||||
'username' => $username,
|
||||
'password' => hashPassword($_POST['password']),
|
||||
'registration_date' => date('Y-m-d H:i:s'),
|
||||
'bucket_tokens' => 0,
|
||||
'bucket_last_update' => 0,
|
||||
'type' => 'testing',
|
||||
]);
|
||||
|
||||
// Setup SFTP directory
|
||||
umask(0002);
|
||||
if (mkdir(CONF['ht']['ht_path'] . '/' . $id, 0775) !== true)
|
||||
output(500, 'Can\'t create user directory.');
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['chgrp_path'] . ' ' . CONF['ht']['sftpgo_group'] . ' ' . CONF['ht']['ht_path'] . '/' . $id . ' --no-dereference', result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t change user directory group.');
|
||||
|
||||
// Setup Tor config directory
|
||||
if (mkdir(CONF['ht']['tor_config_path'] . '/' . $id, 0755) !== true)
|
||||
output(500, 'Can\'t create Tor config directory.');
|
||||
|
||||
// Setup Tor keys directory
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['mkdir_path'] . ' --mode=0700 ' . CONF['ht']['tor_keys_path'] . '/' . $id, result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t create Tor keys directory.');
|
||||
|
||||
$_SESSION['id'] = $id;
|
||||
$_SESSION['display-username'] = htmlspecialchars($_POST['username']);
|
||||
$_SESSION['type'] = 'testing';
|
||||
|
||||
redir();
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>Déjà un compte ? <a class="auth" href="login">Se connecter</a></p>
|
||||
|
||||
<form method="post">
|
||||
|
||||
<label for="username">Identifiant</label>
|
||||
<br>
|
||||
<input id="username" minlength="1" maxlength="1024" pattern="<?= USERNAME_REGEX ?>" required="" name="username" type="text" placeholder="<?= PLACEHOLDER_USERNAME ?>"><br>
|
||||
|
||||
<details>
|
||||
<summary><label for="password">Clé de passe</label></summary>
|
||||
<p>Une clé de passe sécurisée est trop compliquée à deviner pour une attaque qui testerait automatiquement plein de clés de passe tout en connaissant d'autres informations et secrets sur vous.</p>
|
||||
<p>Minimum 8 caractères si elle contient minuscule, majuscule et chiffre, ou minimum 10 caractères sinon.</p>
|
||||
</details>
|
||||
<input autocomplete="new-password" id="password" minlength="8" maxlength="1024" pattern="<?= PASSWORD_REGEX ?>" required="" name="password" type="password" placeholder="<?= PLACEHOLDER_PASSWORD ?>">
|
||||
<br>
|
||||
<input type="submit">
|
||||
</form>
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
if (!isset($_POST['delete']))
|
||||
output(403, 'Il faut confirmer la suppression du compte');
|
||||
|
||||
foreach (query('select', 'registry', ['username' => $_SESSION['id']], 'domain') as $domain)
|
||||
regDeleteDomain($domain);
|
||||
|
||||
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
|
||||
nsDeleteZone($zone);
|
||||
|
||||
foreach (query('select', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'domain_type' => 'onion',
|
||||
'protocol' => 'http',
|
||||
], 'site_dir') as $dir)
|
||||
htDeleteSite($dir, domainType: 'onion', protocol: 'http');
|
||||
|
||||
foreach (query('select', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'domain_type' => 'dns',
|
||||
'protocol' => 'http',
|
||||
], 'site_dir') as $dir)
|
||||
htDeleteSite($dir, domainType: 'dns', protocol: 'http');
|
||||
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t remove Tor keys directory.');
|
||||
|
||||
removeDirectory(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id']);
|
||||
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['sftpgo_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t remove user\'s directory.');
|
||||
|
||||
query('delete', 'users', ['id' => $_SESSION['id']]);
|
||||
|
||||
logout();
|
||||
|
||||
output(200, 'Compte supprimé.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Cette action supprimera toutes les données appartenant à ce compte, y compris :
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>la possession et la réservation des domaines dans le registre</li>
|
||||
<li>les enregistrements DNS des zones hébergées sur le serveur de noms</li>
|
||||
<li>le contenu des sites</li>
|
||||
<li>les paires de clés des services Onion</li>
|
||||
</ul>
|
||||
|
||||
<form method="post">
|
||||
<input type="checkbox" name="delete" id="delete" required="">
|
||||
<label for="delete">Supprimer mon compte et toutes ses données</label>
|
||||
<br>
|
||||
<input type="submit">
|
||||
</form>
|
|
@ -1,30 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
checkUsernameFormat($_POST['new-username']);
|
||||
|
||||
$username = hashUsername($_POST['new-username']);
|
||||
|
||||
if (usernameExists($username) !== false)
|
||||
output(403, 'Ce nom de compte est déjà utilisé.');
|
||||
|
||||
DB->prepare('UPDATE users SET username = :username WHERE id = :id')
|
||||
->execute([':username' => $username, ':id' => $_SESSION['id']]);
|
||||
|
||||
$_SESSION['display-username'] = htmlspecialchars($_POST['new-username']);
|
||||
|
||||
output(200, 'Identifiant changé.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Vous pouvez ici changer l'identifiant permettant d'accéder à votre compte Niver.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="new-username">Nouvel identifiant</label><br>
|
||||
<input required="" autocomplete="new-username" minlength="1" maxlength="1024" pattern="<?= USERNAME_REGEX ?>" id="new-username" name="new-username" type="text" placeholder="<?= PLACEHOLDER_USERNAME ?>"><br>
|
||||
|
||||
<input type="submit">
|
||||
</form>
|
|
@ -1,105 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$_POST['domain'] = formatDomain($_POST['domain']);
|
||||
|
||||
if (dirsStatuses('dns', 'http')[$_POST['dir']] !== false)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
if (query('select', 'sites', ['domain' => $_POST['domain']], 'domain') !== [])
|
||||
output(403, 'Ce domaine existe déjà sur ce service.');
|
||||
|
||||
$remoteAaaaRecords = dns_get_record($_POST['domain'], DNS_AAAA);
|
||||
if (is_array($remoteAaaaRecords) !== true)
|
||||
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 <code>' . CONF['ht']['ipv6_address'] . '</code>.');
|
||||
|
||||
$remoteARecords = dns_get_record($_POST['domain'], DNS_A);
|
||||
if (is_array($remoteARecords) !== true)
|
||||
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 <code>' . CONF['ht']['ipv4_address'] . '</code>.');
|
||||
|
||||
$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('/^' . preg_quote(SERVER_NAME, '/') . '_domain-verification=([0-9a-f]{8})-([0-9a-f]{32})$/Dm', implode(LF, array_column($remoteTXTRecords, 'txt')), $matches) !== 1)
|
||||
output(403, 'Aucun enregistrement TXT au format correct trouvé.');
|
||||
|
||||
checkAuthToken($matches[1], $matches[2]);
|
||||
|
||||
rateLimit();
|
||||
|
||||
addSite($_SESSION['id'], $_POST['dir'], $_POST['domain'], 'dns', 'http');
|
||||
|
||||
exec('2>&1 ' . CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' certonly' . (($_SESSION['type'] === 'approved') ? '' : ' --test-cert') . ' --key-type rsa --rsa-key-size 3072 --webroot --webroot-path /srv/niver/acme --domain ' . $_POST['domain'], $output, $returnCode);
|
||||
if ($returnCode !== 0)
|
||||
output(500, 'Certbot failed to get a Let\'s Encrypt certificate.', $output);
|
||||
|
||||
$nginxConf = 'server {
|
||||
listen [' . CONF['ht']['ipv6_listen_address'] . ']:' . CONF['ht']['https_port'] . ' ssl http2;
|
||||
listen ' . CONF['ht']['ipv4_listen_address'] . ':' . CONF['ht']['https_port'] . ' ssl http2;
|
||||
server_name ' . $_POST['domain'] . ';
|
||||
root ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . ';
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/' . $_POST['domain'] . '/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/' . $_POST['domain'] . '/privkey.pem;
|
||||
|
||||
include inc/ht-tls.conf;
|
||||
}
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['nginx_config_path'] . '/' . $_POST['domain'] . '.conf', $nginxConf) === false)
|
||||
output(500, 'Failed to write Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
|
||||
output(200, 'Accès HTTP par domaine ajouté sur ce dossier !');
|
||||
}
|
||||
|
||||
$dirsStatuses = dirsStatuses('onion', 'http');
|
||||
|
||||
$proof = getAuthToken();
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Ajouter sur un dossier de site un accès <?= linkToDocs('http', 'HTTP') ?> par <?= linkToDocs('dns', 'DNS') ?> et <?= linkToDocs('tls', 'TLS') ?> <?= linkToDocs('ca', 'authentifié par <em>Let\'s Encrypt</em>') ?>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
La présence des enregistrements ci-après sera vérifiée lors du traitement de ce formulaire.
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt><code>AAAA</code></dt>
|
||||
<dd>
|
||||
<code><?= CONF['ht']['ipv6_address'] ?></code>
|
||||
</dd>
|
||||
<dt><code>A</code></dt>
|
||||
<dd>
|
||||
<code><?= CONF['ht']['ipv4_address'] ?></code>
|
||||
</dd>
|
||||
<dt><code>TXT</code></dt>
|
||||
<dd>
|
||||
<code><?= SERVER_NAME ?>_domain-verification=<?= $proof ?></code>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<form method="post">
|
||||
<label for="domain">Domaine sur lequel répondre</label><br>
|
||||
<input required="" placeholder="site.<?= PLACEHOLDER_DOMAIN ?>" 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
|
||||
foreach ($dirsStatuses as $dir => $alreadyEnabled)
|
||||
echo ' <option' . ($alreadyEnabled ? ' disabled=""' : '') . ' value="' . $dir . '">' . $dir . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Valider" type="submit">
|
||||
</form>
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
if (dirsStatuses('onion', 'http')[$_POST['dir']] !== false)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
rateLimit();
|
||||
|
||||
// Add Tor config
|
||||
$torConf = 'HiddenServiceDir ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . '/
|
||||
HiddenServicePort 80 [::1]:' . CONF['ht']['internal_onion_http_port'] . '
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], $torConf) === false)
|
||||
output(500, 'Failed to write new Tor configuration.');
|
||||
|
||||
// Reload Tor
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['tor_reload_cmd'], $output, $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Tor.');
|
||||
|
||||
// Get the address generated by Tor
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['cat_path'] . ' ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . '/hostname', $output);
|
||||
$onion = $output[0];
|
||||
if (preg_match('/^[0-9a-z]{56}\.onion$/D', $onion) !== 1)
|
||||
output(500, 'No onion address found.');
|
||||
|
||||
// Store it in the database
|
||||
addSite($_SESSION['id'], $_POST['dir'], $onion, 'onion', 'http');
|
||||
|
||||
// Add Nginx config
|
||||
$nginxConf = 'server {
|
||||
listen [::1]:' . CONF['ht']['internal_onion_http_port'] . ';
|
||||
server_name ' . $onion . ';
|
||||
root ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . ';
|
||||
|
||||
include inc/ht-onion.conf;
|
||||
}
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['nginx_config_path'] . '/' . $onion . '.conf', $nginxConf) === false)
|
||||
output(500, 'Failed to write Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
|
||||
// Tell the user their site address
|
||||
output(200, 'L\'adresse de votre service Onion HTTP est : <a href="http://' . $onion . '/"><code>http://' . $onion . '/</code></a>');
|
||||
}
|
||||
|
||||
$dirsStatuses = dirsStatuses('onion', 'http');
|
||||
|
||||
?>
|
||||
|
||||
<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
|
||||
foreach ($dirsStatuses as $dir => $alreadyEnabled)
|
||||
echo ' <option' . ($alreadyEnabled ? ' disabled=""' : '') . ' value="' . $dir . '">' . $dir . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Valider" type="submit">
|
||||
</form>
|
|
@ -1,96 +0,0 @@
|
|||
|
||||
<form method="post">
|
||||
<input type="radio" name="print" id="table" value="table" checked="">
|
||||
<label for="table">Tableau de mes enregistrements</label>
|
||||
<br>
|
||||
<input type="radio" name="print" id="ds" value="ds">
|
||||
<label for="ds">Enregistrement DS</label>
|
||||
<br>
|
||||
<input type="radio" name="print" id="raw" value="raw">
|
||||
<label for="raw">Fichier de zone brut</label>
|
||||
<br>
|
||||
<label for="zone">Zone</label>
|
||||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach (nsListUserZones($_SESSION['id']) as $zone)
|
||||
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Afficher" type="submit">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
|
||||
$zoneContent = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
|
||||
if ($zoneContent === false)
|
||||
output(500, 'Unable to read zone file.');
|
||||
|
||||
if ($_POST['print'] === 'raw') {
|
||||
echo '<pre>' . htmlspecialchars($zoneContent) . '</pre>';
|
||||
output(200);
|
||||
}
|
||||
|
||||
if ($_POST['print'] === 'table') { ?>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Domaine</th>
|
||||
<th>TTL</th>
|
||||
<th>Type</th>
|
||||
<th>Contenu</th>
|
||||
</tr>
|
||||
<?php
|
||||
foreach(explode(LF, $zoneContent) as $zoneLine) {
|
||||
if (str_starts_with($zoneLine, ';')) continue; // Ignore comments
|
||||
if (empty($zoneLine)) continue;
|
||||
$elements = preg_split('/[\t ]+/', $zoneLine, 4);
|
||||
if (!in_array($elements[2], ALLOWED_TYPES, true)) continue; // Ignore records generated by Knot
|
||||
echo ' <tr>';
|
||||
foreach ($elements as $element)
|
||||
echo ' <td><code>' . htmlspecialchars($element) . '</code></td>';
|
||||
echo ' </tr>';
|
||||
}
|
||||
echo '</table>';
|
||||
}
|
||||
|
||||
if ($_POST['print'] === 'ds') {
|
||||
|
||||
$found = preg_match('/^' . preg_quote($_POST['zone'], '/') . '[\t ]+0[\t ]+CDS[\t ]+(?<tag>[0-9]{1,5})[\t ]+(?<algo>[0-9]{1,2})[\t ]+(?<digest_type>[0-9])[\t ]+(?<digest>[0-9A-F]{64})$/Dm', $zoneContent, $matches);
|
||||
if ($found !== 1)
|
||||
output(500, 'Unable to get public key record from zone file.');
|
||||
|
||||
?>
|
||||
|
||||
<dl>
|
||||
<dt>Zone</dt>
|
||||
<dd>
|
||||
<code><?= $_POST['zone'] ?></code>
|
||||
</dd>
|
||||
<dt>Tag</dt>
|
||||
<dd>
|
||||
<code><?= $matches['tag'] ?></code>
|
||||
</dd>
|
||||
<dt>Algorithme</dt>
|
||||
<dd>
|
||||
<code><?= $matches['algo'] ?></code><?php if ($matches['algo'] === '15') echo ' (Ed25519)'; ?>
|
||||
</dd>
|
||||
<dt>Type de condensat</dt>
|
||||
<dd>
|
||||
<code><?= $matches['digest_type'] ?></code><?php if ($matches['digest_type'] === '2') echo ' (SHA-256)'; ?>
|
||||
</dd>
|
||||
<dt>Condensat</dt>
|
||||
<dd>
|
||||
<code><?= $matches['digest'] ?></code>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<?php
|
||||
output(200);
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$_POST['domain'] = formatAbsoluteDomain($_POST['domain']);
|
||||
|
||||
if (query('select', 'zones', ['zone' => $_POST['domain']], 'zone') !== [])
|
||||
output(403, 'Cette zone existe déjà sur ce service.');
|
||||
|
||||
exec(CONF['dns']['kdig_path'] . ' ' . ltrim(strstr($_POST['domain'], '.'), '.') . ' NS +short', $parentAuthoritatives);
|
||||
if ($parentAuthoritatives === [])
|
||||
output(403, 'Serveurs de noms de la zone parente introuvables');
|
||||
foreach ($parentAuthoritatives as $parentAuthoritative)
|
||||
checkAbsoluteDomainFormat($parentAuthoritative);
|
||||
|
||||
exec(CONF['dns']['kdig_path'] . ' ' . $_POST['domain'] . ' NS @' . $parentAuthoritatives[0] . ' +noidn', $results);
|
||||
if (preg_match('/^' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+(?<salt>[0-9a-f]{8})-(?<hash>[0-9a-f]{32})\._domain-verification\.' . preg_quote(SERVER_NAME, '/') . '\.$/Dm', implode(LF, $results), $matches) !== 1)
|
||||
output(403, 'Enregistrement d\'authentification introuvable');
|
||||
|
||||
checkAuthToken($matches['salt'], $matches['hash']);
|
||||
|
||||
rateLimit();
|
||||
|
||||
insert('zones', [
|
||||
'zone' => $_POST['domain'],
|
||||
'username' => $_SESSION['id'],
|
||||
]);
|
||||
|
||||
$knotZonePath = CONF['ns']['knot_zones_path'] . '/' . $_POST['domain'] . 'zone';
|
||||
$knotZone = implode(' ', [
|
||||
$_POST['domain'],
|
||||
SOA_VALUES['ttl'],
|
||||
'SOA',
|
||||
CONF['ns']['servers'][0],
|
||||
SOA_VALUES['email'],
|
||||
1,
|
||||
SOA_VALUES['refresh'],
|
||||
SOA_VALUES['retry'],
|
||||
SOA_VALUES['expire'],
|
||||
SOA_VALUES['negative'],
|
||||
]) . LF;
|
||||
foreach (CONF['ns']['servers'] as $server)
|
||||
$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . LF;
|
||||
if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true)
|
||||
output(500, 'Failed to write new zone file.');
|
||||
if (chmod($knotZonePath, 0660) !== true)
|
||||
output(500, 'Failed to chmod new zone file.');
|
||||
|
||||
knotcConfExec([
|
||||
"set 'zone[" . $_POST['domain'] . "]'",
|
||||
"set 'zone[" . $_POST['domain'] . "].template' 'niver'",
|
||||
]);
|
||||
|
||||
output(200, 'La zone a été créée.');
|
||||
}
|
||||
|
||||
$proof = getAuthToken();
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Pour prouver que vous possédez bien ce domaine, il doit posséder un <?= linkToDocs('ns-record', 'enregistrement NS') ?> égal à <code><?= $proof ?>._domain-verification.<?= SERVER_NAME ?>.</code> lors du traitement de ce formulaire.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
La zone sera servie par ces serveurs de noms :
|
||||
<ul>
|
||||
<?php
|
||||
foreach (CONF['ns']['servers'] as $server)
|
||||
echo ' <li><code>' . $server . '</code></li>';
|
||||
?>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="domain">Domaine</label><br>
|
||||
<input required="" placeholder="domain.<?= PLACEHOLDER_DOMAIN ?>." id="domain" name="domain" type="text"><br>
|
||||
<input value="Ajouter" type="submit">
|
||||
</form>
|
|
@ -1,25 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
|
||||
nsDeleteZone($_POST['zone']);
|
||||
|
||||
output(200, 'La zone a été supprimée.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<form method="post">
|
||||
<label for="zone">Zone</label>
|
||||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach (nsListUserZones($_SESSION['id']) as $zone)
|
||||
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Supprimer toutes les données liées à cette zone" type="submit">
|
||||
</form>
|
|
@ -1,49 +0,0 @@
|
|||
<form method="post">
|
||||
<label for="domain">Domaine</label>
|
||||
<select required="" name="domain" id="domain">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach (regListUserDomains($_SESSION['id']) as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Afficher" type="submit">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
regCheckDomainPossession($_POST['domain']);
|
||||
|
||||
$zoneContent = file_get_contents(CONF['reg']['registry_file']);
|
||||
if ($zoneContent === false)
|
||||
output(500, 'Unable to read registry file.');
|
||||
|
||||
?>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Domaine</th>
|
||||
<th>TTL</th>
|
||||
<th>Type</th>
|
||||
<th>Contenu</th>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
foreach(explode(LF, $zoneContent) as $zoneLine) {
|
||||
if (str_starts_with($zoneLine, ';')) continue; // Ignore comments
|
||||
if (empty($zoneLine)) continue;
|
||||
$elements = preg_split('/[\t ]+/', $zoneLine, 4);
|
||||
if (!str_ends_with($elements[0], $_POST['domain'])) continue; // Ignore records for other domains
|
||||
if (!in_array($elements[2], ['A', 'AAAA', 'NS', 'DS'], true)) continue; // Ignore records generated by Knot
|
||||
echo ' <tr>' . LF;
|
||||
foreach ($elements as $element)
|
||||
echo ' <td><code>' . htmlspecialchars($element) . '</code></td>' . LF;
|
||||
echo ' </tr>' . LF;
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
|
||||
output(200);
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
if (preg_match('/' . SUBDOMAIN_REGEX . '/D', $_POST['subdomain']) !== 1)
|
||||
output(403, 'Le nom de domaine doit être composé uniquement d\'entre 4 et 63 lettres minuscules ou chiffre (a-z et 0-9)');
|
||||
|
||||
$domain = formatAbsoluteDomain($_POST['subdomain'] . '.' . CONF['reg']['registry']);
|
||||
|
||||
if (query('select', 'registry', ['domain' => $domain], 'domain') !== [])
|
||||
output(403, 'Ce domaine n\'est pas disponible à l\'enregistrement. Il est déjà enregistré.');
|
||||
|
||||
if (in_array($_POST['subdomain'], explode(LF, file_get_contents(CONF['common']['root_path'] . '/pages/reg/reserved.txt'))))
|
||||
output(403, 'Ce domaine n\'est pas disponible à l\'enregistrement. Il est réservé.');
|
||||
|
||||
rateLimit();
|
||||
|
||||
insert('registry', [
|
||||
'domain' => $domain,
|
||||
'username' => $_SESSION['id'],
|
||||
'last_renewal' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
output(200, 'Domaine ajouté au registre.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Enregistrer un nouveau domaine sur son compte. Ce domaine doit être composé uniquement d'au moins 4 lettres latines non accentuées (a-z).
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="subdomain">Sous-domaine</label>
|
||||
<br>
|
||||
<code><input id="subdomain" pattern="<?= SUBDOMAIN_REGEX ?>" required="" placeholder="niver" name="subdomain" type="text">.<?= CONF['reg']['registry'] ?></code>
|
||||
<br>
|
||||
<input value="Enregistrer" type="submit">
|
||||
</form>
|
|
@ -1,44 +0,0 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
if (preg_match('/' . SUBDOMAIN_REGEX . '/D', $_POST['domain']) !== 1)
|
||||
output(403, 'Le nom de domaine semble incorrect');
|
||||
|
||||
$domain = $_POST['domain'] . '.' . CONF['reg']['registry'];
|
||||
|
||||
if (query('select', 'registry', ['username' => $_SESSION['id'], 'domain' => $domain], 'domain') !== [])
|
||||
output(403, 'Le compte présent possède déjà ce domaine.');
|
||||
|
||||
exec(CONF['dns']['kdig_path'] . ' ' . $domain . ' NS @' . CONF['reg']['address'] . ' +noidn', $results);
|
||||
if (preg_match('/^' . preg_quote($domain, '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+(?<salt>[0-9a-f]{8})-(?<hash>[0-9a-f]{32})\._transfer-verification\.' . preg_quote(SERVER_NAME, '/') . '\.$/Dm', implode(LF, $results), $matches) !== 1)
|
||||
output(403, 'Enregistrement d\'authentification introuvable');
|
||||
|
||||
checkAuthToken($matches['salt'], $matches['hash']);
|
||||
|
||||
DB->prepare('UPDATE registry SET username = :username WHERE domain = :domain')
|
||||
->execute([':username' => $_SESSION['id'], ':domain' => $domain]);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], [
|
||||
$domain,
|
||||
'NS',
|
||||
$matches['salt'] . '-' . $matches['hash'] . '._transfer-verification.' . SERVER_NAME . '.'
|
||||
], 'delete');
|
||||
|
||||
output(200, 'Le domaine a été transféré vers le compte présent, l\'enregistrement d\'authentification a été automatiquement retiré.');
|
||||
}
|
||||
|
||||
$proof = getAuthToken();
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Pour prouver que vous êtes autorisé à recevoir le domaine par san possessaire actuele, ledit domaine doit posséder un <?= linkToDocs('ns-record', 'enregistrement NS') ?> égal à <code><?= $proof ?>._transfer-verification.<?= SERVER_NAME ?>.</code> lors du traitement de ce formulaire. Cet enregistrement sera automatiquement retiré une fois validé.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="subdomain">Sous-domaine à recevoir</label>
|
||||
<br>
|
||||
<code><input required="" placeholder="subdomain" id="subdomain" name="subdomain" type="text">.<?= CONF['reg']['registry'] ?></code>
|
||||
<br>
|
||||
<input value="Recevoir ce domaine" type="submit">
|
||||
</form>
|
18
pg-act/auth/approval.php
Normal file
18
pg-act/auth/approval.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
if ($_SESSION['type'] !== 'testing')
|
||||
output(403, 'Approbation impossible : votre compte est déjà approuvé.');
|
||||
|
||||
if (isset(query('select', 'approval-keys', ['key' => $_POST['key']], 'key')[0]) !== true)
|
||||
output(403, 'Approbation impossible : cette clé d\'approbation n\'est pas disponible. Elle a été mal saisie, a expiré ou a déjà été utilisée pour un autre compte.');
|
||||
|
||||
query('delete', 'approval-keys', ['key' => $_POST['key']]);
|
||||
|
||||
DB->prepare('UPDATE users SET type = "approved" WHERE id = :id')
|
||||
->execute([':id' => $_SESSION['id']]);
|
||||
|
||||
$_SESSION['type'] = 'approved';
|
||||
|
||||
insert('approval-keys', ['key' => bin2hex(random_bytes(16))]);
|
||||
|
||||
output(200, 'Compte approuvé.');
|
28
pg-act/auth/login.php
Normal file
28
pg-act/auth/login.php
Normal file
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
checkPasswordFormat($_POST['password']);
|
||||
|
||||
checkUsernameFormat($_POST['username']);
|
||||
|
||||
$username = hashUsername($_POST['username']);
|
||||
|
||||
if (usernameExists($username) !== true)
|
||||
output(403, 'Connexion impossible : ce compte n\'existe pas.');
|
||||
|
||||
$id = query('select', 'users', ['username' => $username], 'id')[0];
|
||||
|
||||
if (checkPassword($id, $_POST['password']) !== true)
|
||||
output(403, 'Connexion impossible : clé de passe invalide.');
|
||||
|
||||
if (outdatedPasswordHash($id))
|
||||
changePassword($id, $_POST['password']);
|
||||
|
||||
stopSession();
|
||||
startSession();
|
||||
|
||||
$_SESSION['id'] = $id;
|
||||
$_SESSION['display-username'] = htmlspecialchars($_POST['username']);
|
||||
$_SESSION['type'] = query('select', 'users', ['id' => $id], 'type')[0];
|
||||
|
||||
redir();
|
||||
|
10
pg-act/auth/password.php
Normal file
10
pg-act/auth/password.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
checkPasswordFormat($_POST['new-password']);
|
||||
|
||||
if (checkPassword($_SESSION['id'], $_POST['current-password']) !== true)
|
||||
output(403, 'Changement impossible : clé de passe invalide.');
|
||||
|
||||
changePassword($_SESSION['id'], $_POST['new-password']);
|
||||
|
||||
output(200, 'Clé de passe changée.');
|
50
pg-act/auth/register.php
Normal file
50
pg-act/auth/register.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
checkPasswordFormat($_POST['password']);
|
||||
|
||||
checkUsernameFormat($_POST['username']);
|
||||
|
||||
$username = hashUsername($_POST['username']);
|
||||
|
||||
if (usernameExists($username) !== false)
|
||||
output(403, 'Ce nom de compte est déjà utilisé.');
|
||||
|
||||
rateLimit();
|
||||
|
||||
$id = hash('sha256', random_bytes(32));
|
||||
|
||||
insert('users', [
|
||||
'id' => $id,
|
||||
'username' => $username,
|
||||
'password' => hashPassword($_POST['password']),
|
||||
'registration_date' => date('Y-m-d H:i:s'),
|
||||
'bucket_tokens' => 0,
|
||||
'bucket_last_update' => 0,
|
||||
'type' => 'testing',
|
||||
]);
|
||||
|
||||
// Setup SFTP directory
|
||||
umask(0002);
|
||||
if (mkdir(CONF['ht']['ht_path'] . '/' . $id, 0775) !== true)
|
||||
output(500, 'Can\'t create user directory.');
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['chgrp_path'] . ' ' . CONF['ht']['sftpgo_group'] . ' ' . CONF['ht']['ht_path'] . '/' . $id . ' --no-dereference', result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t change user directory group.');
|
||||
|
||||
// Setup Tor config directory
|
||||
if (mkdir(CONF['ht']['tor_config_path'] . '/' . $id, 0755) !== true)
|
||||
output(500, 'Can\'t create Tor config directory.');
|
||||
|
||||
// Setup Tor keys directory
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['mkdir_path'] . ' --mode=0700 ' . CONF['ht']['tor_keys_path'] . '/' . $id, result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t create Tor keys directory.');
|
||||
|
||||
stopSession();
|
||||
startSession();
|
||||
|
||||
$_SESSION['id'] = $id;
|
||||
$_SESSION['display-username'] = htmlspecialchars($_POST['username']);
|
||||
$_SESSION['type'] = 'testing';
|
||||
|
||||
redir();
|
40
pg-act/auth/unregister.php
Normal file
40
pg-act/auth/unregister.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
if (!isset($_POST['delete']))
|
||||
output(403, 'Il faut confirmer la suppression du compte');
|
||||
|
||||
foreach (query('select', 'registry', ['username' => $_SESSION['id']], 'domain') as $domain)
|
||||
regDeleteDomain($domain);
|
||||
|
||||
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
|
||||
nsDeleteZone($zone);
|
||||
|
||||
foreach (query('select', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'domain_type' => 'onion',
|
||||
'protocol' => 'http',
|
||||
], 'site_dir') as $dir)
|
||||
htDeleteSite($dir, domainType: 'onion', protocol: 'http');
|
||||
|
||||
foreach (query('select', 'sites', [
|
||||
'username' => $_SESSION['id'],
|
||||
'domain_type' => 'dns',
|
||||
'protocol' => 'http',
|
||||
], 'site_dir') as $dir)
|
||||
htDeleteSite($dir, domainType: 'dns', protocol: 'http');
|
||||
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t remove Tor keys directory.');
|
||||
|
||||
removeDirectory(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id']);
|
||||
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['sftpgo_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t remove user\'s directory.');
|
||||
|
||||
query('delete', 'users', ['id' => $_SESSION['id']]);
|
||||
|
||||
logout();
|
||||
|
||||
output(200, 'Compte supprimé.');
|
15
pg-act/auth/username.php
Normal file
15
pg-act/auth/username.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
checkUsernameFormat($_POST['new-username']);
|
||||
|
||||
$username = hashUsername($_POST['new-username']);
|
||||
|
||||
if (usernameExists($username) !== false)
|
||||
output(403, 'Ce nom de compte est déjà utilisé.');
|
||||
|
||||
DB->prepare('UPDATE users SET username = :username WHERE id = :id')
|
||||
->execute([':username' => $username, ':id' => $_SESSION['id']]);
|
||||
|
||||
$_SESSION['display-username'] = htmlspecialchars($_POST['new-username']);
|
||||
|
||||
output(200, 'Identifiant changé.');
|
59
pg-act/ht/add-http-dns.php
Normal file
59
pg-act/ht/add-http-dns.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
$_POST['domain'] = formatDomain($_POST['domain']);
|
||||
|
||||
if (dirsStatuses('dns', 'http')[$_POST['dir']] !== false)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
if (query('select', 'sites', ['domain' => $_POST['domain']], 'domain') !== [])
|
||||
output(403, 'Ce domaine existe déjà sur ce service.');
|
||||
|
||||
$remoteAaaaRecords = dns_get_record($_POST['domain'], DNS_AAAA);
|
||||
if (is_array($remoteAaaaRecords) !== true)
|
||||
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 <code>' . CONF['ht']['ipv6_address'] . '</code>.');
|
||||
|
||||
$remoteARecords = dns_get_record($_POST['domain'], DNS_A);
|
||||
if (is_array($remoteARecords) !== true)
|
||||
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 <code>' . CONF['ht']['ipv4_address'] . '</code>.');
|
||||
|
||||
$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('/^' . preg_quote(SERVER_NAME, '/') . '_domain-verification=([0-9a-f]{8})-([0-9a-f]{32})$/Dm', implode(LF, array_column($remoteTXTRecords, 'txt')), $matches) !== 1)
|
||||
output(403, 'Aucun enregistrement TXT au format correct trouvé.');
|
||||
|
||||
checkAuthToken($matches[1], $matches[2]);
|
||||
|
||||
rateLimit();
|
||||
|
||||
addSite($_SESSION['id'], $_POST['dir'], $_POST['domain'], 'dns', 'http');
|
||||
|
||||
exec('2>&1 ' . CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' certonly' . (($_SESSION['type'] === 'approved') ? '' : ' --test-cert') . ' --key-type rsa --rsa-key-size 3072 --webroot --webroot-path /srv/niver/acme --domain ' . $_POST['domain'], $output, $returnCode);
|
||||
if ($returnCode !== 0)
|
||||
output(500, 'Certbot failed to get a Let\'s Encrypt certificate.', $output);
|
||||
|
||||
$nginxConf = 'server {
|
||||
listen [' . CONF['ht']['ipv6_listen_address'] . ']:' . CONF['ht']['https_port'] . ' ssl http2;
|
||||
listen ' . CONF['ht']['ipv4_listen_address'] . ':' . CONF['ht']['https_port'] . ' ssl http2;
|
||||
server_name ' . $_POST['domain'] . ';
|
||||
root ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . ';
|
||||
|
||||
ssl_certificate /etc/letsencrypt/live/' . $_POST['domain'] . '/fullchain.pem;
|
||||
ssl_certificate_key /etc/letsencrypt/live/' . $_POST['domain'] . '/privkey.pem;
|
||||
|
||||
include inc/ht-tls.conf;
|
||||
}
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['nginx_config_path'] . '/' . $_POST['domain'] . '.conf', $nginxConf) === false)
|
||||
output(500, 'Failed to write Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
|
||||
output(200, 'Accès HTTP par domaine ajouté sur ce dossier !');
|
47
pg-act/ht/add-http-onion.php
Normal file
47
pg-act/ht/add-http-onion.php
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
|
||||
if (dirsStatuses('onion', 'http')[$_POST['dir']] !== false)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
rateLimit();
|
||||
|
||||
// Add Tor config
|
||||
$torConf = 'HiddenServiceDir ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . '/
|
||||
HiddenServicePort 80 [::1]:' . CONF['ht']['internal_onion_http_port'] . '
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], $torConf) === false)
|
||||
output(500, 'Failed to write new Tor configuration.');
|
||||
|
||||
// Reload Tor
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['tor_reload_cmd'], $output, $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Tor.');
|
||||
|
||||
// Get the address generated by Tor
|
||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['cat_path'] . ' ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . '/hostname', $output);
|
||||
$onion = $output[0];
|
||||
if (preg_match('/^[0-9a-z]{56}\.onion$/D', $onion) !== 1)
|
||||
output(500, 'No onion address found.');
|
||||
|
||||
// Store it in the database
|
||||
addSite($_SESSION['id'], $_POST['dir'], $onion, 'onion', 'http');
|
||||
|
||||
// Add Nginx config
|
||||
$nginxConf = 'server {
|
||||
listen [::1]:' . CONF['ht']['internal_onion_http_port'] . ';
|
||||
server_name ' . $onion . ';
|
||||
root ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'] . ';
|
||||
|
||||
include inc/ht-onion.conf;
|
||||
}
|
||||
';
|
||||
if (file_put_contents(CONF['ht']['nginx_config_path'] . '/' . $onion . '.conf', $nginxConf) === false)
|
||||
output(500, 'Failed to write Nginx configuration.');
|
||||
|
||||
// Reload Nginx
|
||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code: $code);
|
||||
if ($code !== 0)
|
||||
output(500, 'Failed to reload Nginx.');
|
||||
|
||||
// Tell the user their site address
|
||||
output(200, 'L\'adresse de votre service Onion HTTP est : <a href="http://' . $onion . '/"><code>http://' . $onion . '/</code></a>');
|
8
pg-act/ht/del-http-dns.php
Normal file
8
pg-act/ht/del-http-dns.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
if (dirsStatuses('dns', 'http')[$_POST['dir']] !== true)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
htDeleteSite($_POST['dir'], domainType: 'dns', protocol: 'http');
|
||||
|
||||
output(200, 'Accès retiré.');
|
8
pg-act/ht/del-http-onion.php
Normal file
8
pg-act/ht/del-http-onion.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
if (dirsStatuses('onion', 'http')[$_POST['dir']] !== true)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
htDeleteSite($_POST['dir'], domainType: 'onion', protocol: 'http');
|
||||
|
||||
output(200, 'Accès retiré.');
|
23
pg-act/ns/caa.php
Normal file
23
pg-act/ns/caa.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['flag'] >= 0 AND $_POST['flag'] <= 255))
|
||||
output(403, 'Wrong value for <code>flag</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-z]{1,127}$/D', $_POST['tag'])))
|
||||
output(403, 'Wrong value for <code>tag</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-z0-9.-]{1,255}$/D', $_POST['value'])))
|
||||
output(403, 'Wrong value for <code>value</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'CAA',
|
||||
$_POST['flag'],
|
||||
$_POST['tag'],
|
||||
$_POST['value']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
14
pg-act/ns/cname.php
Normal file
14
pg-act/ns/cname.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$_POST['cname'] = formatAbsoluteDomain($_POST['cname']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'CNAME',
|
||||
$_POST['cname']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
14
pg-act/ns/dname.php
Normal file
14
pg-act/ns/dname.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$_POST['dname'] = formatAbsoluteDomain($_POST['dname']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'DNAME',
|
||||
$_POST['dname']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
|
@ -1,7 +1,8 @@
|
|||
<?php
|
||||
|
||||
if (processForm() AND isset($_POST['zone-content'])) { // Update zone
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
|
||||
if (isset($_POST['zone-content'])) { // Update zone
|
||||
|
||||
// Get current SOA record
|
||||
$current_zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
|
||||
|
@ -58,85 +59,22 @@ if (processForm() AND isset($_POST['zone-content'])) { // Update zone
|
|||
output(500, 'Failed to thaw zone file.', $output);
|
||||
|
||||
usleep(1000000);
|
||||
|
||||
output(200, 'La zone a été mise à jour.');
|
||||
}
|
||||
|
||||
?>
|
||||
// Display zone
|
||||
|
||||
<form method="post">
|
||||
<label for="zone">Zone à modifier</label>
|
||||
<br>
|
||||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach (nsListUserZones($_SESSION['id']) as $zone)
|
||||
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input type="submit" value="Afficher">
|
||||
</form>
|
||||
$zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
|
||||
if ($zone_content === false)
|
||||
output(500, 'Unable to read zone file.');
|
||||
|
||||
<?php
|
||||
|
||||
if (processForm()) { // Display zone
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
|
||||
$zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
|
||||
if ($zone_content === false)
|
||||
output(500, 'Unable to read zone file.');
|
||||
|
||||
$displayed_zone_content = '';
|
||||
foreach(explode(LF, $zone_content) as $zone_line) {
|
||||
if (empty($zone_line) OR str_starts_with($zone_line, ';'))
|
||||
$data['zone_content'] = '';
|
||||
foreach(explode(LF, $zone_content) as $zone_line) {
|
||||
if (empty($zone_line) OR str_starts_with($zone_line, ';'))
|
||||
continue;
|
||||
if (preg_match('/^(?:(?:[a-z0-9_-]{1,63}\.){1,127})?' . preg_quote($_POST['zone'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?<type>[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) {
|
||||
if (in_array($matches['type'], ALLOWED_TYPES, true) !== true)
|
||||
continue;
|
||||
if (preg_match('/^(?:(?:[a-z0-9_-]{1,63}\.){1,127})?' . preg_quote($_POST['zone'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?<type>[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) {
|
||||
if (in_array($matches['type'], ALLOWED_TYPES, true) !== true)
|
||||
continue;
|
||||
$displayed_zone_content .= $zone_line . LF;
|
||||
}
|
||||
$data['zone_content'] .= $zone_line . LF;
|
||||
}
|
||||
$displayed_zone_content .= LF;
|
||||
|
||||
?>
|
||||
<form method="post">
|
||||
<input type="hidden" name="zone" value="<?= $_POST['zone'] ?>">
|
||||
|
||||
<label for="zone-content">Nouveau contenu de la zone <code><strong><?= $_POST['zone'] ?></strong></code></label>
|
||||
<textarea id="zone-content" name="zone-content" wrap="off" rows="<?= substr_count($displayed_zone_content, LF) + 1 ?>"><?= htmlspecialchars($displayed_zone_content) ?></textarea>
|
||||
<br>
|
||||
<input type="submit" value="Remplacer">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
global $final_message;
|
||||
displayFinalMessage();
|
||||
|
||||
?>
|
||||
|
||||
<h2>Valeurs par défaut</h2>
|
||||
|
||||
<p>Si le TTL est omis, il sera définit à <code><time datetime="PT<?= DEFAULT_TTL ?>S"><?= DEFAULT_TTL ?></time></code> secondes.</p>
|
||||
|
||||
<p>La précision de la classe (<code>IN</code>) est facultative.</p>
|
||||
|
||||
<h2>Valeurs autorisées</h2>
|
||||
|
||||
<p>La zone n'est pas autorisée à dépasser <?= ZONE_MAX_CHARACTERS ?> caractères.</p>
|
||||
|
||||
<p>Les TTLs ne sont autorisés qu'entre <code><time datetime="PT<?= MIN_TTL ?>S"><?= MIN_TTL ?></time></code> et <code><time datetime="PT<?= MAX_TTL ?>S"><?= MAX_TTL ?></time></code> secondes.</p>
|
||||
|
||||
<p>Les seuls types dont l'édition est autorisée sont :</p>
|
||||
|
||||
<ul>
|
||||
<?php
|
||||
foreach (ALLOWED_TYPES as $allowed_type)
|
||||
echo ' <li><code>' . $allowed_type . '</code></li>';
|
||||
|
||||
?>
|
||||
</ul>
|
||||
$data['zone_content'] .= LF;
|
14
pg-act/ns/ip.php
Normal file
14
pg-act/ns/ip.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$record = checkIpFormat($_POST['ip']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
$record,
|
||||
$_POST['ip']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
70
pg-act/ns/loc.php
Normal file
70
pg-act/ns/loc.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (empty($_POST['lat-min']))
|
||||
$_POST['lat-min'] = 0;
|
||||
if (empty($_POST['lat-sec']))
|
||||
$_POST['lat-sec'] = 0;
|
||||
if (empty($_POST['lon-min']))
|
||||
$_POST['lon-min'] = 0;
|
||||
if (empty($_POST['lon-sec']))
|
||||
$_POST['lon-sec'] = 0;
|
||||
if (empty($_POST['size']))
|
||||
$_POST['size'] = 1;
|
||||
if (empty($_POST['hp']))
|
||||
$_POST['hp'] = 10000;
|
||||
if (empty($_POST['vp']))
|
||||
$_POST['vp'] = 10;
|
||||
|
||||
if (!($_POST['lat-deg'] >= 0 AND $_POST['lat-deg'] <= 90))
|
||||
output(403, 'Wrong value for <code>lat-deg</code>.');
|
||||
if (!($_POST['lat-min'] >= 0 AND $_POST['lat-min'] <= 59))
|
||||
output(403, 'Wrong value for <code>lat-min</code>.');
|
||||
if (!($_POST['lat-sec'] >= 0 AND $_POST['lat-sec'] <= 59.999))
|
||||
output(403, 'Wrong value for <code>lat-sec</code>.');
|
||||
|
||||
if ($_POST['lat-dir'] !== 'N' AND $_POST['lat-dir'] !== 'S')
|
||||
output(403, 'Wrong value for <code>lat-dir</code>.');
|
||||
|
||||
if (!($_POST['lon-deg'] >= 0 AND $_POST['lon-deg'] <= 180))
|
||||
output(403, 'Wrong value for <code>lon-deg</code>.');
|
||||
if (!($_POST['lon-min'] >= 0 AND $_POST['lon-min'] <= 59))
|
||||
output(403, 'Wrong value for <code>lon-min</code>.');
|
||||
if (!($_POST['lon-sec'] >= 0 AND $_POST['lon-sec'] <= 59.999))
|
||||
output(403, 'Wrong value for <code>lon-sec</code>.');
|
||||
|
||||
if ($_POST['lon-dir'] !== 'E' AND $_POST['lon-dir'] !== 'W')
|
||||
output(403, 'Wrong value for <code>lon-dir</code>.');
|
||||
|
||||
if (!($_POST['alt'] >= -100000 AND $_POST['alt'] <= 42849672.95))
|
||||
output(403, 'Wrong value for <code>alt</code>.');
|
||||
|
||||
if (!($_POST['size'] >= 0 AND $_POST['size'] <= 90000000))
|
||||
output(403, 'Wrong value for <code>size</code>.');
|
||||
|
||||
if (!($_POST['hp'] >= 0 AND $_POST['hp'] <= 90000000))
|
||||
output(403, 'Wrong value for <code>hp</code>.');
|
||||
|
||||
if (!($_POST['vp'] >= 0 AND $_POST['vp'] <= 90000000))
|
||||
output(403, 'Wrong value for <code>vp</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'LOC',
|
||||
$_POST['lat-deg'],
|
||||
$_POST['lat-min'],
|
||||
$_POST['lat-sec'],
|
||||
$_POST['lat-dir'],
|
||||
$_POST['lon-deg'],
|
||||
$_POST['lon-min'],
|
||||
$_POST['lon-sec'],
|
||||
$_POST['lon-dir'],
|
||||
$_POST['alt'] . 'm',
|
||||
$_POST['size'] . 'm',
|
||||
$_POST['hp'] . 'm',
|
||||
$_POST['vp'] . 'm',
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
18
pg-act/ns/mx.php
Normal file
18
pg-act/ns/mx.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['priority'] >= 0 AND $_POST['priority'] <= 255))
|
||||
output(403, 'Wrong value for <code>priority</code>.');
|
||||
|
||||
$_POST['host'] = formatAbsoluteDomain($_POST['host']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'MX',
|
||||
$_POST['priority'],
|
||||
$_POST['host']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
14
pg-act/ns/ns.php
Normal file
14
pg-act/ns/ns.php
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$_POST['ns'] = formatAbsoluteDomain($_POST['ns']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'NS',
|
||||
$_POST['ns']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
25
pg-act/ns/print.php
Normal file
25
pg-act/ns/print.php
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
|
||||
$data['zone_name'] = $_POST['zone'];
|
||||
|
||||
$zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $data['zone_name'] . 'zone');
|
||||
if ($zone_content === false)
|
||||
output(500, 'Unable to read zone file.');
|
||||
|
||||
if ($_POST['print'] === 'raw')
|
||||
$data['zone-raw'] = $zone_content;
|
||||
|
||||
elseif ($_POST['print'] === 'table')
|
||||
$data['zone-table'] = parseZoneFile($zone_content, ALLOWED_TYPES);
|
||||
|
||||
elseif ($_POST['print'] === 'ds') {
|
||||
$found = preg_match('/^' . preg_quote($data['zone_name'], '/') . '[\t ]+0[\t ]+CDS[\t ]+(?<tag>[0-9]{1,5})[\t ]+(?<algo>[0-9]{1,2})[\t ]+(?<digest_type>[0-9])[\t ]+(?<digest>[0-9A-F]{64})$/Dm', $zone_content, $data['zone-ds']);
|
||||
if ($found !== 1)
|
||||
output(500, 'Unable to get public key record from zone file.');
|
||||
}
|
||||
|
||||
else
|
||||
output(403, 'Wrong <code>print</code> method.');
|
||||
|
26
pg-act/ns/srv.php
Normal file
26
pg-act/ns/srv.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['priority'] >= 0 AND $_POST['priority'] <= 65535))
|
||||
output(403, 'Wrong value for <code>priority</code>.');
|
||||
|
||||
if (!($_POST['weight'] >= 0 AND $_POST['weight'] <= 65535))
|
||||
output(403, 'Wrong value for <code>weight</code>.');
|
||||
|
||||
if (!($_POST['port'] >= 0 AND $_POST['port'] <= 65535))
|
||||
output(403, 'Wrong value for <code>port</code>.');
|
||||
|
||||
$_POST['target'] = formatAbsoluteDomain($_POST['target']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'SRV',
|
||||
$_POST['priority'],
|
||||
$_POST['weight'],
|
||||
$_POST['port'],
|
||||
$_POST['target']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
23
pg-act/ns/sshfp.php
Normal file
23
pg-act/ns/sshfp.php
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['algo'] === '1' OR $_POST['algo'] === '3' OR $_POST['algo'] === '4'))
|
||||
output(403, 'Wrong value for <code>algo</code>.');
|
||||
|
||||
if (!($_POST['type'] === '2'))
|
||||
output(403, 'Wrong value for <code>type</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-z0-9]{64}$/D', $_POST['fp'])))
|
||||
output(403, 'Wrong value for <code>fp</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'SSHFP',
|
||||
$_POST['algo'],
|
||||
$_POST['type'],
|
||||
$_POST['fp']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
27
pg-act/ns/tlsa.php
Normal file
27
pg-act/ns/tlsa.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['use'] >= 0 AND $_POST['use'] <= 3))
|
||||
output(403, 'Wrong value for <code>use</code>.');
|
||||
|
||||
if (!($_POST['selector'] === '0' OR $_POST['selector'] === '1'))
|
||||
output(403, 'Wrong value for <code>selector</code>.');
|
||||
|
||||
if (!($_POST['type'] >= 0 AND $_POST['type'] <= 2))
|
||||
output(403, 'Wrong value for <code>type</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-zA-Z0-9.-]{1,1024}$/D', $_POST['content'])))
|
||||
output(403, 'Wrong value for <code>content</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'TLSA',
|
||||
$_POST['use'],
|
||||
$_POST['selector'],
|
||||
$_POST['type'],
|
||||
$_POST['content']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
15
pg-act/ns/txt.php
Normal file
15
pg-act/ns/txt.php
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!(preg_match('/^[a-zA-Z0-9 .@=:!%$+\/\()[\]_-]{5,8192}$/D', $_POST['txt'])))
|
||||
output(403, 'Wrong value for <code>txt</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], [
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'TXT',
|
||||
'"' . $_POST['txt'] . '"'
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
52
pg-act/ns/zone-add.php
Normal file
52
pg-act/ns/zone-add.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
$_POST['domain'] = formatAbsoluteDomain($_POST['domain']);
|
||||
|
||||
if (query('select', 'zones', ['zone' => $_POST['domain']], 'zone') !== [])
|
||||
output(403, 'Cette zone existe déjà sur ce service.');
|
||||
|
||||
exec(CONF['dns']['kdig_path'] . ' ' . ltrim(strstr($_POST['domain'], '.'), '.') . ' NS +short', $parentAuthoritatives);
|
||||
if ($parentAuthoritatives === [])
|
||||
output(403, 'Serveurs de noms de la zone parente introuvables');
|
||||
foreach ($parentAuthoritatives as $parentAuthoritative)
|
||||
checkAbsoluteDomainFormat($parentAuthoritative);
|
||||
|
||||
exec(CONF['dns']['kdig_path'] . ' ' . $_POST['domain'] . ' NS @' . $parentAuthoritatives[0] . ' +noidn', $results);
|
||||
if (preg_match('/^' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+(?<salt>[0-9a-f]{8})-(?<hash>[0-9a-f]{32})\._domain-verification\.' . preg_quote(SERVER_NAME, '/') . '\.$/Dm', implode(LF, $results), $matches) !== 1)
|
||||
output(403, 'Enregistrement d\'authentification introuvable');
|
||||
|
||||
checkAuthToken($matches['salt'], $matches['hash']);
|
||||
|
||||
rateLimit();
|
||||
|
||||
insert('zones', [
|
||||
'zone' => $_POST['domain'],
|
||||
'username' => $_SESSION['id'],
|
||||
]);
|
||||
|
||||
$knotZonePath = CONF['ns']['knot_zones_path'] . '/' . $_POST['domain'] . 'zone';
|
||||
$knotZone = implode(' ', [
|
||||
$_POST['domain'],
|
||||
SOA_VALUES['ttl'],
|
||||
'SOA',
|
||||
CONF['ns']['servers'][0],
|
||||
SOA_VALUES['email'],
|
||||
1,
|
||||
SOA_VALUES['refresh'],
|
||||
SOA_VALUES['retry'],
|
||||
SOA_VALUES['expire'],
|
||||
SOA_VALUES['negative'],
|
||||
]) . LF;
|
||||
foreach (CONF['ns']['servers'] as $server)
|
||||
$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . LF;
|
||||
if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true)
|
||||
output(500, 'Failed to write new zone file.');
|
||||
if (chmod($knotZonePath, 0660) !== true)
|
||||
output(500, 'Failed to chmod new zone file.');
|
||||
|
||||
knotcConfExec([
|
||||
"set 'zone[" . $_POST['domain'] . "]'",
|
||||
"set 'zone[" . $_POST['domain'] . "].template' 'niver'",
|
||||
]);
|
||||
|
||||
output(200, 'La zone a été créée.');
|
7
pg-act/ns/zone-del.php
Normal file
7
pg-act/ns/zone-del.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
nsCheckZonePossession($_POST['zone']);
|
||||
|
||||
nsDeleteZone($_POST['zone']);
|
||||
|
||||
output(200, 'La zone a été supprimée.');
|
30
pg-act/reg/ds.php
Normal file
30
pg-act/reg/ds.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
if (
|
||||
($_POST['algo'] !== '8')
|
||||
AND ($_POST['algo'] !== '13')
|
||||
AND ($_POST['algo'] !== '14')
|
||||
AND ($_POST['algo'] !== '15')
|
||||
AND ($_POST['algo'] !== '16')
|
||||
) output(403, 'Wrong value for <code>algo</code>.');
|
||||
|
||||
$_POST['keytag'] = intval($_POST['keytag']);
|
||||
if ((!preg_match('/^[0-9]{1,6}$/D', $_POST['keytag'])) OR !($_POST['keytag'] >= 1) OR !($_POST['keytag'] <= 65535))
|
||||
output(403, 'Wrong value for <code>keytag</code>.');
|
||||
|
||||
if ($_POST['dt'] !== '2' AND $_POST['dt'] !== '4')
|
||||
output(403, 'Wrong value for <code>dt</code>.');
|
||||
|
||||
regCheckDomainPossession($_POST['zone']);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], [
|
||||
$_POST['zone'],
|
||||
CONF['reg']['ttl'],
|
||||
'DS',
|
||||
$_POST['keytag'],
|
||||
$_POST['algo'],
|
||||
$_POST['dt'],
|
||||
$_POST['key']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
16
pg-act/reg/glue.php
Normal file
16
pg-act/reg/glue.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
regCheckDomainPossession($_POST['suffix']);
|
||||
|
||||
$domain = formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['suffix']);
|
||||
|
||||
$record = checkIpFormat($_POST['ip']);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], [
|
||||
$domain,
|
||||
CONF['reg']['ttl'],
|
||||
$record,
|
||||
$_POST['ip']
|
||||
]);
|
||||
|
||||
output(200, 'Glue ajouté/retiré.');
|
13
pg-act/reg/ns.php
Normal file
13
pg-act/reg/ns.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
regCheckDomainPossession($_POST['domain']);
|
||||
$_POST['ns'] = formatAbsoluteDomain($_POST['ns']);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], [
|
||||
$_POST['domain'],
|
||||
CONF['reg']['ttl'],
|
||||
'NS',
|
||||
$_POST['ns']
|
||||
]);
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
11
pg-act/reg/print.php
Normal file
11
pg-act/reg/print.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
regCheckDomainPossession($_POST['domain']);
|
||||
|
||||
$zone_content = file_get_contents(CONF['reg']['registry_file']);
|
||||
if ($zone_content === false)
|
||||
output(500, 'Unable to read registry file.');
|
||||
|
||||
$data['zone-content'] = parseZoneFile($zone_content, ['A', 'AAAA', 'NS', 'DS'], $_POST['domain']);
|
||||
|
||||
output(200);
|
22
pg-act/reg/register.php
Normal file
22
pg-act/reg/register.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
if (preg_match('/' . SUBDOMAIN_REGEX . '/D', $_POST['subdomain']) !== 1)
|
||||
output(403, 'Le nom de domaine doit être composé uniquement d\'entre 4 et 63 lettres minuscules ou chiffre (a-z et 0-9)');
|
||||
|
||||
$domain = formatAbsoluteDomain($_POST['subdomain'] . '.' . CONF['reg']['registry']);
|
||||
|
||||
if (query('select', 'registry', ['domain' => $domain], 'domain') !== [])
|
||||
output(403, 'Ce domaine n\'est pas disponible à l\'enregistrement. Il est déjà enregistré.');
|
||||
|
||||
if (in_array($_POST['subdomain'], explode(LF, file_get_contents(CONF['common']['root_path'] . '/pg-act/reg/reserved.txt'))))
|
||||
output(403, 'Ce domaine n\'est pas disponible à l\'enregistrement. Il est réservé.');
|
||||
|
||||
rateLimit();
|
||||
|
||||
insert('registry', [
|
||||
'domain' => $domain,
|
||||
'username' => $_SESSION['id'],
|
||||
'last_renewal' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
|
||||
output(200, 'Domaine ajouté au registre.');
|
26
pg-act/reg/transfer.php
Normal file
26
pg-act/reg/transfer.php
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
if (preg_match('/' . SUBDOMAIN_REGEX . '/D', $_POST['domain']) !== 1)
|
||||
output(403, 'Le nom de domaine semble incorrect');
|
||||
|
||||
$domain = $_POST['domain'] . '.' . CONF['reg']['registry'];
|
||||
|
||||
if (query('select', 'registry', ['username' => $_SESSION['id'], 'domain' => $domain], 'domain') !== [])
|
||||
output(403, 'Le compte présent possède déjà ce domaine.');
|
||||
|
||||
exec(CONF['dns']['kdig_path'] . ' ' . $domain . ' NS @' . CONF['reg']['address'] . ' +noidn', $results);
|
||||
if (preg_match('/^' . preg_quote($domain, '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+(?<salt>[0-9a-f]{8})-(?<hash>[0-9a-f]{32})\._transfer-verification\.' . preg_quote(SERVER_NAME, '/') . '\.$/Dm', implode(LF, $results), $matches) !== 1)
|
||||
output(403, 'Enregistrement d\'authentification introuvable');
|
||||
|
||||
checkAuthToken($matches['salt'], $matches['hash']);
|
||||
|
||||
DB->prepare('UPDATE registry SET username = :username WHERE domain = :domain')
|
||||
->execute([':username' => $_SESSION['id'], ':domain' => $domain]);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], [
|
||||
$domain,
|
||||
'NS',
|
||||
$matches['salt'] . '-' . $matches['hash'] . '._transfer-verification.' . SERVER_NAME . '.'
|
||||
], 'delete');
|
||||
|
||||
output(200, 'Le domaine a été transféré vers le compte présent, l\'enregistrement d\'authentification a été automatiquement retiré.');
|
7
pg-act/reg/unregister.php
Normal file
7
pg-act/reg/unregister.php
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
|
||||
regCheckDomainPossession($_POST['domain']);
|
||||
|
||||
regDeleteDomain($_POST['domain']);
|
||||
|
||||
output(200, 'Domaine effacé du registre.');
|
10
pg-view/auth/approval.php
Normal file
10
pg-view/auth/approval.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<p>
|
||||
Ce formulaire permet d'utiliser une clé d'approbation pour valider son compte. Une clé d'approbation est distribuée par l'administrataire sur demande.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="key">Clé d'approbation</label><br>
|
||||
<input required="" id="key" size="33" name="key" type="text" placeholder="27b81fbd8277b11ed1cf03d476cec503">
|
||||
<br>
|
||||
<input type="submit" value="Utiliser">
|
||||
</form>
|
13
pg-view/auth/login.php
Normal file
13
pg-view/auth/login.php
Normal file
|
@ -0,0 +1,13 @@
|
|||
<p>Pas de compte ? <a href="register">En créer un</a></p>
|
||||
|
||||
<form method="post">
|
||||
<label for="username">Identifiant</label><br>
|
||||
<input required="" minlength="1" maxlength="1024" pattern="<?= USERNAME_REGEX ?>" id="username" name="username" type="text" placeholder="<?= PLACEHOLDER_USERNAME ?>">
|
||||
<br>
|
||||
|
||||
<label for="password">Clé de passe</label><br>
|
||||
<input required="" autocomplete="current-password" minlength="8" maxlength="1024" pattern="<?= PASSWORD_REGEX ?>" id="password" name="password" type="password" placeholder="<?= PLACEHOLDER_PASSWORD ?>">
|
||||
<br>
|
||||
|
||||
<input type="submit">
|
||||
</form>
|
3
pg-view/auth/logout.php
Normal file
3
pg-view/auth/logout.php
Normal file
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
|
||||
logout();
|
|
@ -1,18 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
checkPasswordFormat($_POST['new-password']);
|
||||
|
||||
if (checkPassword($_SESSION['id'], $_POST['current-password']) !== true)
|
||||
output(403, 'Changement impossible : clé de passe invalide.');
|
||||
|
||||
changePassword($_SESSION['id'], $_POST['new-password']);
|
||||
|
||||
output(200, 'Clé de passe changée.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Vous pouvez ici changer la clé de passe permettant d'accéder à votre compte Niver.
|
||||
</p>
|
17
pg-view/auth/register.php
Normal file
17
pg-view/auth/register.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<p>Déjà un compte ? <a href="login">Se connecter</a></p>
|
||||
|
||||
<form method="post">
|
||||
|
||||
<label for="username">Identifiant</label>
|
||||
<br>
|
||||
<input id="username" minlength="1" maxlength="1024" pattern="<?= USERNAME_REGEX ?>" required="" name="username" type="text" placeholder="<?= PLACEHOLDER_USERNAME ?>"><br>
|
||||
|
||||
<details>
|
||||
<summary><label for="password">Clé de passe</label></summary>
|
||||
<p>Une clé de passe sécurisée est trop compliquée à deviner pour une attaque qui testerait automatiquement plein de clés de passe tout en connaissant d'autres informations et secrets sur vous.</p>
|
||||
<p>Minimum 8 caractères si elle contient minuscule, majuscule et chiffre, ou minimum 10 caractères sinon.</p>
|
||||
</details>
|
||||
<input autocomplete="new-password" id="password" minlength="8" maxlength="1024" pattern="<?= PASSWORD_REGEX ?>" required="" name="password" type="password" placeholder="<?= PLACEHOLDER_PASSWORD ?>">
|
||||
<br>
|
||||
<input type="submit">
|
||||
</form>
|
17
pg-view/auth/unregister.php
Normal file
17
pg-view/auth/unregister.php
Normal file
|
@ -0,0 +1,17 @@
|
|||
<p>
|
||||
Cette action supprimera toutes les données appartenant à ce compte, y compris :
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
<li>la possession et la réservation des domaines dans le registre</li>
|
||||
<li>les enregistrements DNS des zones hébergées sur le serveur de noms</li>
|
||||
<li>le contenu des sites</li>
|
||||
<li>les paires de clés des services Onion</li>
|
||||
</ul>
|
||||
|
||||
<form method="post">
|
||||
<input type="checkbox" name="delete" id="delete" required="">
|
||||
<label for="delete">Supprimer mon compte et toutes ses données</label>
|
||||
<br>
|
||||
<input type="submit">
|
||||
</form>
|
10
pg-view/auth/username.php
Normal file
10
pg-view/auth/username.php
Normal file
|
@ -0,0 +1,10 @@
|
|||
<p>
|
||||
Vous pouvez ici changer l'identifiant permettant d'accéder à votre compte Niver.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="new-username">Nouvel identifiant</label><br>
|
||||
<input required="" autocomplete="new-username" minlength="1" maxlength="1024" pattern="<?= USERNAME_REGEX ?>" id="new-username" name="new-username" type="text" placeholder="<?= PLACEHOLDER_USERNAME ?>"><br>
|
||||
|
||||
<input type="submit">
|
||||
</form>
|
45
pg-view/ht/add-http-dns.php
Normal file
45
pg-view/ht/add-http-dns.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
$dirsStatuses = dirsStatuses('dns', 'http');
|
||||
|
||||
$proof = getAuthToken();
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Ajouter sur un dossier de site un accès <?= linkToDocs('http', 'HTTP') ?> par <?= linkToDocs('dns', 'DNS') ?> et <?= linkToDocs('tls', 'TLS') ?> <?= linkToDocs('ca', 'authentifié par <em>Let\'s Encrypt</em>') ?>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
La présence des enregistrements ci-après sera vérifiée lors du traitement de ce formulaire.
|
||||
</p>
|
||||
|
||||
<dl>
|
||||
<dt><code>AAAA</code></dt>
|
||||
<dd>
|
||||
<code><?= CONF['ht']['ipv6_address'] ?></code>
|
||||
</dd>
|
||||
<dt><code>A</code></dt>
|
||||
<dd>
|
||||
<code><?= CONF['ht']['ipv4_address'] ?></code>
|
||||
</dd>
|
||||
<dt><code>TXT</code></dt>
|
||||
<dd>
|
||||
<code><?= SERVER_NAME ?>_domain-verification=<?= $proof ?></code>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<form method="post">
|
||||
<label for="domain">Domaine sur lequel répondre</label><br>
|
||||
<input required="" placeholder="site.<?= PLACEHOLDER_DOMAIN ?>" 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
|
||||
foreach ($dirsStatuses as $dir => $alreadyEnabled)
|
||||
echo ' <option' . ($alreadyEnabled ? ' disabled=""' : '') . ' value="' . $dir . '">' . $dir . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Valider" type="submit">
|
||||
</form>
|
22
pg-view/ht/add-http-onion.php
Normal file
22
pg-view/ht/add-http-onion.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
$dirsStatuses = dirsStatuses('onion', 'http');
|
||||
|
||||
?>
|
||||
|
||||
<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
|
||||
foreach ($dirsStatuses as $dir => $alreadyEnabled)
|
||||
echo ' <option' . ($alreadyEnabled ? ' disabled=""' : '') . ' value="' . $dir . '">' . $dir . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Valider" type="submit">
|
||||
</form>
|
|
@ -1,15 +1,6 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
if (dirsStatuses('dns', 'http')[$_POST['dir']] !== true)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
htDeleteSite($_POST['dir'], domainType: 'dns', protocol: 'http');
|
||||
|
||||
output(200, 'Accès retiré.');
|
||||
}
|
||||
|
||||
$dirsStatuses = dirsStatuses('onion', 'http');
|
||||
$dirsStatuses = dirsStatuses('dns', 'http');
|
||||
|
||||
?>
|
||||
|
|
@ -1,14 +1,5 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
if (dirsStatuses('onion', 'http')[$_POST['dir']] !== true)
|
||||
output(403, 'Wrong value for <code>dir</code>.');
|
||||
|
||||
htDeleteSite($_POST['dir'], domainType: 'onion', protocol: 'http');
|
||||
|
||||
output(200, 'Accès retiré.');
|
||||
}
|
||||
|
||||
$dirsStatuses = dirsStatuses('onion', 'http');
|
||||
|
||||
?>
|
|
@ -1,31 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['flag'] >= 0 AND $_POST['flag'] <= 255))
|
||||
output(403, 'Wrong value for <code>flag</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-z]{1,127}$/D', $_POST['tag'])))
|
||||
output(403, 'Wrong value for <code>tag</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-z0-9.-]{1,255}$/D', $_POST['value'])))
|
||||
output(403, 'Wrong value for <code>value</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'CAA',
|
||||
$_POST['flag'],
|
||||
$_POST['tag'],
|
||||
$_POST['value']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-caa', 'Documentation du type d\'enregistrement CAA') ?>
|
||||
</p>
|
|
@ -1,22 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$_POST['cname'] = formatAbsoluteDomain($_POST['cname']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'CNAME',
|
||||
$_POST['cname']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-cname', 'Documentation du type d\'enregistrement CNAME') ?>
|
||||
</p>
|
|
@ -1,22 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$_POST['dname'] = formatAbsoluteDomain($_POST['dname']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'DNAME',
|
||||
$_POST['dname']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-dname', 'Documentation du type d\'enregistrement DNAME') ?>
|
||||
</p>
|
58
pg-view/ns/edit.php
Normal file
58
pg-view/ns/edit.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<form method="post">
|
||||
<label for="zone">Zone à modifier</label>
|
||||
<br>
|
||||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
foreach (nsListUserZones() as $zone)
|
||||
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input type="submit" value="Afficher">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
if (isset($data['zone_content'])) { // Display zone
|
||||
|
||||
?>
|
||||
<form method="post">
|
||||
<input type="hidden" name="zone" value="<?= $_POST['zone'] ?>">
|
||||
|
||||
<label for="zone-content">Nouveau contenu de la zone <code><strong><?= $_POST['zone'] ?></strong></code></label>
|
||||
<br>
|
||||
<textarea id="zone-content" name="zone-content" wrap="off" rows="<?= substr_count($data['zone_content'], LF) + 1 ?>"><?= htmlspecialchars($data['zone_content']) ?></textarea>
|
||||
<br>
|
||||
<input type="submit" value="Remplacer">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
displayFinalMessage($data);
|
||||
|
||||
?>
|
||||
|
||||
<h2>Valeurs par défaut</h2>
|
||||
|
||||
<p>Si le TTL est omis, il sera définit à <code><time datetime="PT<?= DEFAULT_TTL ?>S"><?= DEFAULT_TTL ?></time></code> secondes.</p>
|
||||
|
||||
<p>La précision de la classe (<code>IN</code>) est facultative.</p>
|
||||
|
||||
<h2>Valeurs autorisées</h2>
|
||||
|
||||
<p>La zone n'est pas autorisée à dépasser <?= ZONE_MAX_CHARACTERS ?> caractères.</p>
|
||||
|
||||
<p>Les TTLs ne sont autorisés qu'entre <code><time datetime="PT<?= MIN_TTL ?>S"><?= MIN_TTL ?></time></code> et <code><time datetime="PT<?= MAX_TTL ?>S"><?= MAX_TTL ?></time></code> secondes.</p>
|
||||
|
||||
<p>Les seuls types dont l'édition est autorisée sont :</p>
|
||||
|
||||
<ul>
|
||||
<?php
|
||||
foreach (ALLOWED_TYPES as $allowed_type)
|
||||
echo ' <li><code>' . $allowed_type . '</code></li>';
|
||||
|
||||
?>
|
||||
</ul>
|
|
@ -1,22 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$record = checkIpFormat($_POST['ip']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
$record,
|
||||
$_POST['ip']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-ip', 'Documentation des types d\'enregistrements A et AAAA') ?>
|
||||
</p>
|
|
@ -1,78 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (empty($_POST['lat-min']))
|
||||
$_POST['lat-min'] = 0;
|
||||
if (empty($_POST['lat-sec']))
|
||||
$_POST['lat-sec'] = 0;
|
||||
if (empty($_POST['lon-min']))
|
||||
$_POST['lon-min'] = 0;
|
||||
if (empty($_POST['lon-sec']))
|
||||
$_POST['lon-sec'] = 0;
|
||||
if (empty($_POST['size']))
|
||||
$_POST['size'] = 1;
|
||||
if (empty($_POST['hp']))
|
||||
$_POST['hp'] = 10000;
|
||||
if (empty($_POST['vp']))
|
||||
$_POST['vp'] = 10;
|
||||
|
||||
if (!($_POST['lat-deg'] >= 0 AND $_POST['lat-deg'] <= 90))
|
||||
output(403, 'Wrong value for <code>lat-deg</code>.');
|
||||
if (!($_POST['lat-min'] >= 0 AND $_POST['lat-min'] <= 59))
|
||||
output(403, 'Wrong value for <code>lat-min</code>.');
|
||||
if (!($_POST['lat-sec'] >= 0 AND $_POST['lat-sec'] <= 59.999))
|
||||
output(403, 'Wrong value for <code>lat-sec</code>.');
|
||||
|
||||
if ($_POST['lat-dir'] !== 'N' AND $_POST['lat-dir'] !== 'S')
|
||||
output(403, 'Wrong value for <code>lat-dir</code>.');
|
||||
|
||||
if (!($_POST['lon-deg'] >= 0 AND $_POST['lon-deg'] <= 180))
|
||||
output(403, 'Wrong value for <code>lon-deg</code>.');
|
||||
if (!($_POST['lon-min'] >= 0 AND $_POST['lon-min'] <= 59))
|
||||
output(403, 'Wrong value for <code>lon-min</code>.');
|
||||
if (!($_POST['lon-sec'] >= 0 AND $_POST['lon-sec'] <= 59.999))
|
||||
output(403, 'Wrong value for <code>lon-sec</code>.');
|
||||
|
||||
if ($_POST['lon-dir'] !== 'E' AND $_POST['lon-dir'] !== 'W')
|
||||
output(403, 'Wrong value for <code>lon-dir</code>.');
|
||||
|
||||
if (!($_POST['alt'] >= -100000 AND $_POST['alt'] <= 42849672.95))
|
||||
output(403, 'Wrong value for <code>alt</code>.');
|
||||
|
||||
if (!($_POST['size'] >= 0 AND $_POST['size'] <= 90000000))
|
||||
output(403, 'Wrong value for <code>size</code>.');
|
||||
|
||||
if (!($_POST['hp'] >= 0 AND $_POST['hp'] <= 90000000))
|
||||
output(403, 'Wrong value for <code>hp</code>.');
|
||||
|
||||
if (!($_POST['vp'] >= 0 AND $_POST['vp'] <= 90000000))
|
||||
output(403, 'Wrong value for <code>vp</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'LOC',
|
||||
$_POST['lat-deg'],
|
||||
$_POST['lat-min'],
|
||||
$_POST['lat-sec'],
|
||||
$_POST['lat-dir'],
|
||||
$_POST['lon-deg'],
|
||||
$_POST['lon-min'],
|
||||
$_POST['lon-sec'],
|
||||
$_POST['lon-dir'],
|
||||
$_POST['alt'] . 'm',
|
||||
$_POST['size'] . 'm',
|
||||
$_POST['hp'] . 'm',
|
||||
$_POST['vp'] . 'm',
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-loc', 'Documentation du type d\'enregistrement LOC') ?>
|
||||
</p>
|
|
@ -1,26 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['priority'] >= 0 AND $_POST['priority'] <= 255))
|
||||
output(403, 'Wrong value for <code>priority</code>.');
|
||||
|
||||
$_POST['host'] = formatAbsoluteDomain($_POST['host']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'MX',
|
||||
$_POST['priority'],
|
||||
$_POST['host']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-mx', 'Documentation du type d\'enregistrement MX') ?>
|
||||
</p>
|
|
@ -1,22 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
$_POST['ns'] = formatAbsoluteDomain($_POST['ns']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'NS',
|
||||
$_POST['ns']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-ns', 'Documentation du type d\'enregistrement NS') ?>
|
||||
</p>
|
77
pg-view/ns/print.php
Normal file
77
pg-view/ns/print.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
|
||||
<form method="post">
|
||||
<input type="radio" name="print" id="table" value="table" checked="">
|
||||
<label for="table">Tableau de mes enregistrements</label>
|
||||
<br>
|
||||
<input type="radio" name="print" id="ds" value="ds">
|
||||
<label for="ds">Enregistrement DS</label>
|
||||
<br>
|
||||
<input type="radio" name="print" id="raw" value="raw">
|
||||
<label for="raw">Fichier de zone brut</label>
|
||||
<br>
|
||||
<label for="zone">Zone</label>
|
||||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
foreach (nsListUserZones() as $zone)
|
||||
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Afficher" type="submit">
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
if (isset($data['zone-raw']))
|
||||
echo '<pre>' . htmlspecialchars($data['zone-raw']) . '</pre>';
|
||||
|
||||
if (isset($data['zone-table'])) { ?>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Domaine</th>
|
||||
<th>TTL</th>
|
||||
<th>Type</th>
|
||||
<th>Contenu</th>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($data['zone-table'] as $zone_line) {
|
||||
echo ' <tr>' . LF;
|
||||
foreach ($zone_line as $element)
|
||||
echo ' <td><code>' . htmlspecialchars($element) . '</code></td>' . LF;
|
||||
echo ' </tr>' . LF;
|
||||
}
|
||||
}
|
||||
?>
|
||||
</table>
|
||||
<?php
|
||||
|
||||
if (isset($data['zone-ds'])) { ?>
|
||||
|
||||
<dl>
|
||||
<dt>Zone</dt>
|
||||
<dd>
|
||||
<code><?= $_POST['zone'] ?></code>
|
||||
</dd>
|
||||
<dt>Tag</dt>
|
||||
<dd>
|
||||
<code><?= $data['zone-ds']['tag'] ?></code>
|
||||
</dd>
|
||||
<dt>Algorithme</dt>
|
||||
<dd>
|
||||
<code><?= $data['zone-ds']['algo'] ?></code><?= ($data['zone-ds']['algo'] === '15') ? ' (Ed25519)' : '' ?>
|
||||
</dd>
|
||||
<dt>Type de condensat</dt>
|
||||
<dd>
|
||||
<code><?= $data['zone-ds']['digest_type'] ?></code><?= ($data['zone-ds']['digest_type'] === '2') ? ' (SHA-256)' : '' ?>
|
||||
</dd>
|
||||
<dt>Condensat</dt>
|
||||
<dd>
|
||||
<code><?= $data['zone-ds']['digest'] ?></code>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
|
@ -1,34 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['priority'] >= 0 AND $_POST['priority'] <= 65535))
|
||||
output(403, 'Wrong value for <code>priority</code>.');
|
||||
|
||||
if (!($_POST['weight'] >= 0 AND $_POST['weight'] <= 65535))
|
||||
output(403, 'Wrong value for <code>weight</code>.');
|
||||
|
||||
if (!($_POST['port'] >= 0 AND $_POST['port'] <= 65535))
|
||||
output(403, 'Wrong value for <code>port</code>.');
|
||||
|
||||
$_POST['target'] = formatAbsoluteDomain($_POST['target']);
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'SRV',
|
||||
$_POST['priority'],
|
||||
$_POST['weight'],
|
||||
$_POST['port'],
|
||||
$_POST['target']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-srv', 'Documentation du type d\'enregistrement SRV') ?>
|
||||
</p>
|
|
@ -1,31 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['algo'] === '1' OR $_POST['algo'] === '3' OR $_POST['algo'] === '4'))
|
||||
output(403, 'Wrong value for <code>algo</code>.');
|
||||
|
||||
if (!($_POST['type'] === '2'))
|
||||
output(403, 'Wrong value for <code>type</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-z0-9]{64}$/D', $_POST['fp'])))
|
||||
output(403, 'Wrong value for <code>fp</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'SSHFP',
|
||||
$_POST['algo'],
|
||||
$_POST['type'],
|
||||
$_POST['fp']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-sshfp', 'Documentation du type d\'enregistrement SSHFP') ?>
|
||||
</p>
|
|
@ -1,35 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!($_POST['use'] >= 0 AND $_POST['use'] <= 3))
|
||||
output(403, 'Wrong value for <code>use</code>.');
|
||||
|
||||
if (!($_POST['selector'] === '0' OR $_POST['selector'] === '1'))
|
||||
output(403, 'Wrong value for <code>selector</code>.');
|
||||
|
||||
if (!($_POST['type'] >= 0 AND $_POST['type'] <= 2))
|
||||
output(403, 'Wrong value for <code>type</code>.');
|
||||
|
||||
if (!(preg_match('/^[a-zA-Z0-9.-]{1,1024}$/D', $_POST['content'])))
|
||||
output(403, 'Wrong value for <code>content</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'TLSA',
|
||||
$_POST['use'],
|
||||
$_POST['selector'],
|
||||
$_POST['type'],
|
||||
$_POST['content']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-tlsa', 'Documentation du type d\'enregistrement TLSA') ?>
|
||||
</p>
|
|
@ -1,23 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
$values = nsParseCommonRequirements();
|
||||
|
||||
if (!(preg_match('/^[a-zA-Z0-9 .@=:!%$+\/\()[\]_-]{5,8192}$/D', $_POST['txt'])))
|
||||
output(403, 'Wrong value for <code>txt</code>.');
|
||||
|
||||
knotcZoneExec($_POST['zone'], array(
|
||||
$values['domain'],
|
||||
$values['ttl'],
|
||||
'TXT',
|
||||
'"' . $_POST['txt'] . '"'
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-txt', 'Documentation du type d\'enregistrement TXT') ?>
|
||||
</p>
|
19
pg-view/ns/zone-add.php
Normal file
19
pg-view/ns/zone-add.php
Normal file
|
@ -0,0 +1,19 @@
|
|||
<p>
|
||||
Pour prouver que vous possédez bien ce domaine, il doit posséder un <?= linkToDocs('ns-record', 'enregistrement NS') ?> égal à <code><?= $proof ?>._domain-verification.<?= SERVER_NAME ?>.</code> lors du traitement de ce formulaire.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
La zone sera servie par ces serveurs de noms :
|
||||
<ul>
|
||||
<?php
|
||||
foreach (CONF['ns']['servers'] as $server)
|
||||
echo ' <li><code>' . $server . '</code></li>';
|
||||
?>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="domain">Domaine</label><br>
|
||||
<input required="" placeholder="domain.<?= PLACEHOLDER_DOMAIN ?>." id="domain" name="domain" type="text"><br>
|
||||
<input value="Ajouter" type="submit">
|
||||
</form>
|
12
pg-view/ns/zone-del.php
Normal file
12
pg-view/ns/zone-del.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<form method="post">
|
||||
<label for="zone">Zone</label>
|
||||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
foreach (nsListUserZones() as $zone)
|
||||
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Supprimer toutes les données liées à cette zone" type="submit">
|
||||
</form>
|
|
@ -1,45 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (isset($_SESSION['id']))
|
||||
$domains = regListUserDomains($_SESSION['id']);
|
||||
else
|
||||
$domains = [];
|
||||
|
||||
if (processForm()) {
|
||||
if (
|
||||
($_POST['algo'] !== '8')
|
||||
AND ($_POST['algo'] !== '13')
|
||||
AND ($_POST['algo'] !== '14')
|
||||
AND ($_POST['algo'] !== '15')
|
||||
AND ($_POST['algo'] !== '16')
|
||||
) output(403, 'Wrong value for <code>algo</code>.');
|
||||
|
||||
$_POST['keytag'] = intval($_POST['keytag']);
|
||||
if ((!preg_match('/^[0-9]{1,6}$/D', $_POST['keytag'])) OR !($_POST['keytag'] >= 1) OR !($_POST['keytag'] <= 65535))
|
||||
output(403, 'Wrong value for <code>keytag</code>.');
|
||||
|
||||
if ($_POST['dt'] !== '2' AND $_POST['dt'] !== '4')
|
||||
output(403, 'Wrong value for <code>dt</code>.');
|
||||
|
||||
regCheckDomainPossession($_POST['zone']);
|
||||
|
||||
$action = checkAction($_POST['action']);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], array(
|
||||
$_POST['zone'],
|
||||
CONF['reg']['ttl'],
|
||||
'DS',
|
||||
$_POST['keytag'],
|
||||
$_POST['algo'],
|
||||
$_POST['dt'],
|
||||
$_POST['key']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Ici vous pouvez indiquer au registre l'enregistrement DS d'une zone afin de permettre de déléguer la confiance <?= linkToDocs('dnssec', 'DNSSEC') ?>.
|
||||
</p>
|
||||
|
@ -56,7 +14,7 @@ if (processForm()) {
|
|||
<select required="" name="zone" id="zone">
|
||||
<option value="" disabled="" selected="">---</option>
|
||||
<?php
|
||||
foreach ($domains as $domain)
|
||||
foreach (regListUserDomains() as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
|
@ -1,24 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
regCheckDomainPossession($_POST['suffix']);
|
||||
|
||||
$domain = formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['suffix']);
|
||||
|
||||
$record = checkIpFormat($_POST['ip']);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], array(
|
||||
$domain,
|
||||
CONF['reg']['ttl'],
|
||||
$record,
|
||||
$_POST['ip']
|
||||
));
|
||||
|
||||
output(200, 'Glue ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('glue-record', 'Documentation sur le glue record'); ?>
|
||||
</p>
|
||||
|
@ -42,9 +21,8 @@ if (processForm()) {
|
|||
<select required="" name="suffix" id="suffix">
|
||||
<option value="" disabled="" selected="">---</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach(regListUserDomains($_SESSION['id']) as $suffix)
|
||||
echo ' <option value="' . $suffix . '">' . $suffix . '</option>' . LF;
|
||||
foreach(regListUserDomains() as $suffix)
|
||||
echo ' <option value="' . $suffix . '">' . $suffix . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
</div>
|
|
@ -1,21 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
regCheckDomainPossession($_POST['domain']);
|
||||
$_POST['ns'] = formatAbsoluteDomain($_POST['ns']);
|
||||
|
||||
knotcZoneExec(CONF['reg']['registry'], array(
|
||||
$_POST['domain'],
|
||||
CONF['reg']['ttl'],
|
||||
'NS',
|
||||
$_POST['ns']
|
||||
));
|
||||
|
||||
output(200, 'Enregistrement ajouté/retiré.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
<?= linkToDocs('record-ns', 'Documentation du type d\'enregistrement NS') ?>
|
||||
</p>
|
||||
|
@ -32,9 +14,8 @@ if (processForm()) {
|
|||
<select required="" name="domain" id="domain">
|
||||
<option value="" disabled="" selected="">---</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach (regListUserDomains($_SESSION['id']) as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
foreach (regListUserDomains() as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
34
pg-view/reg/print.php
Normal file
34
pg-view/reg/print.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<form method="post">
|
||||
<label for="domain">Domaine</label>
|
||||
<select required="" name="domain" id="domain">
|
||||
<option value="" disabled="" selected="">-</option>
|
||||
<?php
|
||||
foreach (regListUserDomains() as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
||||
<input value="Afficher" type="submit">
|
||||
</form>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Domaine</th>
|
||||
<th>TTL</th>
|
||||
<th>Type</th>
|
||||
<th>Contenu</th>
|
||||
</tr>
|
||||
|
||||
<?php
|
||||
|
||||
if (isset($data['zone-content'])) {
|
||||
foreach ($data['zone-content'] as $zone_line) {
|
||||
echo ' <tr>' . LF;
|
||||
foreach ($zone_line as $element)
|
||||
echo ' <td><code>' . htmlspecialchars($element) . '</code></td>' . LF;
|
||||
echo ' </tr>' . LF;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
</table>
|
11
pg-view/reg/register.php
Normal file
11
pg-view/reg/register.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<p>
|
||||
Enregistrer un nouveau domaine sur son compte. Ce domaine doit être composé uniquement d'au moins 4 lettres latines non accentuées (a-z).
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="subdomain">Sous-domaine</label>
|
||||
<br>
|
||||
<code><input id="subdomain" pattern="<?= SUBDOMAIN_REGEX ?>" required="" placeholder="niver" name="subdomain" type="text">.<?= CONF['reg']['registry'] ?></code>
|
||||
<br>
|
||||
<input value="Enregistrer" type="submit">
|
||||
</form>
|
242
pg-view/reg/reserved.txt
Normal file
242
pg-view/reg/reserved.txt
Normal file
|
@ -0,0 +1,242 @@
|
|||
# List of subdomains not available to register
|
||||
#
|
||||
# They may be forbidden because:
|
||||
# - they may be privileged for impersonating Niver, spamming or fishing
|
||||
# - they are reserved for a project asking for it and deserving such a well-known name
|
||||
|
||||
niver
|
||||
|
||||
# Registry-related
|
||||
nic
|
||||
domain
|
||||
domains
|
||||
reg
|
||||
registry
|
||||
|
||||
# Special subdomains
|
||||
autoconfig
|
||||
autodiscover
|
||||
|
||||
# Special TLDs
|
||||
example
|
||||
invalid
|
||||
test
|
||||
local
|
||||
localhost
|
||||
onion
|
||||
|
||||
# Standard-related
|
||||
ns0
|
||||
ns1
|
||||
ns2
|
||||
ns3
|
||||
ns4
|
||||
ns5
|
||||
ns6
|
||||
ns7
|
||||
ns8
|
||||
ns9
|
||||
dns
|
||||
dns0
|
||||
dns1
|
||||
dns2
|
||||
dns3
|
||||
dns4
|
||||
dns5
|
||||
dns6
|
||||
dns7
|
||||
dns8
|
||||
dns9
|
||||
www
|
||||
wwww
|
||||
www0
|
||||
www1
|
||||
www2
|
||||
www3
|
||||
www4
|
||||
www5
|
||||
www6
|
||||
www7
|
||||
www8
|
||||
www9
|
||||
srv
|
||||
srv0
|
||||
srv1
|
||||
srv2
|
||||
srv3
|
||||
srv4
|
||||
srv5
|
||||
srv6
|
||||
srv7
|
||||
srv8
|
||||
srv9
|
||||
ssh
|
||||
sftp
|
||||
http
|
||||
https
|
||||
ssl
|
||||
tls
|
||||
mtx
|
||||
matrix
|
||||
gmi
|
||||
gemini
|
||||
ftp
|
||||
ftps
|
||||
mx
|
||||
imap
|
||||
imaps
|
||||
smtp
|
||||
smtps
|
||||
pop
|
||||
xmpp
|
||||
fedi
|
||||
html
|
||||
rss
|
||||
ipv4
|
||||
ipv6
|
||||
|
||||
# Prevent account fishing
|
||||
account
|
||||
accounts
|
||||
register
|
||||
profile
|
||||
signup
|
||||
login
|
||||
auth
|
||||
authenticate
|
||||
connect
|
||||
|
||||
# Commercial
|
||||
com
|
||||
free
|
||||
trial
|
||||
ads
|
||||
bank
|
||||
banks
|
||||
business
|
||||
customer
|
||||
customers
|
||||
store
|
||||
stores
|
||||
shop
|
||||
shops
|
||||
job
|
||||
jobs
|
||||
marketing
|
||||
sales
|
||||
|
||||
# Miscellaneous
|
||||
org
|
||||
net
|
||||
com
|
||||
gov
|
||||
gouv
|
||||
edu
|
||||
api
|
||||
cdn
|
||||
support
|
||||
admin
|
||||
web
|
||||
dev
|
||||
host
|
||||
portal
|
||||
beta
|
||||
alpha
|
||||
demo
|
||||
vpn
|
||||
temp
|
||||
root
|
||||
data
|
||||
stats
|
||||
chat
|
||||
about
|
||||
remote
|
||||
portal
|
||||
boost
|
||||
core
|
||||
learn
|
||||
community
|
||||
meta
|
||||
news
|
||||
public
|
||||
online
|
||||
join
|
||||
mobile
|
||||
tech
|
||||
space
|
||||
zone
|
||||
name
|
||||
access
|
||||
search
|
||||
static
|
||||
secure
|
||||
security
|
||||
bbs
|
||||
help
|
||||
info
|
||||
code
|
||||
doc
|
||||
docs
|
||||
server
|
||||
servers
|
||||
client
|
||||
clients
|
||||
mail
|
||||
mails
|
||||
email
|
||||
emails
|
||||
webmail
|
||||
site
|
||||
sites
|
||||
website
|
||||
websites
|
||||
blog
|
||||
blogs
|
||||
gemlog
|
||||
gemlogs
|
||||
capsule
|
||||
capsules
|
||||
source
|
||||
sources
|
||||
update
|
||||
updates
|
||||
forum
|
||||
forums
|
||||
service
|
||||
services
|
||||
ressource
|
||||
ressources
|
||||
image
|
||||
images
|
||||
video
|
||||
videos
|
||||
radio
|
||||
radios
|
||||
music
|
||||
map
|
||||
maps
|
||||
app
|
||||
apps
|
||||
dev
|
||||
devs
|
||||
developer
|
||||
developers
|
||||
social
|
||||
cloud
|
||||
clouds
|
||||
network
|
||||
networks
|
||||
survey
|
||||
surveys
|
||||
build
|
||||
builds
|
||||
upload
|
||||
uploads
|
||||
download
|
||||
downloads
|
||||
content
|
||||
contents
|
||||
drive
|
||||
drives
|
||||
home
|
||||
homes
|
11
pg-view/reg/transfer.php
Normal file
11
pg-view/reg/transfer.php
Normal file
|
@ -0,0 +1,11 @@
|
|||
<p>
|
||||
Pour prouver que vous êtes autorisé à recevoir le domaine par san possessaire actuele, ledit domaine doit posséder un <?= linkToDocs('ns-record', 'enregistrement NS') ?> égal à <code><?= getAuthToken() ?>._transfer-verification.<?= SERVER_NAME ?>.</code> lors du traitement de ce formulaire. Cet enregistrement sera automatiquement retiré une fois validé.
|
||||
</p>
|
||||
|
||||
<form method="post">
|
||||
<label for="subdomain">Sous-domaine à recevoir</label>
|
||||
<br>
|
||||
<code><input required="" placeholder="subdomain" id="subdomain" name="subdomain" type="text">.<?= CONF['reg']['registry'] ?></code>
|
||||
<br>
|
||||
<input value="Recevoir ce domaine" type="submit">
|
||||
</form>
|
|
@ -1,15 +1,3 @@
|
|||
<?php
|
||||
|
||||
if (processForm()) {
|
||||
regCheckDomainPossession($_POST['domain']);
|
||||
|
||||
regDeleteDomain($_POST['domain']);
|
||||
|
||||
output(200, 'Domaine effacé du registre.');
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<p>
|
||||
Ceci désenregistrera le domaine, et le rendra ainsi à nouveau disponible à l'enregistrement par n'importe qui.
|
||||
</p>
|
||||
|
@ -20,9 +8,8 @@ if (processForm()) {
|
|||
<select required="" name="domain" id="domain">
|
||||
<option value="" disabled="" selected="">---</option>
|
||||
<?php
|
||||
if (isset($_SESSION['id']))
|
||||
foreach(regListUserDomains($_SESSION['id']) as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
foreach(regListUserDomains() as $domain)
|
||||
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
|
||||
?>
|
||||
</select>
|
||||
<br>
|
85
router.php
85
router.php
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
define('TIME', hrtime(true));
|
||||
define('CONF', parse_ini_file(__DIR__ . '/config.ini', true, INI_SCANNER_TYPED));
|
||||
|
||||
foreach (array_diff(scandir(CONF['common']['root_path'] . '/fn'), array('..', '.')) as $file)
|
||||
|
@ -31,7 +32,8 @@ function getPageInformations($pages, $pageElements) {
|
|||
if (!isset($pages['index']) OR $pageElements[0] === 'index')
|
||||
return [
|
||||
'titles_lineage' => [$pages[$pageElements[0]]['title'] ?? false],
|
||||
'page_metadata' => $pages[$pageElements[0]] ?? NULL
|
||||
'page_metadata' => $pages[$pageElements[0]] ?? NULL,
|
||||
'terminal' => $pageElements[0] !== 'index'
|
||||
];
|
||||
$result = $pages['index']['title'];
|
||||
if (!isset($pageElements[1]))
|
||||
|
@ -45,6 +47,7 @@ function getPageInformations($pages, $pageElements) {
|
|||
$pageInformations = getPageInformations(PAGES, PAGE_LINEAGE);
|
||||
define('TITLES_LINEAGE', array_reverse($pageInformations['titles_lineage']));
|
||||
define('PAGE_METADATA', $pageInformations['page_metadata']);
|
||||
define('PAGE_TERMINAL', $pageInformations['terminal']);
|
||||
|
||||
if (!TITLES_LINEAGE[array_key_last(TITLES_LINEAGE)]) {
|
||||
http_response_code(404);
|
||||
|
@ -52,11 +55,7 @@ if (!TITLES_LINEAGE[array_key_last(TITLES_LINEAGE)]) {
|
|||
}
|
||||
|
||||
const SESSION_COOKIE_NAME = 'niver-session-key';
|
||||
if (
|
||||
isset($_COOKIE[SESSION_COOKIE_NAME]) // Resume session
|
||||
OR
|
||||
(isset($_POST['username']) AND in_array(PAGE_URL, ['auth/login', 'auth/register'])) // Start new session
|
||||
) {
|
||||
function startSession() {
|
||||
session_start([
|
||||
'name' => SESSION_COOKIE_NAME,
|
||||
'sid_length' => 64,
|
||||
|
@ -72,44 +71,8 @@ if (
|
|||
'use_only_cookies' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr"<?php if (!empty(SERVICE)) echo ' class="' . SERVICE . '"'; ?>>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?php
|
||||
foreach(array_reverse(TITLES_LINEAGE) as $id => $title)
|
||||
echo strip_tags($title) . (array_key_last(TITLES_LINEAGE) === $id ? '' : ' < ');
|
||||
?></title>
|
||||
<?php
|
||||
foreach (glob('css/*.css') as $cssPath)
|
||||
echo ' <link type="text/css" rel="stylesheet" media="screen" href="' . CONF['common']['prefix'] . '/' . $cssPath . '">' . LF;
|
||||
?>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<p>
|
||||
<?php if (isset($_SESSION['id'])) { ?>
|
||||
<?= ($_SESSION['type'] === 'approved') ? '<span title="Compte approuvé">👤 </span>' : '<span title="Compte de test">⏳ </span>' ?><strong><?= $_SESSION['display-username'] ?></strong> <a class="auth" href="<?= CONF['common']['prefix'] ?>/auth/logout">Se déconnecter</a>
|
||||
<?php } else { ?>
|
||||
<span aria-hidden="true">👻 </span><em>Anonyme</em> <a class="auth" href="<?= redirUrl('auth/login') ?>">Se connecter</a>
|
||||
<?php } ?>
|
||||
</p>
|
||||
<nav>
|
||||
<?php
|
||||
foreach (TITLES_LINEAGE as $id => $title) {
|
||||
$lastTitle = (TITLES_LINEAGE[array_key_last(TITLES_LINEAGE)] === $title);
|
||||
echo '<ul><li>' . ($lastTitle ? '<h1>' : '') . '<a' . (($id === 0) ? ' class="niver"' : '') . ' href="' . CONF['common']['prefix'] . ($lastTitle ? '/' . PAGE_URL : '/' . implode('/', array_slice(PAGE_LINEAGE, 0, $id)) . (($lastTitle OR $id === 0) ? '' : '/')) . '">' . $title . '</a>' . ($lastTitle ? '</h1>' : '') . LF;
|
||||
}
|
||||
echo str_repeat('</li></ul>', count(TITLES_LINEAGE));
|
||||
?>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<?php
|
||||
if (isset($_COOKIE[SESSION_COOKIE_NAME]))
|
||||
startSession(); // Resume session
|
||||
|
||||
if (in_array(SERVICE, ['reg', 'ns', 'ht']) AND CONF[SERVICE]['enabled'] !== true)
|
||||
output(403, 'Ce service est désactivé.');
|
||||
|
@ -128,24 +91,26 @@ if (in_array($_SERVER['SERVER_NAME'], CONF['common']['public_domains'], true) !=
|
|||
output(500, 'The current server name is not allowed in configuration.');
|
||||
define('SERVER_NAME', $_SERVER['SERVER_NAME']);
|
||||
|
||||
function displayFinalMessage() {
|
||||
global $final_message;
|
||||
echo $final_message ?? '';
|
||||
$final_message = NULL;
|
||||
function displayFinalMessage($data) {
|
||||
if (isset($data['final_message'])) {
|
||||
echo $data['final_message'];
|
||||
unset($data['final_message']);
|
||||
}
|
||||
}
|
||||
|
||||
function executePage() {
|
||||
require 'pages/' . PAGE_ADDRESS . '.php';
|
||||
if ($_POST !== []) {
|
||||
if (PAGE_METADATA['require-login'] ?? true !== false) {
|
||||
if (isset($_SESSION['id']) !== true)
|
||||
output(403, 'Vous devez être connecté·e à un compte pour effectuer cette action.');
|
||||
if (isset(query('select', 'users', ['id' => $_SESSION['id']], 'id')[0]) !== true)
|
||||
output(403, 'Ce compte n\'existe plus. Déconnectez-vous pour terminer cette session fantôme.');
|
||||
}
|
||||
if (file_exists('pg-act/' . PAGE_ADDRESS . '.php'))
|
||||
require 'pg-act/' . PAGE_ADDRESS . '.php';
|
||||
}
|
||||
|
||||
displayFinalMessage();
|
||||
?>
|
||||
</main>
|
||||
<footer>
|
||||
<small><a rel="external" href="https://code.antopie.org/niver/niver" class="niver">Code source</a> sous <abbr title="Cooperative Nonviolent Public License No Attribution version 7 ou plus">CNPL-NAv7+</abbr>.</small>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
function displayPage($data) {
|
||||
require 'view.php';
|
||||
exit();
|
||||
}
|
||||
executePage();
|
||||
displayPage($data ??= NULL);
|
||||
|
|
51
view.php
Normal file
51
view.php
Normal file
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="fr"<?php if (!empty(SERVICE)) echo ' class="' . SERVICE . '"'; ?>>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title><?php
|
||||
foreach(array_reverse(TITLES_LINEAGE) as $id => $title)
|
||||
echo strip_tags($title) . (array_key_last(TITLES_LINEAGE) === $id ? '' : ' < ');
|
||||
?></title>
|
||||
<?php
|
||||
foreach (glob('css/*.css') as $css_path)
|
||||
echo ' <link type="text/css" rel="stylesheet" media="screen" href="' . CONF['common']['prefix'] . '/' . $css_path . '">' . LF;
|
||||
?>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<p>
|
||||
<?php if (isset($_SESSION['id'])) { ?>
|
||||
<?= ($_SESSION['type'] === 'approved') ? '<span title="Compte approuvé">👤 </span>' : '<span title="Compte de test">⏳ </span>' ?><strong><?= $_SESSION['display-username'] ?></strong> <a class="auth" href="<?= CONF['common']['prefix'] ?>/auth/logout">Se déconnecter</a>
|
||||
<?php } else { ?>
|
||||
<span aria-hidden="true">👻 </span><em>Anonyme</em> <a class="auth" href="<?= redirUrl('auth/login') ?>">Se connecter</a>
|
||||
<?php } ?>
|
||||
</p>
|
||||
<nav>
|
||||
<?php
|
||||
foreach (TITLES_LINEAGE as $id => $title) {
|
||||
$lastTitle = (TITLES_LINEAGE[array_key_last(TITLES_LINEAGE)] === $title);
|
||||
echo '<ul><li>' . ($lastTitle ? '<h1>' : '') . '<a' . (($id === 0) ? ' class="niver"' : '') . ' href="' . CONF['common']['prefix'] . ($lastTitle ? '/' . PAGE_URL : '/' . implode('/', array_slice(PAGE_LINEAGE, 0, $id)) . (($lastTitle OR $id === 0) ? '' : '/')) . '">' . $title . '</a>' . ($lastTitle ? '</h1>' : '') . LF;
|
||||
}
|
||||
echo str_repeat('</li></ul>', count(TITLES_LINEAGE));
|
||||
?>
|
||||
|
||||
</nav>
|
||||
</header>
|
||||
<main>
|
||||
<?php
|
||||
|
||||
require 'pg-view/' . PAGE_ADDRESS . '.php';
|
||||
|
||||
if ($_POST === [] AND PAGE_METADATA['require-login'] ?? true !== false AND !isset($_SESSION['id']) AND PAGE_TERMINAL)
|
||||
echo '<p>Ce formulaire ne sera pas accepté car il faut <a class="auth" href="' . redirUrl('auth/login') . '">se connecter</a> avant.</p>';
|
||||
|
||||
displayFinalMessage($data);
|
||||
|
||||
?>
|
||||
</main>
|
||||
<footer>
|
||||
<small><a rel="external" href="https://code.antopie.org/niver/niver" class="niver">Code source</a> sous <abbr title="Cooperative Nonviolent Public License No Attribution version 7 ou plus">CNPL-NAv7+</abbr>.</small>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in a new issue