Advanced services status management
This commit is contained in:
parent
a95f6203eb
commit
abb9aabf5b
|
@ -32,6 +32,15 @@ String defining the displayed identity of the service.
|
||||||
|
|
||||||
Pretty string sometimes prefixed to the service name. Can be empty.
|
Pretty string sometimes prefixed to the service name. Can be empty.
|
||||||
|
|
||||||
|
### `services[]`
|
||||||
|
|
||||||
|
Keys `reg`, `ns` and `ht` are required.
|
||||||
|
|
||||||
|
Values can be:
|
||||||
|
* `enabled`: the service is provided as usual
|
||||||
|
* `error`: the service is temporarily unavailable for maintenance/debugging
|
||||||
|
* `disabled`: the service is ignored everywhere ; this installation never provides it
|
||||||
|
|
||||||
## `[dns]`
|
## `[dns]`
|
||||||
|
|
||||||
This configuration section is used by both the registry (`reg`) and the public name server (`ns`).
|
This configuration section is used by both the registry (`reg`) and the public name server (`ns`).
|
||||||
|
@ -46,10 +55,6 @@ Filesystem path to the `kdig` binary. Used to authenticate resources possession
|
||||||
|
|
||||||
## `[reg]`
|
## `[reg]`
|
||||||
|
|
||||||
### `enabled`
|
|
||||||
|
|
||||||
Defines whether the web interface for this service is accessible.
|
|
||||||
|
|
||||||
### `suffixes[]`
|
### `suffixes[]`
|
||||||
|
|
||||||
Lists the suffixes that the registry manages.
|
Lists the suffixes that the registry manages.
|
||||||
|
@ -78,10 +83,6 @@ Host where the Knot DNS server answers the registry values. Should be a secure (
|
||||||
|
|
||||||
## `[ns]`
|
## `[ns]`
|
||||||
|
|
||||||
### `enabled`
|
|
||||||
|
|
||||||
Defines whether the web interface for this service is accessible.
|
|
||||||
|
|
||||||
### `knot_zones_path`
|
### `knot_zones_path`
|
||||||
|
|
||||||
Filesystem path to the zones directory. The full path to created zonefiles will be `knot_zones_path/<zone-apex-domain>.zone`.
|
Filesystem path to the zones directory. The full path to created zonefiles will be `knot_zones_path/<zone-apex-domain>.zone`.
|
||||||
|
@ -102,10 +103,6 @@ Administrator email address published in every SOA record. Ends with a `.`, `@`
|
||||||
|
|
||||||
## `[ht]`
|
## `[ht]`
|
||||||
|
|
||||||
### `enabled`
|
|
||||||
|
|
||||||
Defines whether the web interface for this service is accessible. (Users can still use SFTP.)
|
|
||||||
|
|
||||||
### `ht_path`
|
### `ht_path`
|
||||||
|
|
||||||
Filesystem path to the users files base directory. Files of a user are located inside `ht_path/<their-internal-user-id>/`
|
Filesystem path to the users files base directory. Files of a user are located inside `ht_path/<their-internal-user-id>/`
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
## As a developer
|
## As a developer
|
||||||
|
|
||||||
Extract messages to be translated from the source files and into a Portable Object Template file:
|
Extract messages to be translated from the source files and into a Portable Object Template file:
|
||||||
```
|
```shell
|
||||||
xgettext --from-code=UTF-8 --no-wrap -d messages -p locales/ --from-code=UTF-8 *.php */*.php */*/*.php
|
xgettext --from-code=UTF-8 --no-wrap -d messages -p locales/ *.php */*.php */*/*.php
|
||||||
mv locales/messages.po locales/messages.pot
|
mv locales/messages.po locales/messages.pot
|
||||||
```
|
```
|
||||||
|
|
||||||
Merge messages into existing Portable Objects:
|
Merge messages into existing Portable Objects:
|
||||||
```
|
```shell
|
||||||
msgmerge --no-wrap locales/fr/C/LC_MESSAGES/messages.po locales/messages.pot -o locales/fr/C/LC_MESSAGES/messages.po
|
msgmerge --no-wrap locales/fr/C/LC_MESSAGES/messages.po locales/messages.pot -o locales/fr/C/LC_MESSAGES/messages.po
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ msgmerge --no-wrap locales/fr/C/LC_MESSAGES/messages.po locales/messages.pot -o
|
||||||
|
|
||||||
### To start a new translation
|
### To start a new translation
|
||||||
|
|
||||||
```
|
```shell
|
||||||
mkdir -p locales/fr/C/LC_MESSAGES/
|
mkdir -p locales/fr/C/LC_MESSAGES/
|
||||||
msginit -i locales/messages.pot -o locales/fr/C/LC_MESSAGES/messages.po
|
msginit -i locales/messages.pot -o locales/fr/C/LC_MESSAGES/messages.po
|
||||||
```
|
```
|
||||||
|
@ -26,12 +26,12 @@ msginit -i locales/messages.pot -o locales/fr/C/LC_MESSAGES/messages.po
|
||||||
|
|
||||||
Edit `locales/fr/C/LC_MESSAGES/messages.po` using either
|
Edit `locales/fr/C/LC_MESSAGES/messages.po` using either
|
||||||
* any text editor
|
* any text editor
|
||||||
* a dedicated translation software like [Poedit](https://poedit.net/), [KDE's Lokalize](https://apps.kde.org/lokalize/) or [GNOME Translation Editor](https://wiki.gnome.org/Apps/Gtranslator).
|
* dedicated translation software like [Poedit](https://poedit.net/), [KDE's Lokalize](https://apps.kde.org/lokalize/) or [GNOME Translation Editor](https://wiki.gnome.org/Apps/Gtranslator).
|
||||||
|
|
||||||
## As an administrator
|
## As an administrator
|
||||||
|
|
||||||
To compile Portable Objects into Machine Objects:
|
To compile Portable Objects into Machine Objects:
|
||||||
```
|
```shell
|
||||||
msgfmt locales/fr/C/LC_MESSAGES/messages.po -o locales/fr/C/LC_MESSAGES/messages.mo
|
msgfmt locales/fr/C/LC_MESSAGES/messages.po -o locales/fr/C/LC_MESSAGES/messages.mo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -6,13 +6,15 @@ public_domains[] = "servnest.test"
|
||||||
prefix = ""
|
prefix = ""
|
||||||
service_name = "ServNest"
|
service_name = "ServNest"
|
||||||
service_emoji = "🪺"
|
service_emoji = "🪺"
|
||||||
|
services[reg] = "enabled"
|
||||||
|
services[ns] = "enabled"
|
||||||
|
services[ht] = "enabled"
|
||||||
|
|
||||||
[dns]
|
[dns]
|
||||||
knotc_path = "/usr/sbin/knotc"
|
knotc_path = "/usr/sbin/knotc"
|
||||||
kdig_path = "/usr/bin/kdig"
|
kdig_path = "/usr/bin/kdig"
|
||||||
|
|
||||||
[reg]
|
[reg]
|
||||||
enabled = true
|
|
||||||
suffixes[servnest.test.] = "approved"
|
suffixes[servnest.test.] = "approved"
|
||||||
suffixes[test.servnest.test.] = "all"
|
suffixes[test.servnest.test.] = "all"
|
||||||
suffixes[old.sernnest.test.] = "none"
|
suffixes[old.sernnest.test.] = "none"
|
||||||
|
@ -21,7 +23,6 @@ ttl = 86400
|
||||||
address = "[::1]:42053"
|
address = "[::1]:42053"
|
||||||
|
|
||||||
[ns]
|
[ns]
|
||||||
enabled = true
|
|
||||||
knot_zones_path = "/srv/servnest/ns"
|
knot_zones_path = "/srv/servnest/ns"
|
||||||
servers[] = "ns1.servnest.test."
|
servers[] = "ns1.servnest.test."
|
||||||
servers[] = "ns2.servnest.test."
|
servers[] = "ns2.servnest.test."
|
||||||
|
@ -29,8 +30,6 @@ kzonecheck_path = "/usr/bin/kzonecheck"
|
||||||
public_soa_email = "hostmaster.invalid."
|
public_soa_email = "hostmaster.invalid."
|
||||||
|
|
||||||
[ht]
|
[ht]
|
||||||
enabled = true
|
|
||||||
|
|
||||||
ht_path = "/srv/servnest/ht"
|
ht_path = "/srv/servnest/ht"
|
||||||
|
|
||||||
subpath_domain = "ht.servnest.test"
|
subpath_domain = "ht.servnest.test"
|
||||||
|
|
|
@ -4,11 +4,11 @@ CREATE TABLE IF NOT EXISTS "params" (
|
||||||
"value" TEXT NOT NULL,
|
"value" TEXT NOT NULL,
|
||||||
PRIMARY KEY("name")
|
PRIMARY KEY("name")
|
||||||
);
|
);
|
||||||
INSERT INTO "params"("name", "value") VALUES("instance_bucket_tokens", "0");
|
INSERT INTO "params"("name", "value") VALUES('instance_bucket_tokens', '0');
|
||||||
INSERT INTO "params"("name", "value") VALUES("instance_bucket_last_update", "0");
|
INSERT INTO "params"("name", "value") VALUES('instance_bucket_last_update', '0');
|
||||||
INSERT INTO "params"("name", "value") VALUES("secret_key", "0");
|
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,
|
||||||
"username" TEXT NOT NULL UNIQUE,
|
"username" TEXT NOT NULL UNIQUE,
|
||||||
|
@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS "users" (
|
||||||
"bucket_tokens" INTEGER NOT NULL,
|
"bucket_tokens" INTEGER NOT NULL,
|
||||||
"bucket_last_update" INTEGER NOT NULL,
|
"bucket_last_update" INTEGER NOT NULL,
|
||||||
"type" TEXT NOT NULL,
|
"type" TEXT NOT NULL,
|
||||||
|
"services" TEXT NOT NULL,
|
||||||
PRIMARY KEY("id")
|
PRIMARY KEY("id")
|
||||||
);
|
);
|
||||||
CREATE TABLE IF NOT EXISTS "approval-keys" (
|
CREATE TABLE IF NOT EXISTS "approval-keys" (
|
||||||
|
|
19
fn/ht.php
19
fn/ht.php
|
@ -1,5 +1,24 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
function htSetupUserFs($id) {
|
||||||
|
// Setup SFTP directory
|
||||||
|
umask(0002);
|
||||||
|
if (mkdir(CONF['ht']['ht_path'] . '/' . $id, 0775) !== true)
|
||||||
|
output(500, 'Can\'t create user directory.');
|
||||||
|
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['chgrp_path'] . ' ' . CONF['ht']['sftpgo_group'] . ' ' . CONF['ht']['ht_path'] . '/' . $id . ' --no-dereference', result_code: $code);
|
||||||
|
if ($code !== 0)
|
||||||
|
output(500, 'Can\'t change user directory group.');
|
||||||
|
|
||||||
|
// Setup Tor config directory
|
||||||
|
if (mkdir(CONF['ht']['tor_config_path'] . '/' . $id, 0755) !== true)
|
||||||
|
output(500, 'Can\'t create Tor config directory.');
|
||||||
|
|
||||||
|
// Setup Tor keys directory
|
||||||
|
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['mkdir_path'] . ' --mode=0700 ' . CONF['ht']['tor_keys_path'] . '/' . $id, result_code: $code);
|
||||||
|
if ($code !== 0)
|
||||||
|
output(500, 'Can\'t create Tor keys directory.');
|
||||||
|
}
|
||||||
|
|
||||||
function checkDomainFormat($domain) {
|
function checkDomainFormat($domain) {
|
||||||
// If the domain must end without a dot
|
// If the domain must end without a dot
|
||||||
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN) OR !preg_match('/^([a-z0-9_-]{1,63}\.){1,126}[a-z0-9]{1,63}$/D', $domain))
|
if (!filter_var($domain, FILTER_VALIDATE_DOMAIN) OR !preg_match('/^([a-z0-9_-]{1,63}\.){1,126}[a-z0-9]{1,63}$/D', $domain))
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
|
||||||
"Language: fr\n"
|
"Language: fr\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
|
||||||
#: pages.php:9
|
#: pages.php:9
|
||||||
msgid "Authentication"
|
msgid "Authentication"
|
||||||
|
@ -272,11 +272,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:134
|
#: 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."
|
||||||
|
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:147
|
||||||
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:136
|
#: router.php:149
|
||||||
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."
|
||||||
|
|
||||||
|
@ -284,12 +288,12 @@ msgstr "Ce compte n'existe plus. Déconnectez-vous pour terminer cette session f
|
||||||
msgid "Anonymous"
|
msgid "Anonymous"
|
||||||
msgstr "Anonyme"
|
msgstr "Anonyme"
|
||||||
|
|
||||||
#: view.php:41
|
#: view.php:44
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "This form won't be accepted because you need to %slog in%s first."
|
msgid "This form won't be accepted because you need to %slog in%s first."
|
||||||
msgstr "Ce forumulaire ne sera pas accepté car il faut %sse connecter%s d'abord."
|
msgstr "Ce forumulaire ne sera pas accepté car il faut %sse connecter%s d'abord."
|
||||||
|
|
||||||
#: view.php:48
|
#: view.php:51
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%sSource code%s available under %s."
|
msgid "%sSource code%s available under %s."
|
||||||
msgstr "%sCode source%s disponible sous %s."
|
msgstr "%sCode source%s disponible sous %s."
|
||||||
|
@ -314,7 +318,7 @@ msgstr "<strong>Erreur de l'utilisataire</strong> : "
|
||||||
msgid "<strong>Server error</strong>: "
|
msgid "<strong>Server error</strong>: "
|
||||||
msgstr "<strong>Erreur du serveur</strong> : "
|
msgstr "<strong>Erreur du serveur</strong> : "
|
||||||
|
|
||||||
#: fn/common.php:133
|
#: fn/common.php:129
|
||||||
msgid "Wrong proof."
|
msgid "Wrong proof."
|
||||||
msgstr "Preuve incorrecte."
|
msgstr "Preuve incorrecte."
|
||||||
|
|
||||||
|
@ -322,7 +326,7 @@ msgstr "Preuve incorrecte."
|
||||||
msgid "IP address malformed."
|
msgid "IP address malformed."
|
||||||
msgstr "Adresse IP malformée."
|
msgstr "Adresse IP malformée."
|
||||||
|
|
||||||
#: fn/dns.php:67 fn/ht.php:6
|
#: fn/dns.php:67 fn/ht.php:25
|
||||||
msgid "Domain malformed."
|
msgid "Domain malformed."
|
||||||
msgstr "Domaine malformé."
|
msgstr "Domaine malformé."
|
||||||
|
|
||||||
|
@ -372,7 +376,12 @@ msgstr "Cet identifiant est déjà pris."
|
||||||
msgid "Account deletion must be confirmed."
|
msgid "Account deletion must be confirmed."
|
||||||
msgstr "La suppression du compte doit être confirmée."
|
msgstr "La suppression du compte doit être confirmée."
|
||||||
|
|
||||||
#: pg-act/auth/unregister.php:29
|
#: pg-act/auth/unregister.php:10
|
||||||
|
#, php-format
|
||||||
|
msgid "Your account can't be deleted because the %s service is currently unavailable."
|
||||||
|
msgstr "Votre compte ne peut pas être supprimé car le service %s est actuellement indisponible."
|
||||||
|
|
||||||
|
#: pg-act/auth/unregister.php:39
|
||||||
msgid "Account deleted."
|
msgid "Account deleted."
|
||||||
msgstr "Compte supprimé."
|
msgstr "Compte supprimé."
|
||||||
|
|
||||||
|
@ -566,7 +575,7 @@ msgid "Approved"
|
||||||
msgstr "Approuvé"
|
msgstr "Approuvé"
|
||||||
|
|
||||||
#: pg-view/auth/index.php:27
|
#: pg-view/auth/index.php:27
|
||||||
msgid "It was originally a testing account, but has been approved by an administrator, and is suited for stable usecases:"
|
msgid "It was originally a testing account, but has been approved by an administrator, and is suitable for stable use cases:"
|
||||||
msgstr "C'est originellement un compte de test, mais qui a été approuvé par ane administrataire, et qui permet une utilisation stable :"
|
msgstr "C'est originellement un compte de test, mais qui a été approuvé par ane administrataire, et qui permet une utilisation stable :"
|
||||||
|
|
||||||
#: pg-view/auth/index.php:30
|
#: pg-view/auth/index.php:30
|
||||||
|
|
|
@ -271,11 +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:134
|
#: 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."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: router.php:147
|
||||||
msgid "You need to be logged in to do this."
|
msgid "You need to be logged in to do this."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: router.php:136
|
#: router.php:149
|
||||||
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 ""
|
||||||
|
|
||||||
|
@ -283,12 +287,12 @@ msgstr ""
|
||||||
msgid "Anonymous"
|
msgid "Anonymous"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: view.php:41
|
#: view.php:44
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "This form won't be accepted because you need to %slog in%s first."
|
msgid "This form won't be accepted because you need to %slog in%s first."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: view.php:48
|
#: view.php:51
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%sSource code%s available under %s."
|
msgid "%sSource code%s available under %s."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -313,7 +317,7 @@ msgstr ""
|
||||||
msgid "<strong>Server error</strong>: "
|
msgid "<strong>Server error</strong>: "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: fn/common.php:133
|
#: fn/common.php:129
|
||||||
msgid "Wrong proof."
|
msgid "Wrong proof."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -321,7 +325,7 @@ msgstr ""
|
||||||
msgid "IP address malformed."
|
msgid "IP address malformed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: fn/dns.php:67 fn/ht.php:6
|
#: fn/dns.php:67 fn/ht.php:25
|
||||||
msgid "Domain malformed."
|
msgid "Domain malformed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -371,7 +375,12 @@ msgstr ""
|
||||||
msgid "Account deletion must be confirmed."
|
msgid "Account deletion must be confirmed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pg-act/auth/unregister.php:29
|
#: pg-act/auth/unregister.php:10
|
||||||
|
#, php-format
|
||||||
|
msgid "Your account can't be deleted because the %s service is currently unavailable."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: pg-act/auth/unregister.php:39
|
||||||
msgid "Account deleted."
|
msgid "Account deleted."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -565,7 +574,7 @@ msgid "Approved"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pg-view/auth/index.php:27
|
#: pg-view/auth/index.php:27
|
||||||
msgid "It was originally a testing account, but has been approved by an administrator, and is suited for stable usecases:"
|
msgid "It was originally a testing account, but has been approved by an administrator, and is suitable for stable use cases:"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: pg-view/auth/index.php:30
|
#: pg-view/auth/index.php:30
|
||||||
|
|
|
@ -21,25 +21,9 @@ insert('users', [
|
||||||
'bucket_tokens' => 0,
|
'bucket_tokens' => 0,
|
||||||
'bucket_last_update' => 0,
|
'bucket_last_update' => 0,
|
||||||
'type' => 'testing',
|
'type' => 'testing',
|
||||||
|
'services' => '',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Setup SFTP directory
|
|
||||||
umask(0002);
|
|
||||||
if (mkdir(CONF['ht']['ht_path'] . '/' . $id, 0775) !== true)
|
|
||||||
output(500, 'Can\'t create user directory.');
|
|
||||||
exec(CONF['ht']['sudo_path'] . ' ' . CONF['ht']['chgrp_path'] . ' ' . CONF['ht']['sftpgo_group'] . ' ' . CONF['ht']['ht_path'] . '/' . $id . ' --no-dereference', result_code: $code);
|
|
||||||
if ($code !== 0)
|
|
||||||
output(500, 'Can\'t change user directory group.');
|
|
||||||
|
|
||||||
// Setup Tor config directory
|
|
||||||
if (mkdir(CONF['ht']['tor_config_path'] . '/' . $id, 0755) !== true)
|
|
||||||
output(500, 'Can\'t create Tor config directory.');
|
|
||||||
|
|
||||||
// Setup Tor keys directory
|
|
||||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['tor_user'] . ' ' . CONF['ht']['mkdir_path'] . ' --mode=0700 ' . CONF['ht']['tor_keys_path'] . '/' . $id, result_code: $code);
|
|
||||||
if ($code !== 0)
|
|
||||||
output(500, 'Can\'t create Tor keys directory.');
|
|
||||||
|
|
||||||
stopSession();
|
stopSession();
|
||||||
startSession();
|
startSession();
|
||||||
|
|
||||||
|
|
|
@ -3,24 +3,34 @@
|
||||||
if (!isset($_POST['delete']))
|
if (!isset($_POST['delete']))
|
||||||
output(403, _('Account deletion must be confirmed.'));
|
output(403, _('Account deletion must be confirmed.'));
|
||||||
|
|
||||||
foreach (query('select', 'registry', ['username' => $_SESSION['id']], 'domain') as $domain)
|
$user_services = explode(',', query('select', 'users', ['username' => $_SESSION['id']], 'services')[0]);
|
||||||
regDeleteDomain($domain);
|
|
||||||
|
|
||||||
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
|
foreach (SERVICES_USER as $service)
|
||||||
nsDeleteZone($zone);
|
if (in_array($service, $user_services, true) AND CONF['common']['services'][$service] !== 'enabled')
|
||||||
|
output(503, sprintf(_('Your account can\'t be deleted because the %s service is currently unavailable.'), '<em>' . PAGES[$service]['index']['title'] . '</em>'));
|
||||||
|
|
||||||
foreach (query('select', 'sites', ['username' => $_SESSION['id']]) as $site)
|
if (in_array('reg', $user_services, true))
|
||||||
htDeleteSite($site['address'], $site['type']);
|
foreach (query('select', 'registry', ['username' => $_SESSION['id']], 'domain') as $domain)
|
||||||
|
regDeleteDomain($domain);
|
||||||
|
|
||||||
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 (in_array('ns', $user_services, true))
|
||||||
if ($code !== 0)
|
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
|
||||||
output(500, 'Can\'t remove Tor keys directory.');
|
nsDeleteZone($zone);
|
||||||
|
|
||||||
removeDirectory(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id']);
|
if (in_array('ht', $user_services, true)) {
|
||||||
|
foreach (query('select', 'sites', ['username' => $_SESSION['id']]) as $site)
|
||||||
|
htDeleteSite($site['address'], $site['type']);
|
||||||
|
|
||||||
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['sftpgo_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'], result_code: $code);
|
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)
|
if ($code !== 0)
|
||||||
output(500, 'Can\'t remove user\'s directory.');
|
output(500, 'Can\'t remove Tor keys directory.');
|
||||||
|
|
||||||
|
removeDirectory(CONF['ht']['tor_config_path'] . '/' . $_SESSION['id']);
|
||||||
|
|
||||||
|
exec(CONF['ht']['sudo_path'] . ' -u ' . CONF['ht']['sftpgo_user'] . ' ' . CONF['ht']['rm_path'] . ' --recursive ' . CONF['ht']['ht_path'] . '/' . $_SESSION['id'], result_code: $code);
|
||||||
|
if ($code !== 0)
|
||||||
|
output(500, 'Can\'t remove user\'s directory.');
|
||||||
|
}
|
||||||
|
|
||||||
query('delete', 'users', ['id' => $_SESSION['id']]);
|
query('delete', 'users', ['id' => $_SESSION['id']]);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
</dd>
|
</dd>
|
||||||
<dt><span aria-hidden="true">👤 </span><em><?= _('Approved') ?></em></dt>
|
<dt><span aria-hidden="true">👤 </span><em><?= _('Approved') ?></em></dt>
|
||||||
<dd>
|
<dd>
|
||||||
<?= _('It was originally a testing account, but has been approved by an administrator, and is suited for stable usecases:') ?>
|
<?= _('It was originally a testing account, but has been approved by an administrator, and is suitable for stable use cases:') ?>
|
||||||
<ul>
|
<ul>
|
||||||
<li><?= sprintf(_('%s of SFTP quota'), ((CONF['ht']['user_quota_approved'] >> 30) >= 1) ? CONF['ht']['user_quota_approved'] >> 30 . ' ' . _('<abbr title="gibibyte">GiB</abbr>') : CONF['ht']['user_quota_approved'] >> 20 . ' ' . _('<abbr title="mebibyte">MiB</abbr>')) ?></li>
|
<li><?= sprintf(_('%s of SFTP quota'), ((CONF['ht']['user_quota_approved'] >> 30) >= 1) ? CONF['ht']['user_quota_approved'] >> 30 . ' ' . _('<abbr title="gibibyte">GiB</abbr>') : CONF['ht']['user_quota_approved'] >> 20 . ' ' . _('<abbr title="mebibyte">MiB</abbr>')) ?></li>
|
||||||
<li><?= _('Stable Let\'s Encrypt certificates') ?></li>
|
<li><?= _('Stable Let\'s Encrypt certificates') ?></li>
|
||||||
|
|
|
@ -1,26 +1,17 @@
|
||||||
<nav>
|
<nav>
|
||||||
<dl>
|
<dl>
|
||||||
<dt><a class="auth" href="auth/"><?= PAGES['auth']['index']['title'] ?></a></dt>
|
<?php
|
||||||
<dd>
|
|
||||||
<?= PAGES['auth']['index']['description'] ?>
|
foreach (array_merge(['auth' => 'enabled'], CONF['common']['services']) as $service => $status) {
|
||||||
</dd>
|
if ($status !== 'enabled' AND $status !== 'error')
|
||||||
<?php if (CONF['reg']['enabled'] === true) { ?>
|
continue;
|
||||||
<dt><a class="reg" href="reg/"><?= PAGES['reg']['index']['title'] ?></code></a></dt>
|
?>
|
||||||
<dd>
|
<?= ($status === 'error') ? '<s>' : '' ?>
|
||||||
<?= PAGES['reg']['index']['description'] ?>
|
<dt><a class="<?= $service ?>" href="<?= $service ?>/"><?= PAGES[$service]['index']['title'] ?></a></dt>
|
||||||
</dd>
|
<dd>
|
||||||
<?php } ?>
|
<?= PAGES[$service]['index']['description'] ?>
|
||||||
<?php if (CONF['ns']['enabled'] === true) { ?>
|
</dd>
|
||||||
<dt><a class="ns" href="ns/"><?= PAGES['ns']['index']['title'] ?></a></dt>
|
<?= ($status === 'error') ? '</s>' : '' ?>
|
||||||
<dd>
|
<?php } ?>
|
||||||
<?= PAGES['ns']['index']['description'] ?>
|
|
||||||
</dd>
|
|
||||||
<?php } ?>
|
|
||||||
<?php if (CONF['ht']['enabled'] === true) { ?>
|
|
||||||
<dt><a class="ht" href="ht/"><?= PAGES['ht']['index']['title'] ?></a></dt>
|
|
||||||
<dd>
|
|
||||||
<?= PAGES['ht']['index']['description'] ?>
|
|
||||||
</dd>
|
|
||||||
<?php } ?>
|
|
||||||
</dl>
|
</dl>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
36
router.php
36
router.php
|
@ -15,13 +15,15 @@ setlocale(LC_MESSAGES, 'C.UTF-8');
|
||||||
bindtextdomain('messages', 'locales/' . LOCALE);
|
bindtextdomain('messages', 'locales/' . LOCALE);
|
||||||
header('Content-Language: ' . LOCALE);
|
header('Content-Language: ' . LOCALE);
|
||||||
|
|
||||||
|
const SERVICES_USER = ['reg', 'ns', 'ht'];
|
||||||
|
|
||||||
const LF = "\n";
|
const LF = "\n";
|
||||||
|
|
||||||
const PLACEHOLDER_DOMAIN = 'example'; // From RFC2606: Reserved Top Level DNS Names > 2. TLDs for Testing, & Documentation Examples
|
const PLACEHOLDER_DOMAIN = 'example'; // From RFC2606: Reserved Top Level DNS Names > 2. TLDs for Testing, & Documentation Examples
|
||||||
const PLACEHOLDER_IPV6 = '2001:db8::3'; // From RFC3849: IPv6 Address Prefix Reserved for Documentation
|
const PLACEHOLDER_IPV6 = '2001:db8::3'; // From RFC3849: IPv6 Address Prefix Reserved for Documentation
|
||||||
const PLACEHOLDER_IPV4 = '203.0.113.42'; // From RFC5737: IPv4 Address Blocks Reserved for Documentation
|
const PLACEHOLDER_IPV4 = '203.0.113.42'; // From RFC5737: IPv4 Address Blocks Reserved for Documentation
|
||||||
|
|
||||||
foreach (array_diff(scandir(CONF['common']['root_path'] . '/fn'), array('..', '.')) as $file)
|
foreach (array_diff(scandir(CONF['common']['root_path'] . '/fn'), ['..', '.']) as $file)
|
||||||
require CONF['common']['root_path'] . '/fn/' . $file;
|
require CONF['common']['root_path'] . '/fn/' . $file;
|
||||||
|
|
||||||
require 'pages.php';
|
require 'pages.php';
|
||||||
|
@ -38,7 +40,6 @@ define('PAGE_URL', $pageAddress);
|
||||||
define('PAGE_ADDRESS', $pageAddress . ((substr($pageAddress, -1) === '/' OR $pageAddress === '') ? 'index' : ''));
|
define('PAGE_ADDRESS', $pageAddress . ((substr($pageAddress, -1) === '/' OR $pageAddress === '') ? 'index' : ''));
|
||||||
define('PAGE_LINEAGE', explode('/', PAGE_ADDRESS));
|
define('PAGE_LINEAGE', explode('/', PAGE_ADDRESS));
|
||||||
define('SERVICE', dirname(PAGE_ADDRESS));
|
define('SERVICE', dirname(PAGE_ADDRESS));
|
||||||
define('PAGE', basename(PAGE_ADDRESS, '.php'));
|
|
||||||
|
|
||||||
function getPageInformations($pages, $pageElements) {
|
function getPageInformations($pages, $pageElements) {
|
||||||
if (!isset($pages['index']) OR $pageElements[0] === 'index')
|
if (!isset($pages['index']) OR $pageElements[0] === 'index')
|
||||||
|
@ -87,6 +88,7 @@ if (isset($_COOKIE[SESSION_COOKIE_NAME]))
|
||||||
startSession(); // Resume session
|
startSession(); // Resume session
|
||||||
|
|
||||||
if (isset($_SESSION['id'])) {
|
if (isset($_SESSION['id'])) {
|
||||||
|
// Decrypt display username
|
||||||
if (!isset($_COOKIE['display-username-decryption-key']))
|
if (!isset($_COOKIE['display-username-decryption-key']))
|
||||||
output(403, 'The display username decryption key has not been sent.');
|
output(403, 'The display username decryption key has not been sent.');
|
||||||
$decryption_result = htmlspecialchars(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
|
$decryption_result = htmlspecialchars(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||||
|
@ -98,17 +100,18 @@ if (isset($_SESSION['id'])) {
|
||||||
if ($decryption_result === false)
|
if ($decryption_result === false)
|
||||||
output(403, 'Unable to decrypt display username.');
|
output(403, 'Unable to decrypt display username.');
|
||||||
define('DISPLAY_USERNAME', $decryption_result);
|
define('DISPLAY_USERNAME', $decryption_result);
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array(SERVICE, ['reg', 'ns', 'ht']) AND CONF[SERVICE]['enabled'] !== true)
|
// Enable not already enabled services for this user
|
||||||
output(403, 'Ce service est désactivé.');
|
$user_services = array_filter(explode(',', query('select', 'users', ['id' => $_SESSION['id']], 'services')[0]));
|
||||||
|
if (in_array(SERVICE, SERVICES_USER, true) AND !in_array(SERVICE, $user_services, true) AND CONF['common']['services'][SERVICE] === 'enabled') {
|
||||||
|
$user_services[] = SERVICE;
|
||||||
|
|
||||||
// Protect against cross-site request forgery if a POST request is received
|
DB->prepare('UPDATE users SET services = :services WHERE id = :id')
|
||||||
if ($_POST !== []) {
|
->execute([':services' => implode(',', $user_services), ':id' => $_SESSION['id']]);
|
||||||
if (isset($_SERVER['HTTP_SEC_FETCH_SITE']) !== true)
|
|
||||||
output(403, 'The <code>Sec-Fetch-Site</code> HTTP header is required when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).');
|
if (SERVICE === 'ht')
|
||||||
if ($_SERVER['HTTP_SEC_FETCH_SITE'] !== 'same-origin')
|
htSetupUserFs($_SESSION['id']);
|
||||||
output(403, 'The <code>Sec-Fetch-Site</code> HTTP header must be <code>same-origin</code> when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).');
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($_SERVER['SERVER_NAME']) !== true)
|
if (isset($_SERVER['SERVER_NAME']) !== true)
|
||||||
|
@ -125,18 +128,27 @@ function displayFinalMessage($data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_POST !== []) {
|
if ($_POST !== []) {
|
||||||
|
if (in_array(SERVICE, SERVICES_USER, true) AND CONF['common']['services'][SERVICE] !== 'enabled')
|
||||||
|
output(503, _('This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it.'));
|
||||||
|
|
||||||
|
// Protect against cross-site request forgery if a POST request is received
|
||||||
|
if (isset($_SERVER['HTTP_SEC_FETCH_SITE']) !== true)
|
||||||
|
output(403, 'The <code>Sec-Fetch-Site</code> HTTP header is required when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).');
|
||||||
|
if ($_SERVER['HTTP_SEC_FETCH_SITE'] !== 'same-origin')
|
||||||
|
output(403, 'The <code>Sec-Fetch-Site</code> HTTP header must be <code>same-origin</code> when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).');
|
||||||
|
|
||||||
if (PAGE_METADATA['require-login'] ?? true !== false) {
|
if (PAGE_METADATA['require-login'] ?? true !== false) {
|
||||||
if (isset($_SESSION['id']) !== true)
|
if (isset($_SESSION['id']) !== true)
|
||||||
output(403, _('You need to be logged in to do this.'));
|
output(403, _('You need to be logged in to do this.'));
|
||||||
if (isset(query('select', 'users', ['id' => $_SESSION['id']], 'id')[0]) !== true)
|
if (isset(query('select', 'users', ['id' => $_SESSION['id']], 'id')[0]) !== true)
|
||||||
output(403, _('This account doesn\'t exist anymore. Log out to end this ghost session.'));
|
output(403, _('This account doesn\'t exist anymore. Log out to end this ghost session.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists('pg-act/' . PAGE_ADDRESS . '.php'))
|
if (file_exists('pg-act/' . PAGE_ADDRESS . '.php'))
|
||||||
require 'pg-act/' . PAGE_ADDRESS . '.php';
|
require 'pg-act/' . PAGE_ADDRESS . '.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayPage($data) {
|
function displayPage($data) {
|
||||||
|
|
||||||
require 'view.php';
|
require 'view.php';
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
3
view.php
3
view.php
|
@ -35,6 +35,9 @@
|
||||||
<main>
|
<main>
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
if (in_array(SERVICE, SERVICES_USER, true) AND CONF['common']['services'][SERVICE] === 'error')
|
||||||
|
echo '<p><strong>' . _('This service is currently under maintenance. No action can be taken on it until an administrator finishes repairing it.') . '</strong></p>';
|
||||||
|
|
||||||
require 'pg-view/' . PAGE_ADDRESS . '.php';
|
require 'pg-view/' . PAGE_ADDRESS . '.php';
|
||||||
|
|
||||||
if ($_POST === [] AND PAGE_METADATA['require-login'] ?? true !== false AND !isset($_SESSION['id']) AND PAGE_TERMINAL)
|
if ($_POST === [] AND PAGE_METADATA['require-login'] ?? true !== false AND !isset($_SESSION['id']) AND PAGE_TERMINAL)
|
||||||
|
|
Loading…
Reference in New Issue