diff --git a/config.ini b/config.ini
index ce84e74..cc94ba0 100644
--- a/config.ini
+++ b/config.ini
@@ -31,6 +31,13 @@ enabled = true
; Path were user's sites will be stored
ht_path = "/srv/niver/ht"
+
+subpath_domain = "ht.niver.test"
+subpath_path = "/srv/niver/subpath"
+
+subdomain_domain = "ht.niver.test"
+subdomain_path = "/srv/niver/subdomain"
+
; Nginx configuration directory
nginx_config_path = "/srv/niver/nginx"
nginx_reload_cmd = "/usr/bin/systemctl reload nginx"
@@ -58,7 +65,7 @@ ipv4_address = "127.0.0.1"
sftp_pub = "/etc/sftpgo/ed25519.pub"
sftp_fp = "/etc/sftpgo/ed25519.fp"
sftp_asciiart = "/etc/sftpgo/ed25519.asciiart"
-sftp_domain = "ht.niver.test"
+sftp_domain = "sftp.niver.test"
public_sftp_port = 2022
; Will be used in configuration files
diff --git a/db/schema.sql b/db/schema.sql
index a50e99c..d99c4b8 100644
--- a/db/schema.sql
+++ b/db/schema.sql
@@ -39,11 +39,12 @@ CREATE TABLE IF NOT EXISTS "zones" (
CREATE TABLE IF NOT EXISTS "sites" (
"username" TEXT NOT NULL,
"site_dir" TEXT NOT NULL,
- "domain" TEXT NOT NULL UNIQUE,
- "domain_type" TEXT NOT NULL,
- "protocol" TEXT NOT NULL,
+ "address" TEXT NOT NULL,
+ "type" TEXT NOT NULL,
"creation_date" TEXT NOT NULL,
- PRIMARY KEY("domain"),
+ UNIQUE("address", "type"),
+ UNIQUE("username", "site_dir", "type"),
+ PRIMARY KEY("address", "type"),
FOREIGN KEY("username") REFERENCES "users"("id")
);
COMMIT;
diff --git a/fn/ht.php b/fn/ht.php
index 6c6d9c3..9a90044 100644
--- a/fn/ht.php
+++ b/fn/ht.php
@@ -21,24 +21,22 @@ function listFsDirs($username) {
return $dirs;
}
-function addSite($username, $siteDir, $domain, $domainType, $protocol) {
+function addSite($username, $siteDir, $address, $type) {
insert('sites', [
'username' => $username,
'site_dir' => $siteDir,
- 'domain' => $domain,
- 'domain_type' => $domainType,
- 'protocol' => $protocol,
+ 'address' => $address,
+ 'type' => $type,
'creation_date' => date('Y-m-d H:i:s'),
]);
}
-function dirsStatuses($domainType, $protocol) {
+function dirsStatuses($type) {
if (isset($_SESSION['id']) !== true)
return [];
$dbDirs = query('select', 'sites', [
'username' => $_SESSION['id'],
- 'domain_type' => $domainType,
- 'protocol' => $protocol,
+ 'type' => $type,
], 'site_dir');
$dirs = [];
foreach (listFsDirs($_SESSION['id']) as $fsDir)
@@ -46,9 +44,31 @@ function dirsStatuses($domainType, $protocol) {
return $dirs;
}
-function htDeleteSite($dir, $domainType, $protocol) {
+function htDeleteSite($address, $type) {
+ match ($type) {
+ 'onion', 'dns' => htDeleteDedicatedSite($address, $type),
+ 'subpath', 'subdomain' => htDeleteSubSite($address, $type)
+ };
+}
- if ($domainType === 'onion') {
+function htDeleteSubSite($address, $type) {
+ if (unlink(CONF['ht'][$type . '_path'] . '/' . $address) !== true)
+ output(500, 'Unable to delete symlink.');
+
+ query('delete', 'sites', [
+ 'username' => $_SESSION['id'],
+ 'type' => $type,
+ 'address' => $address,
+ ]);
+}
+
+function htDeleteDedicatedSite($address, $type) {
+ $dir = query('select', 'sites', [
+ 'address' => $address,
+ 'type' => $type,
+ ], 'site_dir')[0];
+
+ if ($type === 'onion') {
// Delete Tor config
if (unlink(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id'] . '/' . $dir) !== true)
output(500, 'Failed to delete Tor configuration.');
@@ -65,13 +85,7 @@ function htDeleteSite($dir, $domainType, $protocol) {
}
// Delete Nginx config
- $domain = query('select', 'sites', [
- 'username' => $_SESSION['id'],
- 'domain_type' => $domainType,
- 'protocol' => $protocol,
- 'site_dir' => $dir,
- ], 'domain')[0];
- if (unlink(CONF['ht']['nginx_config_path'] . '/' . $domain . '.conf') !== true)
+ if (unlink(CONF['ht']['nginx_config_path'] . '/' . $address . '.conf') !== true)
output(500, 'Failed to delete Nginx configuration.');
// Reload Nginx
@@ -79,9 +93,9 @@ function htDeleteSite($dir, $domainType, $protocol) {
if ($code !== 0)
output(500, 'Failed to reload Nginx.');
- if ($domainType === 'dns') {
+ if ($type === 'dns') {
// Delete Let's Encrypt certificate
- exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' delete --quiet --cert-name ' . $domain, $output, $code);
+ exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' delete --quiet --cert-name ' . $address, $output, $code);
if ($code !== 0)
output(500, 'Certbot failed to delete the Let\'s Encrypt certificate.');
}
@@ -89,8 +103,7 @@ function htDeleteSite($dir, $domainType, $protocol) {
// Delete from database
query('delete', 'sites', [
'username' => $_SESSION['id'],
- 'domain_type' => $domainType,
- 'protocol' => $protocol,
+ 'type' => $type,
'site_dir' => $dir,
]);
}
diff --git a/pages.php b/pages.php
index b433d01..220aebe 100644
--- a/pages.php
+++ b/pages.php
@@ -149,23 +149,29 @@ define('PAGES', [
'title' => '' . CONF['ht']['subpath_domain'] . '/
',
+ 'description' => 'Son URL ressemblera Ă https://' . CONF['ht']['subpath_domain'] . '/monsite/
',
+ 'tokens_account_cost' => 900,
],
- 'add-http-onion' => [
- 'title' => 'Ajouter un accès HTTP par Onion',
- 'description' => 'Ajouter un accès HTTP par ' . linkToDocs('tor', 'service Onion') . ' sur un sous-dossier de l\'espace SFTP',
+ 'add-subdomain' => [
+ 'title' => 'Accès par sous-domaine de .' . CONF['ht']['subdomain_domain'] . '
',
+ 'description' => 'Son URL ressemblera Ă https://monsite.' . CONF['ht']['subpath_domain'] . '/
',
'tokens_account_cost' => 1800,
],
- 'del-http-dns' => [
- 'title' => 'Retirer un accès HTTP par DNS+TLS',
- 'description' => 'Retirer un accès HTTP par DNS et TLS d\'un sous-dossier de l\'espace SFTP',
+ 'add-dns' => [
+ 'title' => 'Accès par domaine dédié et certificat Let\'s Encrypt',
+ 'description' => 'Son URL ressemblera Ă https://monsite.example/
',
+ 'tokens_account_cost' => 3600,
],
- 'del-http-onion' => [
- 'title' => 'Retirer un accès HTTP par Onion',
- 'description' => 'Retirer un accès HTTP par service Onion d\'un sous-dossier de l\'espace SFTP',
+ 'add-onion' => [
+ 'title' => 'Accès par service Onion',
+ 'description' => 'Son URL ressemblera Ă http://nrdselxjgryq5fwek2xh3pxg4b26z26eyzlbs4y5lownk465jhaamayd.onion/
, qui ne fonctionnera que par le réseau Tor',
+ 'tokens_account_cost' => 1800,
+ ],
+ 'del' => [
+ 'title' => 'Retirer un accès',
+ 'description' => 'Retirer un accès HTTP déjà existant d\'un sous-dossier de l\'espace SFTP',
],
],
]);
diff --git a/pg-act/auth/unregister.php b/pg-act/auth/unregister.php
index 23ccdb1..185dbf7 100644
--- a/pg-act/auth/unregister.php
+++ b/pg-act/auth/unregister.php
@@ -9,19 +9,8 @@ foreach (query('select', 'registry', ['username' => $_SESSION['id']], 'domain')
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
nsDeleteZone($zone);
-foreach (query('select', 'sites', [
- 'username' => $_SESSION['id'],
- 'domain_type' => 'onion',
- 'protocol' => 'http',
-], 'site_dir') as $dir)
- htDeleteSite($dir, domainType: 'onion', protocol: 'http');
-
-foreach (query('select', 'sites', [
- 'username' => $_SESSION['id'],
- 'domain_type' => 'dns',
- 'protocol' => 'http',
-], 'site_dir') as $dir)
- htDeleteSite($dir, domainType: 'dns', protocol: 'http');
+foreach (query('select', 'sites', ['username' => $_SESSION['id']]) as $site)
+ htDeleteSite($site['address'], $site['type']);
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['tor_keys_path'] . '/' . $_SESSION['id'], result_code: $code);
if ($code !== 0)
diff --git a/pg-act/ht/add-http-dns.php b/pg-act/ht/add-dns.php
similarity index 93%
rename from pg-act/ht/add-http-dns.php
rename to pg-act/ht/add-dns.php
index 893dc48..8ceebee 100644
--- a/pg-act/ht/add-http-dns.php
+++ b/pg-act/ht/add-dns.php
@@ -2,7 +2,7 @@
$_POST['domain'] = formatDomain($_POST['domain']);
-if (dirsStatuses('dns', 'http')[$_POST['dir']] !== false)
+if (dirsStatuses('dns')[$_POST['dir']] !== false)
output(403, 'Wrong value for dir
.');
if (query('select', 'sites', ['domain' => $_POST['domain']], 'domain') !== [])
@@ -30,7 +30,7 @@ checkAuthToken($matches[1], $matches[2]);
rateLimit();
-addSite($_SESSION['id'], $_POST['dir'], $_POST['domain'], 'dns', 'http');
+addSite($_SESSION['id'], $_POST['dir'], $_POST['domain'], 'dns');
exec('2>&1 ' . CONF['ht']['sudo_path'] . ' ' . CONF['ht']['certbot_path'] . ' certonly' . (($_SESSION['type'] === 'approved') ? '' : ' --test-cert') . ' --key-type rsa --rsa-key-size 3072 --webroot --webroot-path /srv/niver/acme --domain ' . $_POST['domain'], $output, $returnCode);
if ($returnCode !== 0)
@@ -56,4 +56,4 @@ exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['nginx_reload_cmd'], result_code
if ($code !== 0)
output(500, 'Failed to reload Nginx.');
-output(200, 'Accès HTTP par domaine ajouté sur ce dossier !');
+output(200, 'Accès HTTP par domaine dédié ajouté sur ce dossier !');
diff --git a/pg-act/ht/add-http-onion.php b/pg-act/ht/add-onion.php
similarity index 93%
rename from pg-act/ht/add-http-onion.php
rename to pg-act/ht/add-onion.php
index 679458d..eb078b1 100644
--- a/pg-act/ht/add-http-onion.php
+++ b/pg-act/ht/add-onion.php
@@ -1,6 +1,6 @@
dir.');
rateLimit();
@@ -24,7 +24,7 @@ if (preg_match('/^[0-9a-z]{56}\.onion$/D', $onion) !== 1)
output(500, 'No onion address found.');
// Store it in the database
-addSite($_SESSION['id'], $_POST['dir'], $onion, 'onion', 'http');
+addSite($_SESSION['id'], $_POST['dir'], $onion, 'onion');
// Add Nginx config
$nginxConf = 'server {
diff --git a/pg-act/ht/add-subdomain.php b/pg-act/ht/add-subdomain.php
new file mode 100644
index 0000000..2d333b9
--- /dev/null
+++ b/pg-act/ht/add-subdomain.php
@@ -0,0 +1,19 @@
+dir.');
+
+if (preg_match('/^[a-z0-9]{1,32}$/D', $_POST['subdomain']) !== 1)
+ output(403, 'Label de domaine invalide.');
+
+if (query('select', 'sites', ['address' => $_POST['subdomain'], 'type' => 'subdomain']) !== [])
+ output(403, 'Ce domaine est déjà utilisé sur ce service. Utilisez-en un autre.');
+
+rateLimit();
+
+addSite($_SESSION['id'], $_POST['dir'], $_POST['subdomain'], 'subdomain');
+
+if (symlink(CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['subdomain_path'] . '/' . $_POST['subdomain']) !== true)
+ output(500, 'Unable to create symlink.');
+
+output(200, 'Accès HTTP par sous-chemin ajouté sur ce dossier !');
diff --git a/pg-act/ht/add-subpath.php b/pg-act/ht/add-subpath.php
new file mode 100644
index 0000000..3f300b7
--- /dev/null
+++ b/pg-act/ht/add-subpath.php
@@ -0,0 +1,19 @@
+dir.');
+
+if (preg_match('/^[a-z0-9]{1,32}$/D', $_POST['path']) !== 1)
+ output(403, 'Chemin invalide.');
+
+if (query('select', 'sites', ['address' => $_POST['path'], 'type' => 'subpath']) !== [])
+ output(403, 'Ce chemin est déjà utilisé sur ce service. Utilisez-en un autre.');
+
+rateLimit();
+
+addSite($_SESSION['id'], $_POST['dir'], $_POST['path'], 'subpath');
+
+if (symlink(CONF['ht']['ht_path'] . '/' . $_SESSION['id'] . '/' . $_POST['dir'], CONF['ht']['subpath_path'] . '/' . $_POST['path']) !== true)
+ output(500, 'Unable to create symlink.');
+
+output(200, 'Accès HTTP par sous-chemin ajouté sur ce dossier !');
diff --git a/pg-act/ht/del-http-dns.php b/pg-act/ht/del-http-dns.php
deleted file mode 100644
index 9664888..0000000
--- a/pg-act/ht/del-http-dns.php
+++ /dev/null
@@ -1,8 +0,0 @@
-dir.');
-
-htDeleteSite($_POST['dir'], domainType: 'dns', protocol: 'http');
-
-output(200, 'Accès retiré.');
diff --git a/pg-act/ht/del-http-onion.php b/pg-act/ht/del-http-onion.php
deleted file mode 100644
index fe46a41..0000000
--- a/pg-act/ht/del-http-onion.php
+++ /dev/null
@@ -1,8 +0,0 @@
-dir.');
-
-htDeleteSite($_POST['dir'], domainType: 'onion', protocol: 'http');
-
-output(200, 'Accès retiré.');
diff --git a/pg-act/ht/del.php b/pg-act/ht/del.php
new file mode 100644
index 0000000..b5fe7b4
--- /dev/null
+++ b/pg-act/ht/del.php
@@ -0,0 +1,11 @@
+subpath|subdomain|onion|dns):(?
site
.');
+
+if (isset(query('select', 'sites', ['username' => $_SESSION['id'], 'address' => $site['address'], 'type' => $site['type']], 'address')[0]) !== true)
+ output(403, 'Unavailable value for site
.');
+
+htDeleteSite($site['address'], $site['type']);
+
+output(200, 'Accès retiré.');
diff --git a/pg-view/ht/add-http-dns.php b/pg-view/ht/add-dns.php
similarity index 86%
rename from pg-view/ht/add-http-dns.php
rename to pg-view/ht/add-dns.php
index dade10a..067a2a9 100644
--- a/pg-view/ht/add-http-dns.php
+++ b/pg-view/ht/add-dns.php
@@ -3,7 +3,7 @@
- La présence des enregistrements ci-après sera vérifiée lors du traitement de ce formulaire. + Le domaine doit posséder les enregistrements ci-après lors du traitement de ce formulaire.
- Ajouter un accès en .onion sur un dossier + Ajouter un accès par = linkToDocs('tor', 'service Onion') ?> sur un dossier.
+ Ajouter sur un dossier de site un accès = linkToDocs('http', 'HTTP') ?> par sous-chemin de = CONF['ht']['subpath_domain'] ?>/
.
+
- Retirer un accès DNS et TLS d'un dossier -
- - diff --git a/pg-view/ht/del-http-onion.php b/pg-view/ht/del-http-onion.php deleted file mode 100644 index 958f5c9..0000000 --- a/pg-view/ht/del-http-onion.php +++ /dev/null @@ -1,16 +0,0 @@ -- Retirer un accès Onion d'un dossier -
- - diff --git a/pg-view/ht/del.php b/pg-view/ht/del.php new file mode 100644 index 0000000..66c44ea --- /dev/null +++ b/pg-view/ht/del.php @@ -0,0 +1,23 @@ ++ Retirer un accès HTTP d'un dossier +
+ + diff --git a/pg-view/ht/index.php b/pg-view/ht/index.php index d2a0391..d029d26 100644 --- a/pg-view/ht/index.php +++ b/pg-view/ht/index.php @@ -15,7 +15,12 @@ if ($sites === []) else { echo '/= $site['site_dir'] ?>
/<nom du site>/*
. Indiquez les données ci-dessous à votre client SFTP pour y accéder.
+?>. Indiquez les données ci-dessous à votre client SFTP pour y accéder.
- La compression gzip est supportée, si le client le supporte et que le fichier est disponible, chemin.gz
est servi au lieu de chemin
.
+ La compression gzip statique est supportée, si le client le supporte et que le fichier est disponible, chemin.gz
est servi au lieu de chemin
.
- Lors d'une requête sur un dossier, le premier des fichiers suivants qui existe dans ce dossier est répondu : + Lors d'une requête sur un dossier, le premier des fichiers suivants qui existe dans ce dossier est répondu :
index.html
- Lors d'une requĂŞte aboutissant Ă une erreur 404
, le premier des fichiers suivants qui existe à la racine du site est répondu :
+ Lors d'une requĂŞte aboutissant Ă une erreur 404
, le premier des fichiers suivants qui existe à la racine du site est répondu :
404.html