diff --git a/common/init.php b/common/init.php index 01224ba..3c74841 100644 --- a/common/init.php +++ b/common/init.php @@ -13,12 +13,8 @@ define("PLACEHOLDER_IPV4", "203.0.113.42"); // From RFC5737: IPv4 Address Blocks // Page titles definition require "pages.php"; -require CONF['common']['root_path'] . "/fn/common.php"; -// Service-specific functions and constants -if (SERVICE === "reg" OR SERVICE === "ns") - require CONF['common']['root_path'] . "/fn/dns.php"; -if (SERVICE !== "") - require CONF['common']['root_path'] . "/fn/" . SERVICE . ".php"; +foreach (array_diff(scandir(CONF['common']['root_path'] . "/fn"), array('..', '.')) as $file) + require CONF['common']['root_path'] . '/fn/' . $file; function success($msg = '') { if ($msg !== '') diff --git a/common/pages.php b/common/pages.php index 027fef9..ece0217 100644 --- a/common/pages.php +++ b/common/pages.php @@ -6,6 +6,7 @@ define('TITLES', [ 'index' => 'Authentification', 'login' => 'Se connecter', 'register' => 'Créer un compte', + 'unregister' => 'Supprimer son compte', 'password' => 'Changer la clé de passe', 'logout' => 'Déconnexion', ], @@ -48,6 +49,7 @@ define('DESCRIPTIONS', [ 'index' => 'Gérer son compte', 'login' => 'Démarrer une nouvelle session avec un compte existant', 'register' => 'Créer un nouveau compte Niver', + 'unregister' => 'Effacer les données liées à son compte', 'password' => 'Changer la chaîne de caractères permettant de vous authentifier.', 'logout' => 'Terminer la session et effacer ses cookies', ], diff --git a/fn/auth.php b/fn/auth.php index de957af..204bdfa 100644 --- a/fn/auth.php +++ b/fn/auth.php @@ -29,7 +29,7 @@ function hashPassword($password) { } function userExist($username) { - return $username === query('select', 'users', ['username' => $username], 'username')[0]; + return isset(query('select', 'users', ['username' => $username], 'username')[0]); } function checkPassword($username, $password) { diff --git a/fn/dns.php b/fn/dns.php index db58ab1..108d9e0 100644 --- a/fn/dns.php +++ b/fn/dns.php @@ -1,22 +1,42 @@ knotc failed with exit code " . $code['begin'] . ": " . $output['begin'][0] . "."); + serverError("knotcConfExec: knotc failed with exit code " . $code['begin'] . ": " . $output['begin'][0] . "."); - exec(CONF['dns']['knotc_path'] . " zone-" . $action . "set " . $suffix . " " . implode(" ", $cmd), $output['op'], $code['op']); - if ($code['op'] !== 0) { - exec(CONF['dns']['knotc_path'] . " zone-abort " . $suffix); - serverError("knotc failed with exit code " . $code['op'] . ": " . $output['op'][0] . "."); + foreach ($cmds as $cmd) { + exec(CONF['dns']['knotc_path'] . " conf-" . $cmd, $output['op'], $code['op']); + if ($code['op'] !== 0) { + exec(CONF['dns']['knotc_path'] . " conf-abort"); + serverError("knotcConfExec: knotc failed with exit code " . $code['op'] . ": " . $output['op'][0] . "."); + } } - exec(CONF['dns']['knotc_path'] . " zone-commit " . $suffix, $output['commit'], $code['commit']); + exec(CONF['dns']['knotc_path'] . " conf-commit", $output['commit'], $code['commit']); if ($code['commit'] !== 0) { - exec(CONF['dns']['knotc_path'] . " zone-abort " . $suffix); - serverError("knotc failed with exit code " . $code['commit'] . ": " . $output['commit'][0] . "."); + exec(CONF['dns']['knotc_path'] . " conf-abort"); + serverError("knotcConfExec: knotc failed with exit code " . $code['commit'] . ": " . $output['commit'][0] . "."); + } +} + +function knotcZoneExec($zone, $cmd) { + $action = checkAction($_POST['action']); + + exec(CONF['dns']['knotc_path'] . " zone-begin " . $zone, $output['begin'], $code['begin']); + if ($code['begin'] !== 0) + serverError("knotcZoneExec: knotc failed with exit code " . $code['begin'] . ": " . $output['begin'][0] . "."); + + exec(CONF['dns']['knotc_path'] . " zone-" . $action . "set " . $zone . " " . implode(" ", $cmd), $output['op'], $code['op']); + if ($code['op'] !== 0) { + exec(CONF['dns']['knotc_path'] . " zone-abort " . $zone); + serverError("knotcZoneExec: knotc failed with exit code " . $code['op'] . ": " . $output['op'][0] . "."); + } + + exec(CONF['dns']['knotc_path'] . " zone-commit " . $zone, $output['commit'], $code['commit']); + if ($code['commit'] !== 0) { + exec(CONF['dns']['knotc_path'] . " zone-abort " . $zone); + serverError("knotcZoneExec: knotc failed with exit code " . $code['commit'] . ": " . $output['commit'][0] . "."); } } diff --git a/fn/ht.php b/fn/ht.php index 048ca4d..0959cd7 100644 --- a/fn/ht.php +++ b/fn/ht.php @@ -20,18 +20,16 @@ function addSite($username, $siteDir, $domain, $domainType, $protocol) { $op = $db->prepare("INSERT INTO sites(username, site_dir, domain, domain_type, protocol, creation_date, le_enabled) VALUES(:username, :site_dir, :domain, :domain_type, :protocol, :creation_date, :le_enabled)"); - if ($domainType === "dns" AND $protocol === "http") - $le_enabled = 0; - else - $le_enabled = NULL; - $op->bindValue(':username', $username); $op->bindValue(':site_dir', $siteDir); $op->bindValue(':domain', $domain); $op->bindValue(':domain_type', $domainType); $op->bindValue(':protocol', $protocol); $op->bindValue(':creation_date', date("Y-m-d H:i:s")); - $op->bindValue(':le_enabled', $le_enabled); + if ($domainType === "dns" AND $protocol === "http") + $op->bindValue(':le_enabled', 0); + else + $op->bindValue(':le_enabled', NULL); $op->execute(); } @@ -47,3 +45,51 @@ function dirsStatuses($username, $domainType, $protocol) { $dirs[$fsDir] = in_array($fsDir, $dbDirs); return $dirs; } + +function htDeleteSite($dir, $domainType, $protocol) { + + if ($domainType === 'onion') { + // Delete Tor config + $torConf = file_get_contents(CONF['ht']['tor_config_path']); + if ($torConf === false) + serverError("Failed to read current Tor configuration."); + $torConf = str_replace('HiddenServiceDir ' . CONF['ht']['tor_keys_path'] . '/' . $dir . '/ +HiddenServicePort 80 [::1]:' . CONF['ht']['internal_onion_http_port'] . ' +', '', $torConf); + if (file_put_contents(CONF['ht']['tor_config_path'], $torConf) === false) + serverError("Failed to write new Tor configuration."); + + // Reload Tor + exec(CONF['ht']['sudo_path'] . " " . CONF['ht']['systemctl_path'] . " reload " . CONF['ht']['tor_service'], $output, $code); + if ($code !== 0) + serverError("Failed to reload Tor."); + + // Delete Tor keys + exec(CONF['ht']['sudo_path'] . " -u " . CONF['ht']['tor_user'] . " " . CONF['ht']['rm_path'] . " --recursive " . CONF['ht']['tor_keys_path'] . "/" . $dir, $output, $code); + if ($code !== 0) + serverError("Failed to delete Tor keys."); + } + + // Delete Nginx config + $domain = query('select', 'sites', [ + 'username' => $_SESSION['username'], + 'domain_type' => $domainType, + 'protocol' => $protocol, + 'site_dir' => $dir, + ], 'domain')[0]; + if (unlink(CONF['ht']['nginx_config_path'] . '/' . $domain . '.conf') !== true) + serverError("Failed to delete Nginx configuration."); + + // Reload Nginx + exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['systemctl_path'] . ' reload nginx', result_code: $code); + if ($code !== 0) + serverError("Failed to reload Nginx."); + + // Delete from database + query('delete', 'sites', [ + 'username' => $_SESSION['username'], + 'domain_type' => $domainType, + 'protocol' => $protocol, + 'site_dir' => $dir, + ]); +} diff --git a/fn/ns.php b/fn/ns.php index a598661..378d612 100644 --- a/fn/ns.php +++ b/fn/ns.php @@ -35,3 +35,21 @@ function nsCheckZonePossession($zone) { if (!in_array($zone, query('select', 'zones', ['username' => $_SESSION['username']], 'zone'), true)) userError("You don't own this zone on the nameserver."); } + +function nsDeleteZone($zone) { + // Remove from Knot configuration + knotcConfExec(["unset 'zone[$zone]'"]); + + // Remove Knot zone file + if(unlink(CONF['ns']['knot_zones_path'] . '/' . $zone . 'zone') !== true) + serverError("Failed to remove Knot zone file."); + + // Remove Knot related data + exec(CONF['dns']['knotc_path'] . " zone-purge " . $zone); + + // Remove from database + query('delete', 'zones', [ + 'zone' => $zone, + 'username' => $_SESSION['username'], + ]); +} diff --git a/fn/reg.php b/fn/reg.php index 03953c1..3a8205d 100644 --- a/fn/reg.php +++ b/fn/reg.php @@ -12,3 +12,19 @@ function regCheckDomainPossession($domain) { function regIsFree($domain) { return empty(query('select', 'registry', ['domain' => $domain], 'domain')); } + +function regDeleteDomain($domain) { + // Delete domain from registry file + $regFile = file_get_contents(CONF['reg']['registry_file']); + if ($regFile === false) + serverError("Failed to read current registry File."); + $regFile = preg_replace("#[^\n]{0,1024}" . $domain . " {0,1024}[^\n]{0,1024}\n#", "", $regFile); + if (file_put_contents(CONF['reg']['registry_file'], $regFile) === false) + serverError("Failed to write new registry file."); + + // Delete from Niver's database + query('delete', 'registry', [ + 'domain' => $domain, + 'username' => $_SESSION['username'], + ]); +} diff --git a/public/auth/unregister.php b/public/auth/unregister.php new file mode 100644 index 0000000..2fa7d70 --- /dev/null +++ b/public/auth/unregister.php @@ -0,0 +1,49 @@ + + +
+ + +
+ +
+ + $_SESSION['username']], 'domain') as $domain) + regDeleteDomain($domain); + +foreach (query('select', 'zones', ['username' => $_SESSION['username']], 'zone') as $zone) + nsDeleteZone($zone); + +foreach (query('select', 'sites', [ + 'username' => $_SESSION['username'], + 'domain_type' => 'onion', + 'protocol' => 'http', +], 'site_dir') as $dir) + htDeleteSite($dir, domainType: 'onion', protocol: 'http'); + +foreach (query('select', 'sites', [ + 'username' => $_SESSION['username'], + 'domain_type' => 'dns', + 'protocol' => 'http', +], 'site_dir') as $dir) + htDeleteSite($dir, domainType: 'dns', protocol: 'http'); + +// PHP rmdir() only works on empty directories +$dirObj = new RecursiveDirectoryIterator(CONF['ht']['ht_path'] . "/" . $_SESSION['username'], RecursiveDirectoryIterator::SKIP_DOTS); +$files = new RecursiveIteratorIterator($dirObj, RecursiveIteratorIterator::CHILD_FIRST); +foreach ($files as $path) + $path->isDir() && !$path->isLink() ? rmdir($path->getPathname()) : unlink($path->getPathname()); +if (rmdir(CONF['ht']['ht_path'] . '/' . $_SESSION['username']) !== true) + serverError("Unable to delete user's hypertext directory."); + +query('delete', 'users', ['username' => $_SESSION['username']]); + +redir(); + +success("Compte supprimé."); diff --git a/public/ht/del-http-dns.php b/public/ht/del-http-dns.php index cff8a3d..e4ce180 100644 --- a/public/ht/del-http-dns.php +++ b/public/ht/del-http-dns.php @@ -5,9 +5,9 @@

-
- + - -
- + +
+
dir."); -// Delete Nginx config -$onion = query('select', 'sites', [ - 'username' => $_SESSION['username'], - 'domain_type' => 'dns', - 'protocol' => 'http', - 'site_dir' => $_POST['dir'], -], 'domain')[0]; -if (unlink(CONF['ht']['nginx_config_path'] . "/" . $onion . ".conf") !== true) - serverError("Failed to delete Nginx configuration."); +htDeleteSite($_POST['dir'], domainType: 'dns', protocol: 'http'); -// Reload Nginx -exec(CONF['ht']['sudo_path'] . " " . CONF['ht']['systemctl_path'] . " reload nginx", result_code: $code); -if ($code !== 0) - serverError("Failed to reload Nginx."); - -// Delete from database -query('delete', 'sites', [ - 'username' => $_SESSION['username'], - 'domain_type' => 'dns', - 'protocol' => 'http', - 'site_dir' => $_POST['dir'], -]); - -success("Accès retiré avec succès."); +success("Accès retiré."); diff --git a/public/ht/del-http-onion.php b/public/ht/del-http-onion.php index 31d75a8..7ed6222 100644 --- a/public/ht/del-http-onion.php +++ b/public/ht/del-http-onion.php @@ -34,47 +34,6 @@ switchToFormProcess(); if ($dirsStatuses[$_POST['dir']] !== true) userError("Wrong value for dir."); -// Delete Tor config -$torConf = file_get_contents(CONF['ht']['tor_config_path']); -if ($torConf === false) - serverError("Failed to read current Tor configuration."); -$torConf = str_replace("HiddenServiceDir " . CONF['ht']['tor_keys_path'] . "/" . $_POST['dir'] . "/ -HiddenServicePort 80 [::1]:" . CONF['ht']['internal_onion_http_port'] . " -", "", $torConf); -if (file_put_contents(CONF['ht']['tor_config_path'], $torConf) === false) - serverError("Failed to write new Tor configuration."); +htDeleteSite($_POST['dir'], domainType: 'onion', protocol: 'http'); -// Reload Tor -exec(CONF['ht']['sudo_path'] . " " . CONF['ht']['systemctl_path'] . " reload " . CONF['ht']['tor_service'], $output, $code); -if ($code !== 0) - serverError("Failed to reload Tor."); - -// Delete Tor keys -exec(CONF['ht']['sudo_path'] . " -u " . CONF['ht']['tor_user'] . " " . CONF['ht']['rm_path'] . " --recursive " . CONF['ht']['tor_keys_path'] . "/" . $_POST['dir'], $output, $code); -if ($code !== 0) - serverError("Failed to delete Tor keys."); - -// Delete Nginx config -$onion = query('select', 'sites', [ - 'username' => $_SESSION['username'], - 'domain_type' => 'onion', - 'protocol' => 'http', - 'site_dir' => $_POST['dir'], -], 'domain')[0]; -if (unlink(CONF['ht']['nginx_config_path'] . "/" . $onion . ".conf") !== true) - serverError("Failed to delete Nginx configuration."); - -// Reload Nginx -exec(CONF['ht']['sudo_path'] . " " . CONF['ht']['systemctl_path'] . " reload nginx", result_code: $code); -if ($code !== 0) - serverError("Failed to reload Nginx."); - -// Delete from database -query('delete', 'sites', [ - 'username' => $_SESSION['username'], - 'domain_type' => 'onion', - 'protocol' => 'http', - 'site_dir' => $_POST['dir'], -]); - -success("Accès retiré avec succès."); +success("Accès retiré."); diff --git a/public/ns/caa.php b/public/ns/caa.php index f4bd0bc..9cf4685 100644 --- a/public/ns/caa.php +++ b/public/ns/caa.php @@ -36,7 +36,7 @@ if (!(preg_match("/^[a-z]{1,127}$/", $_POST['tag']))) if (!(preg_match("/^[a-z0-9.-]{1,255}$/", $_POST['value']))) userError("Wrong value for value."); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "CAA", diff --git a/public/ns/ip.php b/public/ns/ip.php index 80e5ffc..4e0c0bf 100644 --- a/public/ns/ip.php +++ b/public/ns/ip.php @@ -20,7 +20,7 @@ $values = nsParseCommonRequirements(); $record = checkIpFormat($_POST['ip']); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], $record, diff --git a/public/ns/mx.php b/public/ns/mx.php index 89d51ad..3b6daab 100644 --- a/public/ns/mx.php +++ b/public/ns/mx.php @@ -31,7 +31,7 @@ if (!($_POST['priority'] >= 0 AND $_POST['priority'] <= 255)) $_POST['host'] = formatAbsoluteDomain($_POST['host']); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "MX", diff --git a/public/ns/ns.php b/public/ns/ns.php index d6b3695..e0886db 100644 --- a/public/ns/ns.php +++ b/public/ns/ns.php @@ -18,7 +18,7 @@ $values = nsParseCommonRequirements(); $_POST['ns'] = formatAbsoluteDomain($_POST['ns']); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "NS", diff --git a/public/ns/srv.php b/public/ns/srv.php index bfd68ba..4f1ca0b 100644 --- a/public/ns/srv.php +++ b/public/ns/srv.php @@ -49,7 +49,7 @@ if (!($_POST['port'] >= 0 AND $_POST['port'] <= 65535)) $_POST['target'] = formatAbsoluteDomain($_POST['target']); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "SRV", diff --git a/public/ns/sshfp.php b/public/ns/sshfp.php index 55232f6..974aee2 100644 --- a/public/ns/sshfp.php +++ b/public/ns/sshfp.php @@ -48,7 +48,7 @@ if (!($_POST['type'] === "2")) if (!(preg_match("/^[a-z0-9]{64}$/", $_POST['fp']))) userError("Wrong value for fp."); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "SSHFP", diff --git a/public/ns/tlsa.php b/public/ns/tlsa.php index e1fb755..77133d7 100644 --- a/public/ns/tlsa.php +++ b/public/ns/tlsa.php @@ -60,7 +60,7 @@ if (!($_POST['type'] >= 0 AND $_POST['type'] <= 2)) if (!(preg_match("/^[a-zA-Z0-9.-]{1,1024}$/", $_POST['content']))) userError("Wrong value for content."); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "TLSA", diff --git a/public/ns/txt.php b/public/ns/txt.php index 21c7cbb..fba0aa4 100644 --- a/public/ns/txt.php +++ b/public/ns/txt.php @@ -19,7 +19,7 @@ $values = nsParseCommonRequirements(); if (!(preg_match("/^[a-zA-Z0-9 =:!%$+\/\()[\]_-]{5,8192}$/", $_POST['txt']))) userError("Wrong value for txt."); -knotcExec($_POST['zone'], array( +knotcZoneExec($_POST['zone'], array( $values['domain'], $values['ttl'], "TXT", diff --git a/public/ns/zone-add.php b/public/ns/zone-add.php index a8d910a..711641e 100644 --- a/public/ns/zone-add.php +++ b/public/ns/zone-add.php @@ -29,9 +29,9 @@ if (is_int(file_put_contents($knotZonePath, $knotZone)) !== true) if (chmod($knotZonePath, 0660) !== true) serverError("Failed to chmod new zone file."); -exec(CONF['dns']['knotc_path'] . " conf-begin"); -exec(CONF['dns']['knotc_path'] . " conf-set 'zone[" . $_POST['domain'] . "]'"); -exec(CONF['dns']['knotc_path'] . " conf-set 'zone[" . $_POST['domain'] . "].template' 'niver'"); -exec(CONF['dns']['knotc_path'] . " conf-commit"); +knotcConfExec([ + "set 'zone[" . $_POST['domain'] . "]'", + "set 'zone[" . $_POST['domain'] . "].template' 'niver'", +]); success("La requête a été traitée."); diff --git a/public/ns/zone-del.php b/public/ns/zone-del.php index 0ae5e17..32d8d37 100644 --- a/public/ns/zone-del.php +++ b/public/ns/zone-del.php @@ -20,22 +20,6 @@ switchToFormProcess(); nsCheckZonePossession($_POST['zone']); -// Remove from Knot configuration -exec(CONF['dns']['knotc_path'] . " conf-begin"); -exec(CONF['dns']['knotc_path'] . " conf-unset 'zone[" . $_POST['zone'] . "]'"); -exec(CONF['dns']['knotc_path'] . " conf-commit"); - -// Remove Knot zone file -if(unlink(CONF['ns']['knot_zones_path'] . "/" . $_POST['zone'] . "zone") !== true) - serverError("Failed to remove Knot zone file."); - -// Remove Knot related data -exec(CONF['dns']['knotc_path'] . " zone-purge " . $_POST['zone']); - -// Remove from database -query('delete', 'zones', [ - 'zone' => $_POST['zone'], - 'username' => $_SESSION['username'], -]); +nsDeleteZone($_POST['zone']); success("Zone effacée."); diff --git a/public/reg/ds.php b/public/reg/ds.php index 2223f68..1e1a9d6 100644 --- a/public/reg/ds.php +++ b/public/reg/ds.php @@ -86,7 +86,7 @@ regCheckDomainPossession($_POST['zone']); $action = checkAction($_POST['action']); -knotcExec(CONF['reg']['registry'], array( +knotcZoneExec(CONF['reg']['registry'], array( $_POST['zone'], CONF['reg']['ttl'], "DS", diff --git a/public/reg/glue.php b/public/reg/glue.php index 246e9ff..06ccbbe 100644 --- a/public/reg/glue.php +++ b/public/reg/glue.php @@ -45,7 +45,7 @@ $domain = formatAbsoluteDomain(formatEndWithDot($_POST['subdomain']) . $_POST['s $record = checkIpFormat($_POST['ip']); -knotcExec(CONF['reg']['registry'], array( +knotcZoneExec(CONF['reg']['registry'], array( $domain, CONF['reg']['ttl'], $record, diff --git a/public/reg/ns.php b/public/reg/ns.php index 3f1043e..2f6fbba 100644 --- a/public/reg/ns.php +++ b/public/reg/ns.php @@ -13,8 +13,8 @@ ." . $suffix . "\n"; + foreach(regListUserDomains($_SESSION['username']) as $domain) + echo " \n"; ?> @@ -33,7 +33,7 @@ switchToFormProcess(); regCheckDomainPossession($_POST['domain']); $_POST['ns'] = formatAbsoluteDomain($_POST['ns']); -knotcExec(CONF['reg']['registry'], array( +knotcZoneExec(CONF['reg']['registry'], array( $_POST['domain'], CONF['reg']['ttl'], "NS", diff --git a/public/reg/unregister.php b/public/reg/unregister.php index 42e88b4..c1c39f9 100644 --- a/public/reg/unregister.php +++ b/public/reg/unregister.php @@ -7,8 +7,8 @@ ." . $suffix . "\n"; + foreach(regListUserDomains($_SESSION['username']) as $domain) + echo " \n"; ?> @@ -22,21 +22,6 @@ switchToFormProcess(); regCheckDomainPossession($_POST['domain']); -// Add Tor config -$regFile = file_get_contents(CONF['reg']['registry_file']); -if ($regFile === false) - serverError("Failed to read current registry File."); -$regFile = preg_replace("#[^\n]{0,1024}" . $_POST['domain'] . " {0,1024}[^\n]{0,1024}\n#", "", $regFile); -if (file_put_contents(CONF['reg']['registry_file'], $regFile) === false) - serverError("Failed to write new registry file."); - -// Remove from Niver's database -$db = new PDO('sqlite:' . DB_PATH); -$stmt = $db->prepare("DELETE FROM registry WHERE domain = :domain AND username = :username"); - -$stmt->bindValue(':domain', $_POST['domain']); -$stmt->bindValue(':username', $_SESSION['username']); - -$stmt->execute(); +regDeleteDomain($_POST['domain']); success("Domaine effacé du registre."); diff --git a/sftpgo-auth.php b/sftpgo-auth.php index 126c3c5..6da3772 100644 --- a/sftpgo-auth.php +++ b/sftpgo-auth.php @@ -1,7 +1,6 @@