Browse Source

reg: Delay at unregistration; Display domain history

Miraty 2 years ago
parent
commit
b9af7fee09

+ 7 - 2
db/schema.sql

@@ -10,7 +10,7 @@ INSERT INTO "params"("name", "value") VALUES('secret_key', '0');
 INSERT INTO "params"("name", "value") VALUES('secret_key_last_change', '0');
 INSERT INTO "params"("name", "value") VALUES('secret_key_last_change', '0');
 INSERT INTO "params"("name", "value") VALUES('username_salt', '00000000000000000000000000000000'); -- Should be unique and secret ; generate one using `openssl rand -hex 16` ; can't be changed without breaking current accounts login
 INSERT INTO "params"("name", "value") VALUES('username_salt', '00000000000000000000000000000000'); -- Should be unique and secret ; generate one using `openssl rand -hex 16` ; can't be changed without breaking current accounts login
 CREATE TABLE IF NOT EXISTS "users" (
 CREATE TABLE IF NOT EXISTS "users" (
-	"id"                 TEXT    NOT NULL UNIQUE,
+	"id"                 TEXT    NOT NULL UNIQUE CHECK (LENGTH(id) = 64),
 	"username"           TEXT    NOT NULL UNIQUE,
 	"username"           TEXT    NOT NULL UNIQUE,
 	"password"           TEXT    NOT NULL,
 	"password"           TEXT    NOT NULL,
 	"registration_date"  TEXT    NOT NULL,
 	"registration_date"  TEXT    NOT NULL,
@@ -27,10 +27,15 @@ CREATE TABLE IF NOT EXISTS "approval-keys" (
 CREATE TABLE IF NOT EXISTS "registry" (
 CREATE TABLE IF NOT EXISTS "registry" (
 	"domain"       TEXT    NOT NULL UNIQUE,
 	"domain"       TEXT    NOT NULL UNIQUE,
 	"username"     TEXT    NOT NULL,
 	"username"     TEXT    NOT NULL,
-	"last_renewal" TEXT    NOT NULL,
+	"creation"     TEXT    NOT NULL,
 	PRIMARY KEY("domain"),
 	PRIMARY KEY("domain"),
 	FOREIGN KEY("username") REFERENCES "users"("id")
 	FOREIGN KEY("username") REFERENCES "users"("id")
 );
 );
+CREATE TABLE IF NOT EXISTS "registry-history" (
+	"domain"       TEXT    NOT NULL,
+	"creation"     TEXT    NOT NULL,
+	"expiration"   TEXT    NOT NULL
+);
 CREATE TABLE IF NOT EXISTS "zones" (
 CREATE TABLE IF NOT EXISTS "zones" (
 	"zone"     TEXT    NOT NULL UNIQUE,
 	"zone"     TEXT    NOT NULL UNIQUE,
 	"username" TEXT    NOT NULL,
 	"username" TEXT    NOT NULL,

+ 21 - 5
fn/reg.php

@@ -23,11 +23,27 @@ function regDeleteDomain($domain) {
 	if (file_put_contents($path, $content) === false)
 	if (file_put_contents($path, $content) === false)
 		output(500, 'Failed to write new registry file.');
 		output(500, 'Failed to write new registry file.');
 
 
-	// Delete from database
-	query('delete', 'registry', [
-		'domain' => $domain,
-		'username' => $_SESSION['id'],
-	]);
+	try {
+		DB->beginTransaction();
+
+		$conditions = [
+			'domain' => $domain,
+			'username' => $_SESSION['id'],
+		];
+
+		insert('registry-history', [
+			'domain' => $domain,
+			'creation' => query('select', 'registry', $conditions, 'creation')[0],
+			'expiration' => date('Y-m'),
+		]);
+
+		query('delete', 'registry', $conditions);
+
+		DB->commit();
+	} catch (Exception $e) {
+		DB->rollback();
+		output(500, 'Database error.', [$e->getMessage()]);
+	}
 }
 }
 
 
 function regParseDomain($domain) {
 function regParseDomain($domain) {

+ 32 - 14
locales/fr/C/LC_MESSAGES/messages.po

@@ -1,5 +1,7 @@
 msgid ""
 msgid ""
 msgstr ""
 msgstr ""
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2023-03-25 16:16+0100\n"
 "Language: fr\n"
 "Language: fr\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 
 
@@ -272,15 +274,15 @@ msgstr "Supprimer un accès"
 msgid "Delete an existing HTTP access from a subdirectory of the SFTP space"
 msgid "Delete an existing HTTP access from a subdirectory of the SFTP space"
 msgstr "Retirer un accès HTTP existant d'un sous-dossier de l'espace SFTP"
 msgstr "Retirer un accès HTTP existant d'un sous-dossier de l'espace SFTP"
 
 
-#: router.php:133 view.php:39
+#: router.php:137 view.php:39
 msgid "This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it."
 msgid "This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it."
 msgstr "Ce service est en cours de maintenance. Aucune action ne peut être effectuée avant qu'ane administrataire termine de le réparer."
 msgstr "Ce service est en cours de maintenance. Aucune action ne peut être effectuée avant qu'ane administrataire termine de le réparer."
 
 
-#: router.php:144
+#: router.php:148
 msgid "You need to be logged in to do this."
 msgid "You need to be logged in to do this."
 msgstr "Vous devez être connecté·e à un compte pour faire cela."
 msgstr "Vous devez être connecté·e à un compte pour faire cela."
 
 
-#: router.php:146
+#: router.php:150
 msgid "This account doesn't exist anymore. Log out to end this ghost session."
 msgid "This account doesn't exist anymore. Log out to end this ghost session."
 msgstr "Ce compte n'existe plus. Déconnectez-vous pour terminer cette session fantôme."
 msgstr "Ce compte n'existe plus. Déconnectez-vous pour terminer cette session fantôme."
 
 
@@ -485,19 +487,35 @@ msgstr "Zone supprimée."
 msgid "This format of subdomain is not allowed."
 msgid "This format of subdomain is not allowed."
 msgstr "Ce format de sous-domaine n'est pas autorisé."
 msgstr "Ce format de sous-domaine n'est pas autorisé."
 
 
-#: pg-act/reg/register.php:27
-msgid "This domain is open to registration!"
-msgstr "Ce domaine est disponible à l'enregistrement."
-
-#: pg-act/reg/register.php:29
+#: pg-act/reg/register.php:21
 msgid "This domain is reserved."
 msgid "This domain is reserved."
 msgstr "Ce domaine est réservé."
 msgstr "Ce domaine est réservé."
 
 
-#: pg-act/reg/register.php:31
-msgid "This domain is already registered."
-msgstr "Ce domaine est déjà enregistré."
+#: pg-act/reg/register.php:34
+#, php-format
+msgid "This domain was registered from %s to %s."
+msgstr "Ce domaine était enregistré de %s à %s."
+
+#: pg-act/reg/register.php:38
+#, php-format
+msgid "This blocks it until %s."
+msgstr "Ceci le bloque jusqu'en %s."
+
+#: pg-act/reg/register.php:40
+#, php-format
+msgid "This had blocked it until %s."
+msgstr "Ceci l'avait bloqué jusqu'en %s."
+
+#: pg-act/reg/register.php:48
+#, php-format
+msgid "This domain is already registered, since %s."
+msgstr "Ce domaine est déjà enregistré, depuis %s."
+
+#: pg-act/reg/register.php:54
+msgid "This domain is open to registration!"
+msgstr "Ce domaine est disponible à l'enregistrement."
 
 
-#: pg-act/reg/register.php:47
+#: pg-act/reg/register.php:71
 msgid "Domain registered."
 msgid "Domain registered."
 msgstr "Domaine enregistré."
 msgstr "Domaine enregistré."
 
 
@@ -1116,8 +1134,8 @@ msgid "Receive the domain"
 msgstr "Recevoir le domaine"
 msgstr "Recevoir le domaine"
 
 
 #: pg-view/reg/unregister.php:2
 #: pg-view/reg/unregister.php:2
-msgid "This will unregister the domain, making it registerable by anyone again."
-msgstr "Ceci désenregistrera le domaine, ce qui le re-disponibilisera à tout le monde."
+msgid "This will unregister the domain, making it registerable by anyone again (after a delay of 1 year plus half the registration period, with a maximum of 8 years)."
+msgstr "Ceci désenregistrera le domaine, ce qui le re-disponibilisera à tout le monde (après un délai de 1 an + la moitié de la durée d'enregistrement, avec un maximum de 8 ans)."
 
 
 #: pg-view/reg/unregister.php:16
 #: pg-view/reg/unregister.php:16
 msgid "Unregister"
 msgid "Unregister"

+ 27 - 11
locales/messages.pot

@@ -271,15 +271,15 @@ msgstr ""
 msgid "Delete an existing HTTP access from a subdirectory of the SFTP space"
 msgid "Delete an existing HTTP access from a subdirectory of the SFTP space"
 msgstr ""
 msgstr ""
 
 
-#: router.php:133 view.php:39
+#: router.php:137 view.php:39
 msgid "This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it."
 msgid "This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it."
 msgstr ""
 msgstr ""
 
 
-#: router.php:144
+#: router.php:148
 msgid "You need to be logged in to do this."
 msgid "You need to be logged in to do this."
 msgstr ""
 msgstr ""
 
 
-#: router.php:146
+#: router.php:150
 msgid "This account doesn't exist anymore. Log out to end this ghost session."
 msgid "This account doesn't exist anymore. Log out to end this ghost session."
 msgstr ""
 msgstr ""
 
 
@@ -484,19 +484,35 @@ msgstr ""
 msgid "This format of subdomain is not allowed."
 msgid "This format of subdomain is not allowed."
 msgstr ""
 msgstr ""
 
 
-#: pg-act/reg/register.php:27
-msgid "This domain is open to registration!"
+#: pg-act/reg/register.php:21
+msgid "This domain is reserved."
 msgstr ""
 msgstr ""
 
 
-#: pg-act/reg/register.php:29
-msgid "This domain is reserved."
+#: pg-act/reg/register.php:34
+#, php-format
+msgid "This domain was registered from %s to %s."
+msgstr ""
+
+#: pg-act/reg/register.php:38
+#, php-format
+msgid "This blocks it until %s."
 msgstr ""
 msgstr ""
 
 
-#: pg-act/reg/register.php:31
-msgid "This domain is already registered."
+#: pg-act/reg/register.php:40
+#, php-format
+msgid "This had blocked it until %s."
+msgstr ""
+
+#: pg-act/reg/register.php:48
+#, php-format
+msgid "This domain is already registered, since %s."
+msgstr ""
+
+#: pg-act/reg/register.php:54
+msgid "This domain is open to registration!"
 msgstr ""
 msgstr ""
 
 
-#: pg-act/reg/register.php:47
+#: pg-act/reg/register.php:71
 msgid "Domain registered."
 msgid "Domain registered."
 msgstr ""
 msgstr ""
 
 
@@ -1115,7 +1131,7 @@ msgid "Receive the domain"
 msgstr ""
 msgstr ""
 
 
 #: pg-view/reg/unregister.php:2
 #: pg-view/reg/unregister.php:2
-msgid "This will unregister the domain, making it registerable by anyone again."
+msgid "This will unregister the domain, making it registerable by anyone again (after a delay of 1 year plus half the registration period, with a maximum of 8 years)."
 msgstr ""
 msgstr ""
 
 
 #: pg-view/reg/unregister.php:16
 #: pg-view/reg/unregister.php:16

+ 1 - 1
pg-act/auth/unregister.php

@@ -6,7 +6,7 @@ if (checkPassword($_SESSION['id'], $_POST['current-password']) !== true)
 if (!isset($_POST['delete']))
 if (!isset($_POST['delete']))
 	output(403, _('Account deletion must be confirmed.'));
 	output(403, _('Account deletion must be confirmed.'));
 
 
-$user_services = explode(',', query('select', 'users', ['username' => $_SESSION['id']], 'services')[0]);
+$user_services = explode(',', query('select', 'users', ['id' => $_SESSION['id']], 'services')[0]);
 
 
 foreach (SERVICES_USER as $service)
 foreach (SERVICES_USER as $service)
 	if (in_array($service, $user_services, true) AND CONF['common']['services'][$service] !== 'enabled')
 	if (in_array($service, $user_services, true) AND CONF['common']['services'][$service] !== 'enabled')

+ 40 - 16
pg-act/reg/register.php

@@ -17,31 +17,55 @@ match (CONF['reg']['suffixes'][$_POST['suffix']]) {
 
 
 $domain = formatAbsoluteDomain($_POST['subdomain'] . '.' . $_POST['suffix']);
 $domain = formatAbsoluteDomain($_POST['subdomain'] . '.' . $_POST['suffix']);
 
 
-$registered = query('select', 'registry', ['domain' => $domain], 'domain') !== [];
-$reserved = in_array($_POST['subdomain'], explode(LF, file_get_contents(ROOT_PATH . '/pg-act/reg/reserved.txt')));
-
-$message = match ($registered) {
-	false => match ($reserved) {
-		false => match ($_POST['action']) {
-			'register' => NULL,
-			default => '✔️ ' . _('This domain is open to registration!'),
-		},
-		default => '❌ ' . _('This domain is reserved.'),
-	},
-	default => '❌ ' . _('This domain is already registered.'),
-};
-if ($message !== NULL)
+if (in_array($_POST['subdomain'], explode(LF, file_get_contents(ROOT_PATH . '/pg-act/reg/reserved.txt')), true))
+	message('❌ ' . _('This domain is reserved.'));
+
+$message = '<ul>';
+$blocked = false;
+foreach (query('select', 'registry-history', ['domain' => $domain]) as $data) {
+	$creation = DateTimeImmutable::createFromFormat('Y-m', $data['creation']);
+	$expiration = DateTimeImmutable::createFromFormat('Y-m', $data['expiration']);
+
+	$registration_duration = intval(round($creation->diff($expiration)->format('%a') / 30.4375));
+	$expected_expiration_duration = min(intval($registration_duration * 0.5) + 12, 12*8);
+
+	$new_registration_date = $expiration->add(new DateInterval('P' . $expected_expiration_duration . 'M'));
+
+	$message .= '<li>' . sprintf(_('This domain was registered from %s to %s.'), '<time>' . $data['creation'] . '</time>', '<time>' . $data['expiration'] . '</time>') . ' ';
+
+	if (new DateTimeImmutable('now', new DateTimeZone('UTC')) < $new_registration_date) {
+		$blocked = true;
+		$message .= sprintf(_('This blocks it until %s.'), '<time>' . $new_registration_date->format('Y-m') . '</time>') . ' ❌';
+	} else {
+		$message .= sprintf(_('This had blocked it until %s.'), '<time>' . $new_registration_date->format('Y-m') . '</time>');
+	}
+	$message .= '</li>';
+}
+$message .= '</ul>';
+
+$registration_data = query('select', 'registry', ['domain' => $domain]);
+if ($registration_data !== [])
+	$message .= sprintf(_('This domain is already registered, since %s.'), '<time>' . $registration_data[0]['creation'] . '</time>');
+
+if ($blocked OR $registration_data !== [])
+	message($message);
+
+if ($_POST['action'] !== 'register')
+	message($message . ' ✔️ ' . _('This domain is open to registration!'));
+
+function message($message) {
 	output(200, data: [
 	output(200, data: [
 		'message' => '<p>' . $message . '</p>',
 		'message' => '<p>' . $message . '</p>',
 		'domain' => htmlspecialchars($_POST['subdomain']),
 		'domain' => htmlspecialchars($_POST['subdomain']),
 	]);
 	]);
+}
 
 
 rateLimit();
 rateLimit();
 
 
 insert('registry', [
 insert('registry', [
 	'domain' => $domain,
 	'domain' => $domain,
 	'username' => $_SESSION['id'],
 	'username' => $_SESSION['id'],
-	'last_renewal' => date('Y-m-d H:i:s'),
+	'creation' => date('Y-m'),
 ]);
 ]);
 
 
-output(200, _('Domain registered.'));
+output(200, _('Domain registered.'), ['message' => '<p>' . $message . '</p>']);

+ 5 - 1
pg-view/reg/register.php

@@ -25,6 +25,10 @@ foreach (CONF['reg']['suffixes'] as $suffix => $availability) {
 		</div>
 		</div>
 	</fieldset>
 	</fieldset>
 	<button type="submit" name="action" value="check">👁️ <?= _('Check availability') ?></button>
 	<button type="submit" name="action" value="check">👁️ <?= _('Check availability') ?></button>
-	<?= $data['message'] ?? '<br>' ?>
+	<br>
 	<button type="submit" name="action" value="register">🔗 <?= _('Register') ?></button>
 	<button type="submit" name="action" value="register">🔗 <?= _('Register') ?></button>
 </form>
 </form>
+
+<section>
+	<?= $data['message'] ?? '' ?>
+</section>

+ 1 - 1
pg-view/reg/unregister.php

@@ -1,5 +1,5 @@
 <p>
 <p>
-	<?= _('This will unregister the domain, making it registerable by anyone again.') ?>
+	<?= _('This will unregister the domain, making it registerable by anyone again (after a delay of 1 year plus half the registration period, with a maximum of 8 years).') ?>
 </p>
 </p>
 
 
 <form method="post">
 <form method="post">

+ 4 - 0
router.php

@@ -3,6 +3,10 @@ const ROOT_PATH = __DIR__;
 define('CONF', parse_ini_file(ROOT_PATH . '/config.ini', true, INI_SCANNER_TYPED));
 define('CONF', parse_ini_file(ROOT_PATH . '/config.ini', true, INI_SCANNER_TYPED));
 
 
 define('DB', new PDO('sqlite:' . ROOT_PATH . '/db/servnest.db'));
 define('DB', new PDO('sqlite:' . ROOT_PATH . '/db/servnest.db'));
+DB->exec('PRAGMA foreign_keys = ON;');
+DB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+
+date_default_timezone_set('UTC');
 
 
 $locale = 'en';
 $locale = 'en';
 foreach (explode(',', preg_replace('/[A-Z0-9]|q=|;|-|\./', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '')) as $client_locale) {
 foreach (explode(',', preg_replace('/[A-Z0-9]|q=|;|-|\./', '', $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '')) as $client_locale) {