Add reg/edit.php and regParseRecord()

This commit is contained in:
Miraty 2023-07-31 01:13:06 +02:00
parent 40e67b0c0c
commit 2570d09ba9
16 changed files with 899 additions and 634 deletions

View File

@ -70,11 +70,11 @@ function knotcZoneExec(string $zone, array $cmd, string $action = NULL): void {
}
function checkIpFormat(string $ip): string {
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))
return 'A';
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))
return 'AAAA';
output(403, _('IP address malformed.'));
return match ($ip) {
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) => 'AAAA',
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) => 'A',
default => output(403, _('IP address malformed.')),
};
}
function checkAbsoluteDomainFormat(string $domain): void { // If the domain must end with a dot

View File

@ -1,6 +1,6 @@
<?php declare(strict_types=1);
const SOA_VALUES = [
const NS_SOA_VALUES = [
'ttl' => 10800,
'email' => CONF['ns']['public_soa_email'],
'refresh' => 10800,
@ -9,15 +9,15 @@ const SOA_VALUES = [
'negative' => 10800,
];
const MIN_TTL = 300;
const DEFAULT_TTL = 10800;
const MAX_TTL = 1728000;
const NS_MIN_TTL = 300;
const NS_DEFAULT_TTL = 10800;
const NS_MAX_TTL = 1728000;
const ALLOWED_TYPES = ['AAAA', 'A', 'TXT', 'SRV', 'MX', 'SSHFP', 'TLSA', 'NS', 'DS', 'CSYNC', 'CAA', 'CNAME', 'DNAME', 'SVCB', 'HTTPS', 'LOC'];
const NS_ALLOWED_TYPES = ['AAAA', 'A', 'TXT', 'SRV', 'MX', 'SSHFP', 'TLSA', 'NS', 'DS', 'CSYNC', 'CAA', 'CNAME', 'DNAME', 'SVCB', 'HTTPS', 'LOC'];
const ZONE_MAX_CHARACTERS = 10000;
const NS_TEXTAREA_MAX_CHARACTERS = 10000;
const SYNC_TTL = 10800;
const NS_SYNC_TTL = 10800;
function nsParseCommonRequirements(): array {
nsCheckZonePossession($_POST['zone']);
@ -29,10 +29,10 @@ function nsParseCommonRequirements(): array {
$values['ttl'] = intval($_POST['ttl-value'] * $_POST['ttl-multiplier']);
if ($values['ttl'] < MIN_TTL)
output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), MIN_TTL));
if ($values['ttl'] > MAX_TTL)
output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), MAX_TTL));
if ($values['ttl'] < NS_MIN_TTL)
output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), NS_MIN_TTL));
if ($values['ttl'] > NS_MAX_TTL)
output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), NS_MAX_TTL));
return $values;
}

View File

@ -2,6 +2,9 @@
const SUBDOMAIN_REGEX = '^(?!\-)(?!..\-\-)[a-z0-9-]{4,63}(?<!\-)$';
const REG_TEXTAREA_MAX_CHARACTERS = 5000;
const REG_ALLOWED_TYPES = ['NS', 'DS', 'AAAA', 'A'];
function regListUserDomains(): array {
if (isset($_SESSION['id']))
return query('select', 'registry', ['username' => $_SESSION['id']], 'domain');
@ -13,14 +16,16 @@ function regCheckDomainPossession(string $domain): void {
output(403, 'You don\'t own this domain on the registry.');
}
function regStripDomain(string $domain, string $content): string {
return preg_replace('/^(?:[a-z0-9._-]+\.)?' . preg_quote($domain, '/') . '[\t ]+.+$/Dm', '', $content);
}
function regDeleteDomain(string $domain, string $user_id): void {
// Delete domain from registry file
$path = CONF['reg']['suffixes_path'] . '/' . regParseDomain($domain)['suffix'] . 'zone';
$content = file_get_contents($path);
if ($content === false)
if (($content = file_get_contents($path)) === false)
output(500, 'Failed to read current registry file.');
$content = preg_replace('/^(?:[a-z0-9._-]+\.)?' . preg_quote($domain, '/') . '[\t ]+.+$/Dm', '', $content);
if (file_put_contents($path, $content) === false)
if (file_put_contents($path, regStripDomain($domain, $content)) === false)
output(500, 'Failed to write new registry file.');
try {
@ -59,3 +64,53 @@ function regParseDomain(string $domain): array {
'suffix' => $suffix,
];
}
function regParseRecord(string $domain, array $record): array {
checkAbsoluteDomainFormat($record['domain']);
if ($record['domain'] !== $_POST['domain']) {
if ($record['type'] !== 'ip')
output(403, _('You can only set a NS/DS record for an apex domain.'));
else if (!str_ends_with($record['domain'], '.' . $domain))
output(403, _('You can\'t set a record for another domain.'));
}
$new_rec = [
$record['domain'],
CONF['reg']['ttl'],
$record['type'],
];
if ($record['type'] === 'DS') {
if (!in_array($record['algo'], ['8', '13', '14', '15', '16'], true))
output(403, 'Wrong value for <code>algo</code>.');
if ((preg_match('/^[0-9]{1,6}$/D', $record['keytag'])) !== 1 OR !($record['keytag'] >= 1) OR !($record['keytag'] <= 65535))
output(403, 'Wrong value for <code>keytag</code>.');
if ($record['dt'] !== '2' AND $record['dt'] !== '4')
output(403, 'Wrong value for <code>dt</code>.');
if (preg_match('/^(?:[0-9a-fA-F]{64}|[0-9a-fA-F]{96})$/D', $record['key']) !== 1)
output(403, 'Wrong value for <code>key</code>.');
return [
...$new_rec,
$record['keytag'],
$record['algo'],
$record['dt'],
$record['key'],
];
}
if ($record['type'] === 'NS')
return [
...$new_rec,
formatAbsoluteDomain($record['ns']),
];
if ($record['type'] === 'ip')
return [
$record['domain'],
CONF['reg']['ttl'],
checkIpFormat($record['ip']),
$record['ip'],
];
}

View File

@ -204,8 +204,8 @@ function testNs(string $domain): void {
exit('Error: /ns/caa: CAA record not set' . LF);
curlTest('/ns/edit', [
'zone' => $domain,
'zone-content' => 'aaaa.' . $domain . ' 3600 AAAA ' . CONF['ht']['ipv6_address'] . "\r\n"
'domain' => $domain,
'records' => 'aaaa.' . $domain . ' 3600 AAAA ' . CONF['ht']['ipv6_address'] . "\r\n"
. '@ 86400 NS ' . CONF['ns']['servers'][0] . "\r\n",
]);
exescape([

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -63,6 +63,11 @@ define('PAGES', [
'description' => _('Print every record related to a domain and served by the registry'),
'tokens_account_cost' => 60,
],
'edit' => [
'title' => _('Edit records'),
'description' => _('Set registry records to delegate a domain to chosen name servers'),
'tokens_account_cost' => 900,
],
'ns' => [
'title' => sprintf(_('%s records'), '<abbr title="Name Server">NS</abbr>'),
'description' => sprintf(_('Indicate the name servers of a %s subdomain'), '<code>' . key(CONF['reg']['suffixes']) . '</code>'),

View File

@ -1,60 +1,62 @@
<?php declare(strict_types=1);
nsCheckZonePossession($_POST['zone']);
nsCheckZonePossession($_POST['domain']);
if (isset($_POST['zone-content'])) { // Update zone
$path = CONF['ns']['knot_zones_path'] . '/' . $_POST['domain'] . 'zone';
if (isset($_POST['records'])) {
// Get current SOA record
$current_zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
$current_zone_content = file_get_contents($path);
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 ]+.+)$/Dm', $current_zone_content, $matches) !== 1)
if (preg_match('/^(?<soa>' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,16}[\t ]+SOA[\t ]+.+)$/Dm', $current_zone_content, $matches) !== 1)
output(500, 'Unable to get current SOA record from zone file.');
// Generate new zone content
// Generate new content
$new_zone_content = $matches['soa'] . LF;
if (strlen($_POST['zone-content']) > ZONE_MAX_CHARACTERS)
output(403, sprintf(_('The zone is limited to %s characters.'), ZONE_MAX_CHARACTERS));
foreach (explode("\r\n", $_POST['zone-content']) as $line) {
if ($line === '') continue;
if (preg_match('/^(?<domain>[a-z0-9@._-]{1,256})(?:[\t ]+(?<ttl>[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?<type>[A-Z]{1,16})[\t ]+(?<value>.+)$/D', $line, $matches) !== 1)
output(403, _('The following line does not match the expected format: ') . '<code>' . htmlspecialchars($line) . '</code>');
if (in_array($matches['type'], ALLOWED_TYPES, true) !== true)
if (strlen($_POST['records']) > NS_TEXTAREA_MAX_CHARACTERS)
output(403, sprintf(_('The zone is limited to %s characters.'), NS_TEXTAREA_MAX_CHARACTERS));
foreach (explode("\r\n", $_POST['records']) as $record) {
if ($record === '') continue;
if (preg_match('/^(?<domain>[a-z0-9@._-]{1,256})(?:[\t ]+(?<ttl>[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?<type>[A-Z]{1,16})[\t ]+(?<value>.+)$/D', $record, $matches) !== 1)
output(403, _('The following line does not match the expected format: ') . '<code>' . htmlspecialchars($record) . '</code>');
if (in_array($matches['type'], NS_ALLOWED_TYPES, true) !== true)
output(403, sprintf(_('The %s type is not allowed.'), '<code>' . $matches['type'] . '</code>'));
if ($matches['ttl'] !== '' AND $matches['ttl'] < MIN_TTL)
output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), MIN_TTL));
if ($matches['ttl'] !== '' AND $matches['ttl'] > MAX_TTL)
output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), MAX_TTL));
$new_zone_content .= $matches['domain'] . ' ' . (($matches['ttl'] === '') ? DEFAULT_TTL : $matches['ttl']) . ' ' . $matches['type'] . ' ' . $matches['value'] . LF;
if ($matches['ttl'] !== '' AND $matches['ttl'] < NS_MIN_TTL)
output(403, sprintf(_('TTLs shorter than %s seconds are forbidden.'), NS_MIN_TTL));
if ($matches['ttl'] !== '' AND $matches['ttl'] > NS_MAX_TTL)
output(403, sprintf(_('TTLs longer than %s seconds are forbidden.'), NS_MAX_TTL));
$new_zone_content .= $matches['domain'] . ' ' . (($matches['ttl'] === '') ? NS_DEFAULT_TTL : $matches['ttl']) . ' ' . $matches['type'] . ' ' . $matches['value'] . LF;
}
// Send the zone content to kzonecheck's stdin
$process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . $_POST['zone'] . ' --dnssec off -', [0 => ['pipe', 'r']], $pipes);
$process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . escapeshellarg($_POST['domain']) . ' --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, _('Sent zone content is not correct (according to <code>kzonecheck</code>).'));
output(403, _('Sent content is not correct (according to <code>kzonecheck</code>).'));
ratelimit();
knotc(['zone-freeze', $_POST['zone']], $output, $return_code);
knotc(['zone-freeze', $_POST['domain']], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to freeze zone file.', $output);
knotc(['zone-flush', $_POST['zone']], $output, $return_code);
knotc(['zone-flush', $_POST['domain']], $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)
if (file_put_contents($path, $new_zone_content) === false)
output(500, 'Failed to write zone file.');
knotc(['zone-reload', $_POST['zone']], $output, $return_code);
knotc(['zone-reload', $_POST['domain']], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to reload zone file.', $output);
knotc(['zone-thaw', $_POST['zone']], $output, $return_code);
knotc(['zone-thaw', $_POST['domain']], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to thaw zone file.', $output);
@ -63,18 +65,17 @@ if (isset($_POST['zone-content'])) { // Update zone
// Display zone
$zone_content = file_get_contents(CONF['ns']['knot_zones_path'] . '/' . $_POST['zone'] . 'zone');
if ($zone_content === false)
if (($records = file_get_contents($path)) === false)
output(500, 'Unable to read zone file.');
$data['zone_content'] = '';
foreach (explode(LF, $zone_content) as $zone_line) {
$data['records'] = '';
foreach (explode(LF, $records) 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)
if (preg_match('/^(?:(?:[a-z0-9_-]{1,63}\.){1,127})?' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?<type>[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) {
if (in_array($matches['type'], NS_ALLOWED_TYPES, true) !== true)
continue;
$data['zone_content'] .= $zone_line . LF;
$data['records'] .= $zone_line . LF;
}
}
$data['zone_content'] .= LF;
$data['records'] .= LF;

View File

@ -41,15 +41,15 @@ insert('zones', [
$knotZonePath = CONF['ns']['knot_zones_path'] . '/' . $_POST['domain'] . 'zone';
$knotZone = implode(' ', [
$_POST['domain'],
SOA_VALUES['ttl'],
NS_SOA_VALUES['ttl'],
'SOA',
CONF['ns']['servers'][0],
SOA_VALUES['email'],
NS_SOA_VALUES['email'],
1,
SOA_VALUES['refresh'],
SOA_VALUES['retry'],
SOA_VALUES['expire'],
SOA_VALUES['negative'],
NS_SOA_VALUES['refresh'],
NS_SOA_VALUES['retry'],
NS_SOA_VALUES['expire'],
NS_SOA_VALUES['negative'],
]) . LF;
foreach (CONF['ns']['servers'] as $server)
$knotZone .= $_POST['domain'] . ' 86400 NS ' . $server . LF;

View File

@ -1,30 +1,12 @@
<?php declare(strict_types=1);
if (!in_array($_POST['algo'], ['8', '13', '14', '15', '16'], true))
output(403, 'Wrong value for <code>algo</code>.');
$_POST['keytag'] = intval($_POST['keytag']);
if ((preg_match('/^[0-9]{1,6}$/D', $_POST['keytag'])) !== 1 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>.');
if (preg_match('/^(?:[0-9a-fA-F]{64}|[0-9a-fA-F]{96})$/D', $_POST['key']) !== 1)
output(403, 'Wrong value for <code>key</code>.');
regCheckDomainPossession($_POST['domain']);
rateLimit();
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], [
$_POST['domain'],
CONF['reg']['ttl'],
'DS',
$_POST['keytag'],
$_POST['algo'],
$_POST['dt'],
$_POST['key']
]);
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], regParseRecord($_POST['domain'], [
'type' => 'DS',
...$_POST,
]));
output(200, _('Modification done.'));

97
pg-act/reg/edit.php Normal file
View File

@ -0,0 +1,97 @@
<?php declare(strict_types=1);
regCheckDomainPossession($_POST['domain']);
$suffix = regParseDomain($_POST['domain'])['suffix'];
$path = CONF['reg']['suffixes_path'] . '/' . $suffix . 'zone';
if (isset($_POST['records'])) {
// Generate new content
$new_records = '';
if (strlen($_POST['records']) > REG_TEXTAREA_MAX_CHARACTERS)
output(403, sprintf(_('The zone is limited to %s characters.'), REG_TEXTAREA_MAX_CHARACTERS));
foreach (explode("\r\n", $_POST['records']) as $record) {
if ($record === '') continue;
if (preg_match('/^(?<domain>[a-z0-9@._-]{1,256})(?:[\t ]+(?<ttl>[0-9]{1,16}))?(?:[\t ]+IN)?[\t ]+(?<type>[A-Z]{1,16})[\t ]+(?<value>.+)$/D', $record, $matches) !== 1)
output(403, _('The following line does not match the expected format: ') . '<code>' . htmlspecialchars($record) . '</code>');
if (in_array($matches['type'], REG_ALLOWED_TYPES, true) !== true)
output(403, sprintf(_('The %s type is not allowed.'), '<code>' . $matches['type'] . '</code>'));
if ($matches['type'] === 'DS' AND count($record_values = explode(' ', $matches['value'])) !== 4)
output(403, _('A DS record expects 4 arguments.'));
$new_records .= implode(' ', regParseRecord($_POST['domain'], [
'domain' => $matches['domain'],
'type' => match ($matches['type']) {
'NS', 'DS' => $matches['type'],
'AAAA', 'A' => 'ip',
default => output(403, sprintf(_('The %s type is not allowed.'), '<code>' . $matches['type'] . '</code>')),
},
...match ($matches['type']) {
'NS' => ['ns' => $matches['value']],
'AAAA', 'A' => ['ip' => $matches['value']],
'DS' => array_combine([
'keytag',
'algo',
'dt',
'key',
], $record_values),
},
])) . LF;
}
// Send the zone content to kzonecheck's stdin
$process = proc_open(CONF['ns']['kzonecheck_path'] . ' --origin ' . escapeshellarg($suffix) . ' --dnssec off -', [0 => ['pipe', 'r']], $pipes);
if (is_resource($process) !== true)
output(500, 'Can\'t spawn kzonecheck.');
$new = $suffix . ' 10800 SOA invalid. invalid. 0 21600 7200 3628800 3600' . LF . $suffix . ' 10800 NS invalid.' . LF . $new_records;
fwrite($pipes[0], $new);
fclose($pipes[0]);
if (proc_close($process) !== 0)
output(403, _('Sent content is not correct (according to <code>kzonecheck</code>).'));
ratelimit();
knotc(['zone-freeze', $suffix], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to freeze zone file.', $output);
knotc(['zone-flush', $suffix], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to flush zone file.', $output);
if (($zone_content = file_get_contents($path)) === false)
output(500, 'Unable to read zone file.');
$zone_content = regStripDomain($_POST['domain'], $zone_content);
if (file_put_contents($path, $zone_content . LF . $new_records) === false)
output(500, 'Failed to write zone file.');
knotc(['zone-reload', $suffix], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to reload zone file.', $output);
knotc(['zone-thaw', $suffix], $output, $return_code);
if ($return_code !== 0)
output(500, 'Failed to thaw zone file.', $output);
usleep(1000000);
}
// Display zone
if (($records = file_get_contents($path)) === false)
output(500, 'Unable to read zone file.');
$data['records'] = '';
foreach (explode(LF, $records) 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['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+(?<type>[A-Z]{1,16})[\t ]+.+$/D', $zone_line, $matches)) {
if (in_array($matches['type'], REG_ALLOWED_TYPES, true) !== true)
continue;
$data['records'] .= $zone_line . LF;
}
}
$data['records'] .= LF;

View File

@ -4,11 +4,10 @@ regCheckDomainPossession($_POST['domain']);
rateLimit();
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], [
formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['domain']),
CONF['reg']['ttl'],
checkIpFormat($_POST['ip']),
$_POST['ip']
]);
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], regParseRecord($_POST['domain'], [
'type' => 'ip',
'domain' => formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['domain']),
...$_POST,
]));
output(200, _('Modification done.'));

View File

@ -4,11 +4,9 @@ regCheckDomainPossession($_POST['domain']);
rateLimit();
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], [
$_POST['domain'],
CONF['reg']['ttl'],
'NS',
formatAbsoluteDomain($_POST['ns'])
]);
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], regParseRecord($_POST['domain'], [
'type' => 'NS',
...$_POST,
]));
output(200, _('Modification done.'));

View File

@ -1,12 +1,12 @@
<?php declare(strict_types=1); ?>
<form method="post">
<label for="zone"><?= _('Zone to be changed') ?></label>
<label for="domain"><?= _('Zone to be changed') ?></label>
<br>
<select required="" name="zone" id="zone">
<select required="" name="domain" id="domain">
<option value="" disabled="" selected="">-</option>
<?php
foreach (nsListUserZones() as $zone)
echo ' <option value="' . $zone . '">' . $zone . '</option>' . LF;
foreach (nsListUserZones() as $domain)
echo ' <option value="' . $domain . '">' . $domain . '</option>' . LF;
?>
</select>
<br>
@ -15,15 +15,15 @@ foreach (nsListUserZones() as $zone)
<?php
if (isset($data['zone_content'])) { // Display zone
if (isset($data['records'])) { // Display zone
?>
<form method="post">
<input type="hidden" name="zone" value="<?= $_POST['zone'] ?>">
<input type="hidden" name="domain" value="<?= $_POST['domain'] ?>">
<label for="zone-content"><?= sprintf(_('New content of the %s zone'), '<code><strong>' . $_POST['zone'] . '</strong></code>') ?></label>
<label for="zone-content"><?= sprintf(_('Authoritative records for %s'), '<code><strong>' . $_POST['domain'] . '</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>
<textarea id="records" name="records" wrap="off" rows="<?= substr_count($data['records'], LF) + 1 ?>"><?= htmlspecialchars($data['records']) ?></textarea>
<br>
<input type="submit" value="<?= _('Replace') ?>">
</form>
@ -38,21 +38,21 @@ displayFinalMessage($data);
<h2><?= _('Default values') ?></h2>
<p><?= sprintf(_('If the TTL is omitted, it will default to %s seconds.'), '<code><time datetime="PT' . DEFAULT_TTL . 'S">' . DEFAULT_TTL . '</time></code>') ?></p>
<p><?= sprintf(_('If the TTL is omitted, it will default to %s seconds.'), '<code><time datetime="PT' . NS_DEFAULT_TTL . 'S">' . NS_DEFAULT_TTL . '</time></code>') ?></p>
<p><?= _('Precising the class (<code>IN</code>) is optional.') ?></p>
<h2><?= _('Allowed values') ?></h2>
<p><?= sprintf(_('Submitted zone content is limited to %s characters.'), ZONE_MAX_CHARACTERS) ?></p>
<p><?= sprintf(_('Submitted field content is limited to %s characters.'), NS_TEXTAREA_MAX_CHARACTERS) ?></p>
<p><?= sprintf(_('TTLs must last between %1$s and %2$s seconds.'), '<code><time datetime="PT' . MIN_TTL . 'S">' . MIN_TTL . '</time></code>', '<code><time datetime="PT' . MAX_TTL . 'S">' . MAX_TTL . '</time></code>') ?></p>
<p><?= sprintf(_('TTLs must last between %1$s and %2$s seconds.'), '<code><time datetime="PT' . NS_MIN_TTL . 'S">' . NS_MIN_TTL . '</time></code>', '<code><time datetime="PT' . NS_MAX_TTL . 'S">' . NS_MAX_TTL . '</time></code>') ?></p>
<p><?= _('The only types that can be defined are:') ?></p>
<p><?= _('The only types that can be defined here are:') ?></p>
<ul>
<?php
foreach (ALLOWED_TYPES as $allowed_type)
foreach (NS_ALLOWED_TYPES as $allowed_type)
echo ' <li><code>' . $allowed_type . '</code></li>';
?>
</ul>

View File

@ -32,7 +32,7 @@ foreach ($user_zones as $zone)
<div>
<label for="ttl-value"><?= _('Value') ?></label>
<br>
<input required="" id="ttl-value" list="ttls" name="ttl-value" size="6" type="number" min="1" max="432000" value="<?= $_POST['ttl-value'] ?? DEFAULT_TTL ?>" placeholder="<?= DEFAULT_TTL ?>">
<input required="" id="ttl-value" list="ttls" name="ttl-value" size="6" type="number" min="1" max="432000" value="<?= $_POST['ttl-value'] ?? NS_DEFAULT_TTL ?>" placeholder="<?= NS_DEFAULT_TTL ?>">
<datalist id="ttls">
<option value="900">
<option value="1800">

54
pg-view/reg/edit.php Normal file
View File

@ -0,0 +1,54 @@
<?php declare(strict_types=1); ?>
<form method="post">
<label for="domain"><?= _('Domain to be changed') ?></label>
<br>
<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 type="submit" value="<?= _('Display') ?>">
</form>
<?php
if (isset($data['records'])) { // Display zone
?>
<form method="post">
<input type="hidden" name="domain" value="<?= $_POST['domain'] ?>">
<label for="records"><?= sprintf(_('Delegation records for %s'), '<code><strong>' . $_POST['domain'] . '</strong></code>') ?></label>
<br>
<textarea id="records" name="records" wrap="off" rows="<?= substr_count($data['records'], LF) + 1 ?>"><?= htmlspecialchars($data['records']) ?></textarea>
<br>
<input type="submit" value="<?= _('Replace') ?>">
</form>
<?php
}
displayFinalMessage($data);
?>
<h2><?= _('Input values') ?></h2>
<p><?= _('Precising the class (<code>IN</code>) is optional.') ?></p>
<p><?= sprintf(_('Submitted field content is limited to %s characters.'), REG_TEXTAREA_MAX_CHARACTERS) ?></p>
<p><?= sprintf(_('TTL values are ignored and always set to %s seconds.'), '<code><time datetime="PT' . CONF['reg']['ttl'] . 'S">' . CONF['reg']['ttl'] . '</time></code>') ?></p>
<p><?= _('The only types that can be defined here are:') ?></p>
<ul>
<?php
foreach (REG_ALLOWED_TYPES as $allowed_type)
echo ' <li><code>' . $allowed_type . '</code></li>';
?>
</ul>