diff --git a/pages.php b/pages.php
index 3aa4aee..79d1dd0 100644
--- a/pages.php
+++ b/pages.php
@@ -31,14 +31,17 @@ define('PAGES', [
'approval' => [
'title' => _('Switch to an approved account'),
'description' => _('Switch to an approved account using an approval key'),
+ 'tokens_account_cost' => 300,
],
'password' => [
'title' => _('Change password'),
'description' => _('Change the character string used to authenticate yourself'),
+ 'tokens_account_cost' => 300,
],
'username' => [
'title' => _('Change username'),
'description' => _('Change the name used to identify your account when logging in and displayed at the start of every page'),
+ 'tokens_account_cost' => 300,
],
],
'reg' => [
@@ -58,22 +61,27 @@ define('PAGES', [
'print' => [
'title' => _('Display domain records'),
'description' => _('Print every record related to a domain and served by the registry'),
+ 'tokens_account_cost' => 60,
],
'ns' => [
'title' => sprintf(_('%s records'), 'NS'),
'description' => sprintf(_('Indicate the name servers of a %s subdomain'), '' . key(CONF['reg']['suffixes']) . '
'),
+ 'tokens_account_cost' => 300,
],
'ds' => [
'title' => sprintf(_('%s records'), 'DS'),
'description' => _('Delegate DNSSEC trust'),
+ 'tokens_account_cost' => 300,
],
'transfer' => [
'title' => _('Receive a domain transfer'),
'description' => _('Transfer a domain owned by another account to the current account'),
+ 'tokens_account_cost' => 300,
],
'glue' => [
'title' => _('Glue records'),
'description' => _('Advanced: store the IP address of a name server whose domain is inside the domain it serves'),
+ 'tokens_account_cost' => 300,
],
],
'ns' => [
@@ -93,6 +101,7 @@ define('PAGES', [
'print' => [
'title' => _('Display zone'),
'description' => _('Print zonefile content'),
+ 'tokens_account_cost' => 60,
],
'edit' => [
'title' => _('Edit zone'),
@@ -102,46 +111,57 @@ define('PAGES', [
'ip' => [
'title' => _('AAAA and A records'),
'description' => _('Store domain\'s IP address'),
+ 'tokens_account_cost' => 120,
],
'ns' => [
'title' => sprintf(_('%s records'), 'NS'),
'description' => _('Store zone\'s name server'),
+ 'tokens_account_cost' => 120,
],
'txt' => [
'title' => sprintf(_('%s records'), 'TXT'),
'description' => _('Associate text to domain'),
+ 'tokens_account_cost' => 120,
],
'caa' => [
'title' => sprintf(_('%s records'), 'CAA'),
'description' => _('Limit the certificate authorities allowed to certify the domain'),
+ 'tokens_account_cost' => 120,
],
'srv' => [
'title' => sprintf(_('%s records'), 'SRV'),
'description' => _('Store the location of a domain\'s service'),
+ 'tokens_account_cost' => 120,
],
'mx' => [
'title' => sprintf(_('%s records'), 'MX'),
'description' => _('Store the email server\'s address'),
+ 'tokens_account_cost' => 120,
],
'sshfp' => [
'title' => sprintf(_('%s records'), 'SSHFP'),
'description' => _('Store SSH public keys fingerprints'),
+ 'tokens_account_cost' => 120,
],
'tlsa' => [
'title' => sprintf(_('%s records'), 'TLSA'),
'description' => _('Setup DANE by publishing the TLS certificate fingerprint'),
+ 'tokens_account_cost' => 120,
],
'cname' => [
'title' => sprintf(_('%s records'), 'CNAME'),
'description' => _('Define a domain as an alias of another'),
+ 'tokens_account_cost' => 120,
],
'dname' => [
'title' => sprintf(_('%s records'), 'DNAME'),
'description' => _('Define all subdomains of a domain as aliases of subdomains of another domain'),
+ 'tokens_account_cost' => 120,
],
'loc' => [
'title' => sprintf(_('%s records'), 'LOC'),
'description' => _('Store geographic coordinates'),
+ 'tokens_account_cost' => 120,
],
],
'ht' => [
diff --git a/pg-act/auth/approval.php b/pg-act/auth/approval.php
index 091c3e1..9a8a046 100644
--- a/pg-act/auth/approval.php
+++ b/pg-act/auth/approval.php
@@ -3,6 +3,8 @@
if ($_SESSION['type'] !== 'testing')
output(403, _('This account is already approved.'));
+rateLimit();
+
if (isset(query('select', 'approval-keys', ['key' => $_POST['key']], 'key')[0]) !== true)
output(403, _('This approval key is not available. It has been mistyped, used for another account, or has expired.'));
diff --git a/pg-act/auth/password.php b/pg-act/auth/password.php
index 413bcab..6da1be9 100644
--- a/pg-act/auth/password.php
+++ b/pg-act/auth/password.php
@@ -5,6 +5,8 @@ checkPasswordFormat($_POST['new-password']);
if (checkPassword($_SESSION['id'], $_POST['current-password']) !== true)
output(403, _('Wrong current password.'));
+rateLimit();
+
changePassword($_SESSION['id'], $_POST['new-password']);
output(200, _('Password updated.'));
diff --git a/pg-act/auth/username.php b/pg-act/auth/username.php
index 2a9062e..274e818 100644
--- a/pg-act/auth/username.php
+++ b/pg-act/auth/username.php
@@ -10,6 +10,8 @@ $username = hashUsername($_POST['new-username']);
if (usernameExists($username) !== false)
output(403, _('This username is already taken.'));
+rateLimit();
+
DB->prepare('UPDATE users SET username = :username WHERE id = :id')
->execute([':username' => $username, ':id' => $_SESSION['id']]);
diff --git a/pg-act/ns/caa.php b/pg-act/ns/caa.php
index 83e20ce..53095d6 100644
--- a/pg-act/ns/caa.php
+++ b/pg-act/ns/caa.php
@@ -11,6 +11,8 @@ if (!(preg_match('/^[a-z]{1,127}$/D', $_POST['tag'])))
if (!(preg_match('/^[a-z0-9.-]{1,255}$/D', $_POST['value'])))
output(403, 'Wrong value for value
.');
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/cname.php b/pg-act/ns/cname.php
index 3daeadf..f870b05 100644
--- a/pg-act/ns/cname.php
+++ b/pg-act/ns/cname.php
@@ -4,6 +4,8 @@ $values = nsParseCommonRequirements();
$_POST['cname'] = formatAbsoluteDomain($_POST['cname']);
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/dname.php b/pg-act/ns/dname.php
index ff2e5a7..155fae3 100644
--- a/pg-act/ns/dname.php
+++ b/pg-act/ns/dname.php
@@ -4,6 +4,8 @@ $values = nsParseCommonRequirements();
$_POST['dname'] = formatAbsoluteDomain($_POST['dname']);
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/ip.php b/pg-act/ns/ip.php
index 5fa0da1..4c6b9b9 100644
--- a/pg-act/ns/ip.php
+++ b/pg-act/ns/ip.php
@@ -4,6 +4,8 @@ $values = nsParseCommonRequirements();
$record = checkIpFormat($_POST['ip']);
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/loc.php b/pg-act/ns/loc.php
index 23ed875..a3a50de 100644
--- a/pg-act/ns/loc.php
+++ b/pg-act/ns/loc.php
@@ -49,6 +49,8 @@ if (!($_POST['hp'] >= 0 AND $_POST['hp'] <= 90000000))
if (!($_POST['vp'] >= 0 AND $_POST['vp'] <= 90000000))
output(403, 'Wrong value for vp
.');
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/mx.php b/pg-act/ns/mx.php
index 370151f..c534816 100644
--- a/pg-act/ns/mx.php
+++ b/pg-act/ns/mx.php
@@ -7,6 +7,8 @@ if (!($_POST['priority'] >= 0 AND $_POST['priority'] <= 255))
$_POST['host'] = formatAbsoluteDomain($_POST['host']);
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/ns.php b/pg-act/ns/ns.php
index 8dcf92c..c064131 100644
--- a/pg-act/ns/ns.php
+++ b/pg-act/ns/ns.php
@@ -4,6 +4,8 @@ $values = nsParseCommonRequirements();
$_POST['ns'] = formatAbsoluteDomain($_POST['ns']);
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/print.php b/pg-act/ns/print.php
index 67096e2..c415d15 100644
--- a/pg-act/ns/print.php
+++ b/pg-act/ns/print.php
@@ -4,6 +4,8 @@ nsCheckZonePossession($_POST['zone']);
$data['zone_name'] = $_POST['zone'];
+rateLimit();
+
$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.');
diff --git a/pg-act/ns/srv.php b/pg-act/ns/srv.php
index 02f329c..7c5af6b 100644
--- a/pg-act/ns/srv.php
+++ b/pg-act/ns/srv.php
@@ -13,6 +13,8 @@ if (!($_POST['port'] >= 0 AND $_POST['port'] <= 65535))
$_POST['target'] = formatAbsoluteDomain($_POST['target']);
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/sshfp.php b/pg-act/ns/sshfp.php
index b131cc3..b3b40a1 100644
--- a/pg-act/ns/sshfp.php
+++ b/pg-act/ns/sshfp.php
@@ -11,6 +11,8 @@ if (!($_POST['type'] === '2'))
if (!(preg_match('/^[a-z0-9]{64}$/D', $_POST['fp'])))
output(403, 'Wrong value for fp
.');
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/tlsa.php b/pg-act/ns/tlsa.php
index c9ded9f..de5241e 100644
--- a/pg-act/ns/tlsa.php
+++ b/pg-act/ns/tlsa.php
@@ -14,6 +14,8 @@ if (!($_POST['type'] >= 0 AND $_POST['type'] <= 2))
if (!(preg_match('/^[a-zA-Z0-9.-]{1,1024}$/D', $_POST['content'])))
output(403, 'Wrong value for content
.');
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/ns/txt.php b/pg-act/ns/txt.php
index ebabc5c..959ef49 100644
--- a/pg-act/ns/txt.php
+++ b/pg-act/ns/txt.php
@@ -5,6 +5,8 @@ $values = nsParseCommonRequirements();
if (!(preg_match('/^[a-zA-Z0-9 .@=:!%$+\/\()[\]_-]{5,8192}$/D', $_POST['txt'])))
output(403, 'Wrong value for txt
.');
+rateLimit();
+
knotcZoneExec($_POST['zone'], [
$values['domain'],
$values['ttl'],
diff --git a/pg-act/reg/ds.php b/pg-act/reg/ds.php
index 0b6710e..a656165 100644
--- a/pg-act/reg/ds.php
+++ b/pg-act/reg/ds.php
@@ -17,6 +17,8 @@ if ($_POST['dt'] !== '2' AND $_POST['dt'] !== '4')
regCheckDomainPossession($_POST['zone']);
+rateLimit();
+
knotcZoneExec(regParseDomain($_POST['zone'])['suffix'], [
$_POST['zone'],
CONF['reg']['ttl'],
diff --git a/pg-act/reg/glue.php b/pg-act/reg/glue.php
index 2b4e7c7..3ceecf9 100644
--- a/pg-act/reg/glue.php
+++ b/pg-act/reg/glue.php
@@ -2,6 +2,8 @@
regCheckDomainPossession($_POST['suffix']);
+rateLimit();
+
knotcZoneExec(regParseDomain($_POST['suffix'])['suffix'], [
formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['suffix']),
CONF['reg']['ttl'],
diff --git a/pg-act/reg/ns.php b/pg-act/reg/ns.php
index 3da9608..487c27e 100644
--- a/pg-act/reg/ns.php
+++ b/pg-act/reg/ns.php
@@ -2,6 +2,8 @@
regCheckDomainPossession($_POST['domain']);
+rateLimit();
+
knotcZoneExec(regParseDomain($_POST['domain'])['suffix'], [
$_POST['domain'],
CONF['reg']['ttl'],
diff --git a/pg-act/reg/print.php b/pg-act/reg/print.php
index d00a99e..b639a52 100644
--- a/pg-act/reg/print.php
+++ b/pg-act/reg/print.php
@@ -2,6 +2,8 @@
regCheckDomainPossession($_POST['domain']);
+rateLimit();
+
$zone_content = file_get_contents(CONF['reg']['suffixes_path'] . '/' . regParseDomain($_POST['domain'])['suffix'] . 'zone');
if ($zone_content === false)
output(500, 'Unable to read registry file.');
diff --git a/pg-act/reg/transfer.php b/pg-act/reg/transfer.php
index 8af8fa5..6a44150 100644
--- a/pg-act/reg/transfer.php
+++ b/pg-act/reg/transfer.php
@@ -19,6 +19,8 @@ if (preg_match('/^' . preg_quote($domain, '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+
checkAuthToken($matches['salt'], $matches['hash']);
+rateLimit();
+
DB->prepare('UPDATE registry SET username = :username WHERE domain = :domain')
->execute([':username' => $_SESSION['id'], ':domain' => $domain]);