Direct zone file edition through <textarea>
This commit is contained in:
parent
95095ee6ee
commit
e3f358a62c
12 changed files with 217 additions and 34 deletions
|
@ -23,6 +23,7 @@ Niver is a set of 3 network services:
|
||||||
### Nameserver (`ns`)
|
### Nameserver (`ns`)
|
||||||
|
|
||||||
* Host a zone on the server
|
* Host a zone on the server
|
||||||
|
* Zone file edition through `<textarea>`
|
||||||
* Dedicated forms to set/unset `A`, `AAAA`, `NS`, `TXT`, `CAA`, `SRV`, `MX`, `SRV`, `SSHFP`, `TLSA`, `CNAME`, `DNAME` and `LOC` records
|
* Dedicated forms to set/unset `A`, `AAAA`, `NS`, `TXT`, `CAA`, `SRV`, `MX`, `SRV`, `SSHFP`, `TLSA`, `CNAME`, `DNAME` and `LOC` records
|
||||||
* Display your records or the full zone file
|
* Display your records or the full zone file
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,9 @@ knot_zones_path = "/srv/niver/ns"
|
||||||
servers[] = "ns1.niver.test."
|
servers[] = "ns1.niver.test."
|
||||||
servers[] = "ns2.niver.test."
|
servers[] = "ns2.niver.test."
|
||||||
kdig_path = "/usr/bin/kdig"
|
kdig_path = "/usr/bin/kdig"
|
||||||
|
kzonecheck_path = "/usr/bin/kzonecheck"
|
||||||
|
; @ must be replaced by a dot
|
||||||
|
public_soa_email = "hostmaster.niver.invalid."
|
||||||
|
|
||||||
[ht]
|
[ht]
|
||||||
enabled = true
|
enabled = true
|
||||||
|
|
|
@ -2,7 +2,7 @@ form {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
input, select {
|
input, select, textarea {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
margin: 0.3rem;
|
margin: 0.3rem;
|
||||||
|
@ -52,3 +52,10 @@ fieldset {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-color: var(--svc-color, --foreground-color);
|
border-color: var(--svc-color, --foreground-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
background-color: var(--background-color);
|
||||||
|
color: var(--foreground-color);
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
19
css/main.css
19
css/main.css
|
@ -33,20 +33,17 @@ h2 {
|
||||||
font-size: 1.3rem;
|
font-size: 1.3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
header, main > *:not(table, pre), footer {
|
header, main > *:not(table, pre, form), form > *:not(textarea), footer {
|
||||||
max-width: 40rem;
|
max-width: 40rem;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
main > nav {
|
main > nav {
|
||||||
max-width: 30rem;
|
max-width: 30rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
header, main > *, footer {
|
header, footer {
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 0.8rem;
|
margin-top: 0.8rem;
|
||||||
}
|
}
|
||||||
|
@ -77,18 +74,16 @@ code {
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
text-decoration: underline var(--svc-color) 0.2em;
|
|
||||||
color: var(--foreground-color);
|
color: var(--foreground-color);
|
||||||
|
text-decoration: underline var(--svc-color) 0.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
text-decoration: underline var(--svc-color) 0.25em;
|
text-decoration-thickness: 0.25em;
|
||||||
color: var(--foreground-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a:active {
|
a:active {
|
||||||
text-decoration: underline var(--svc-color) 0.35em;
|
text-decoration-thickness: 0.35em;
|
||||||
color: var(--foreground-color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a[rel=help]:before {
|
a[rel=help]:before {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$final_message = null;
|
$final_message = NULL;
|
||||||
|
|
||||||
function output($code, $msg = '', $logs = ['']) {
|
function output($code, $msg = '', $logs = ['']) {
|
||||||
global $final_message;
|
global $final_message;
|
||||||
|
|
25
fn/ns.php
25
fn/ns.php
|
@ -1,5 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
define('SOA_VALUES', [
|
||||||
|
'ttl' => 10800,
|
||||||
|
'email' => CONF['ns']['public_soa_email'],
|
||||||
|
'refresh' => 10800,
|
||||||
|
'retry' => 3600,
|
||||||
|
'expire' => 3628800,
|
||||||
|
'negative' => 10800,
|
||||||
|
]);
|
||||||
|
|
||||||
|
define('MIN_TTL', 300);
|
||||||
|
define('DEFAULT_TTL', 10800);
|
||||||
|
define('MAX_TTL', 1728000);
|
||||||
|
|
||||||
|
define('ALLOWED_TYPES', ['AAAA', 'A', 'TXT', 'SRV', 'MX', 'SVCB', 'HTTPS', 'NS', 'DS', 'CAA', 'CNAME', 'DNAME', 'LOC', 'SSHFP', 'TLSA']);
|
||||||
|
|
||||||
|
define('ZONE_MAX_CHARACTERS', 10000);
|
||||||
|
|
||||||
function nsCommonRequirements() {
|
function nsCommonRequirements() {
|
||||||
return (isset($_POST['action'])
|
return (isset($_POST['action'])
|
||||||
AND isset($_POST['zone'])
|
AND isset($_POST['zone'])
|
||||||
|
@ -12,15 +29,17 @@ function nsCommonRequirements() {
|
||||||
function nsParseCommonRequirements() {
|
function nsParseCommonRequirements() {
|
||||||
nsCheckZonePossession($_POST['zone']);
|
nsCheckZonePossession($_POST['zone']);
|
||||||
|
|
||||||
if (($_POST['subdomain'] === "") OR ($_POST['subdomain'] === "@"))
|
if (($_POST['subdomain'] === '') OR ($_POST['subdomain'] === '@'))
|
||||||
$values['domain'] = $_POST['zone'];
|
$values['domain'] = $_POST['zone'];
|
||||||
else
|
else
|
||||||
$values['domain'] = formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['zone']);
|
$values['domain'] = formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['zone']);
|
||||||
|
|
||||||
$values['ttl'] = $_POST['ttl-value'] * $_POST['ttl-multiplier'];
|
$values['ttl'] = $_POST['ttl-value'] * $_POST['ttl-multiplier'];
|
||||||
|
|
||||||
if (!($values['ttl'] >= 300 AND $values['ttl'] <= 432000))
|
if ($values['ttl'] < MIN_TTL)
|
||||||
output(403, 'Le TTL doit être compris entre 5 minutes et 5 jours (entre 300 et 432000 secondes).');
|
output(403, 'Les TTLs inférieurs à ' . MIN_TTL . ' secondes ne sont pas autorisés.');
|
||||||
|
if ($values['ttl'] > MAX_TTL)
|
||||||
|
output(403, 'Les TTLs supérieurs à ' . MAX_TTL . ' secondes ne sont pas autorisés.');
|
||||||
|
|
||||||
return $values;
|
return $values;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ if (isset($_SESSION['username']))
|
||||||
<div>
|
<div>
|
||||||
<label for="ttl-value">Valeur</label>
|
<label for="ttl-value">Valeur</label>
|
||||||
<br>
|
<br>
|
||||||
<input required="" id="ttl-value" list="ttls" name="ttl-value" size="6" type="number" min="1" max="432000" value="10800" placeholder="10800">
|
<input required="" id="ttl-value" list="ttls" name="ttl-value" size="6" type="number" min="1" max="432000" value="<?= DEFAULT_TTL ?>" placeholder="<?= DEFAULT_TTL ?>">
|
||||||
<datalist id="ttls">
|
<datalist id="ttls">
|
||||||
<option value="900">
|
<option value="900">
|
||||||
<option value="1800">
|
<option value="1800">
|
||||||
|
|
|
@ -80,6 +80,11 @@ define('PAGES', [
|
||||||
'title' => 'Afficher les données',
|
'title' => 'Afficher les données',
|
||||||
'description' => 'Afficher le contenu de la zone',
|
'description' => 'Afficher le contenu de la zone',
|
||||||
],
|
],
|
||||||
|
'edit' => [
|
||||||
|
'title' => 'Modifier une zone',
|
||||||
|
'description' => 'Éditer un fichier de zone',
|
||||||
|
'tokens_account_cost' => 300,
|
||||||
|
],
|
||||||
'ip' => [
|
'ip' => [
|
||||||
'title' => 'Enregistrements A et AAAA',
|
'title' => 'Enregistrements A et AAAA',
|
||||||
'description' => 'Indiquer l\'adresse IP d\'un domaine',
|
'description' => 'Indiquer l\'adresse IP d\'un domaine',
|
||||||
|
|
142
pages/ns/edit.php
Normal file
142
pages/ns/edit.php
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
if (processForm() AND isset($_POST['zone-content'])) { // Update zone
|
||||||
|
nsCheckZonePossession($_POST['zone']);
|
||||||
|
|
||||||
|
// Get current SOA record
|
||||||
|
$current_zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
|
||||||
|
if ($current_zone_content === false)
|
||||||
|
output(500, 'Unable to read zone file.');
|
||||||
|
if (preg_match('/^(?<soa>' . preg_quote($_POST['zone']) . '[\t ]+[0-9]{1,16}[\t ]+SOA[\t ]+.+)$/m', $current_zone_content, $matches) !== 1)
|
||||||
|
output(500, 'Unable to get current serial from zone file.');
|
||||||
|
|
||||||
|
// Generate new zone content
|
||||||
|
$new_zone_content = $matches['soa'] . "\n";
|
||||||
|
if (strlen($_POST['zone-content']) > ZONE_MAX_CHARACTERS)
|
||||||
|
output(403, 'La zone n\'est pas autorisée à dépasser ' . ZONE_MAX_CHARACTERS . ' caractères.');
|
||||||
|
foreach (explode("\r\n", $_POST['zone-content']) as $line) {
|
||||||
|
if ($line === '') continue;
|
||||||
|
if (preg_match('/^(?<domain>[a-z0-9@._-]+)(?:[\t ]+(?<ttl>[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?<type>[A-Z]{1,16})[\t ]+(?<value>.+)$/', $line, $matches) !== 1)
|
||||||
|
output(403, 'La zone est mal formatée (selon Niver).');
|
||||||
|
if (in_array($matches['type'], ALLOWED_TYPES, true) !== true)
|
||||||
|
output(403, 'Le type <code>' . $matches['type'] . '</code> n\'est pas autorisé.');
|
||||||
|
if ($matches['ttl'] !== '' AND $matches['ttl'] < MIN_TTL)
|
||||||
|
output(403, 'Les TTLs inférieurs à ' . MIN_TTL . ' secondes ne sont pas autorisés.');
|
||||||
|
if ($matches['ttl'] !== '' AND $matches['ttl'] > MAX_TTL)
|
||||||
|
output(403, 'Les TTLs supérieurs à ' . MAX_TTL . ' secondes ne sont pas autorisés.');
|
||||||
|
$new_zone_content .= $matches['domain'] . ' ' . (($matches['ttl'] === '') ? DEFAULT_TTL : $matches['ttl']) . ' ' . $matches['type'] . ' ' . $matches['value'] . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the zone content to kzonecheck's stdin
|
||||||
|
$process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . $_POST['zone'] . ' --dnssec off -', [0 => ['pipe', 'r']], $pipes);
|
||||||
|
if (is_resource($process) !== true)
|
||||||
|
output(500, 'Can\'t spawn kzonecheck.');
|
||||||
|
fwrite($pipes[0], $new_zone_content);
|
||||||
|
fclose($pipes[0]);
|
||||||
|
if (proc_close($process) !== 0)
|
||||||
|
output(403, 'Le contenu de zone envoyé n\'est pas valide (selon <code>kzonecheck</code>).');
|
||||||
|
|
||||||
|
ratelimit();
|
||||||
|
|
||||||
|
exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 10 zone-freeze ' . $_POST['zone'], $output, $return_code);
|
||||||
|
if ($return_code !== 0)
|
||||||
|
output(500, 'Failed to freeze zone file.', $output);
|
||||||
|
|
||||||
|
exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 10 zone-flush ' . $_POST['zone'], $output, $return_code);
|
||||||
|
if ($return_code !== 0)
|
||||||
|
output(500, 'Failed to flush zone file.', $output);
|
||||||
|
|
||||||
|
if (file_put_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone', $new_zone_content) === false)
|
||||||
|
output(500, 'Failed to write zone file.');
|
||||||
|
|
||||||
|
exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 10 zone-reload ' . $_POST['zone'], $output, $return_code);
|
||||||
|
if ($return_code !== 0)
|
||||||
|
output(500, 'Failed to reload zone file.', $output);
|
||||||
|
|
||||||
|
exec(CONF['dns']['knotc_path'] . ' --blocking --timeout 10 zone-thaw ' . $_POST['zone'], $output, $return_code);
|
||||||
|
if ($return_code !== 0)
|
||||||
|
output(500, 'Failed to thaw zone file.', $output);
|
||||||
|
|
||||||
|
usleep(1000000);
|
||||||
|
|
||||||
|
output(200, 'La zone a été mise à jour.');
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<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['username']))
|
||||||
|
foreach (nsListUserZones($_SESSION['username']) as $zone)
|
||||||
|
echo ' <option value="' . $zone . '">' . $zone . '</option>' . "\n";
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
<br>
|
||||||
|
<input type="submit" value="Afficher">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?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("\n", $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 ]+.+$/', $zone_line, $matches)) {
|
||||||
|
if (in_array($matches['type'], ALLOWED_TYPES, true) !== true)
|
||||||
|
continue;
|
||||||
|
$displayed_zone_content .= $zone_line . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$displayed_zone_content .= "\n";
|
||||||
|
|
||||||
|
?>
|
||||||
|
<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, "\n") + 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><?= DEFAULT_TTL ?></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><?= MIN_TTL ?></code> et <code><?= MAX_TTL ?></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>
|
|
@ -50,7 +50,7 @@ if (processForm()) {
|
||||||
if (str_starts_with($zoneLine, ';')) continue; // Ignore comments
|
if (str_starts_with($zoneLine, ';')) continue; // Ignore comments
|
||||||
if (empty($zoneLine)) continue;
|
if (empty($zoneLine)) continue;
|
||||||
$elements = preg_split("#[\t ]+#", $zoneLine, 4);
|
$elements = preg_split("#[\t ]+#", $zoneLine, 4);
|
||||||
if (!in_array($elements[2], ['CAA', 'A', 'AAAA', 'MX', 'NS', 'SRV', 'SSHFP', 'TLSA', 'TXT'], true)) continue; // Ignore records generated by Knot
|
if (!in_array($elements[2], ALLOWED_TYPES, true)) continue; // Ignore records generated by Knot
|
||||||
echo ' <tr>';
|
echo ' <tr>';
|
||||||
foreach ($elements as $element)
|
foreach ($elements as $element)
|
||||||
echo ' <td><code>' . htmlspecialchars($element) . '</code></td>';
|
echo ' <td><code>' . htmlspecialchars($element) . '</code></td>';
|
||||||
|
@ -61,15 +61,10 @@ if (processForm()) {
|
||||||
|
|
||||||
if ($_POST['print'] === 'ds') {
|
if ($_POST['print'] === 'ds') {
|
||||||
|
|
||||||
$found = preg_match("#\n" . preg_quote($_POST['zone']) . "\s+0\s+CDS\s+([0-9]{1,5})\s+([0-9]{1,2})\s+([0-9])\s+([0-9A-F]{64})\n#", $zoneContent, $matches);
|
$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})$/m', $zoneContent, $matches);
|
||||||
if ($found !== 1)
|
if ($found !== 1)
|
||||||
output(500, 'Unable to get public key record from zone file.');
|
output(500, 'Unable to get public key record from zone file.');
|
||||||
|
|
||||||
$tag = $matches[1];
|
|
||||||
$algo = $matches[2];
|
|
||||||
$digestType = $matches[3];
|
|
||||||
$digest = $matches[4];
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
|
@ -79,19 +74,19 @@ if (processForm()) {
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Tag</dt>
|
<dt>Tag</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<code><?= $tag ?></code>
|
<code><?= $matches['tag'] ?></code>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Algorithme</dt>
|
<dt>Algorithme</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<code><?= $algo ?></code><?php if ($algo === "15") echo " (Ed25519)"; ?>
|
<code><?= $matches['algo'] ?></code><?php if ($matches['algo'] === '15') echo ' (Ed25519)'; ?>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Type de condensat</dt>
|
<dt>Type de condensat</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<code><?= $digestType ?></code><?php if ($digestType === "2") echo " (SHA-256)"; ?>
|
<code><?= $matches['digest_type'] ?></code><?php if ($matches['digest_type'] === '2') echo ' (SHA-256)'; ?>
|
||||||
</dd>
|
</dd>
|
||||||
<dt>Condensat</dt>
|
<dt>Condensat</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<code><?= $digest ?></code>
|
<code><?= $matches['digest'] ?></code>
|
||||||
</dd>
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ if (processForm()) {
|
||||||
checkAbsoluteDomainFormat($parentAuthoritative);
|
checkAbsoluteDomainFormat($parentAuthoritative);
|
||||||
|
|
||||||
exec(CONF['ns']['kdig_path'] . ' ' . $_POST['domain'] . ' NS @' . $parentAuthoritatives[0] . ' +noidn', $results);
|
exec(CONF['ns']['kdig_path'] . ' ' . $_POST['domain'] . ' NS @' . $parentAuthoritatives[0] . ' +noidn', $results);
|
||||||
if (preg_match('/\n' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+([0-9a-f]{8})-([0-9a-f]{32})\.auth-owner.+\n/', implode("\n", $results), $matches) !== 1)
|
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})\.auth-owner.+$/m', implode("\n", $results), $matches) !== 1)
|
||||||
output(403, 'Enregistrement d\'authentification introuvable');
|
output(403, 'Enregistrement d\'authentification introuvable');
|
||||||
|
|
||||||
checkAuthToken($matches[1], $matches[2]);
|
checkAuthToken($matches['salt'], $matches['hash']);
|
||||||
|
|
||||||
rateLimit();
|
rateLimit();
|
||||||
|
|
||||||
|
@ -26,7 +26,18 @@ if (processForm()) {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$knotZonePath = CONF['ns']['knot_zones_path'] . "/" . $_POST['domain'] . "zone";
|
$knotZonePath = CONF['ns']['knot_zones_path'] . "/" . $_POST['domain'] . "zone";
|
||||||
$knotZone = $_POST['domain'] . ' 3600 SOA ' . CONF['ns']['servers'][0] . ' admin.niver.test. 1 21600 7200 3628800 3600' . "\n";
|
$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'],
|
||||||
|
]) . "\n";
|
||||||
foreach (CONF['ns']['servers'] as $server)
|
foreach (CONF['ns']['servers'] as $server)
|
||||||
$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . "\n";
|
$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . "\n";
|
||||||
if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true)
|
if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true)
|
||||||
|
|
|
@ -117,11 +117,16 @@ if (in_array(SERVICE, ['reg', 'ns', 'ht']) AND CONF[SERVICE]['enabled'] !== true
|
||||||
if (empty($_POST) === false AND (isset($_SERVER['HTTP_SEC_FETCH_SITE']) !== true OR $_SERVER['HTTP_SEC_FETCH_SITE'] !== "same-origin"))
|
if (empty($_POST) === false AND (isset($_SERVER['HTTP_SEC_FETCH_SITE']) !== true OR $_SERVER['HTTP_SEC_FETCH_SITE'] !== "same-origin"))
|
||||||
output(403, 'Anti-<abbr title="Cross-Site Request Forgery">CSRF</abbr> verification failed ! (Wrong or unset <code>Sec-Fetch-Site</code> HTTP header)');
|
output(403, 'Anti-<abbr title="Cross-Site Request Forgery">CSRF</abbr> verification failed ! (Wrong or unset <code>Sec-Fetch-Site</code> HTTP header)');
|
||||||
|
|
||||||
|
function displayFinalMessage() {
|
||||||
|
global $final_message;
|
||||||
|
echo $final_message ?? '';
|
||||||
|
$final_message = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
function executePage() {
|
function executePage() {
|
||||||
require "pages/" . PAGE_ADDRESS . ".php";
|
require "pages/" . PAGE_ADDRESS . ".php";
|
||||||
|
|
||||||
global $final_message;
|
displayFinalMessage();
|
||||||
echo $final_message ?? '';
|
|
||||||
?>
|
?>
|
||||||
</main>
|
</main>
|
||||||
<footer>
|
<footer>
|
||||||
|
|
Loading…
Reference in a new issue