Advanced services status management
This commit is contained in:
parent
a95f6203eb
commit
abb9aabf5b
13 changed files with 143 additions and 109 deletions
|
@ -32,6 +32,15 @@ String defining the displayed identity of the service.
|
|||
|
||||
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]`
|
||||
|
||||
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]`
|
||||
|
||||
### `enabled`
|
||||
|
||||
Defines whether the web interface for this service is accessible.
|
||||
|
||||
### `suffixes[]`
|
||||
|
||||
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]`
|
||||
|
||||
### `enabled`
|
||||
|
||||
Defines whether the web interface for this service is accessible.
|
||||
|
||||
### `knot_zones_path`
|
||||
|
||||
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]`
|
||||
|
||||
### `enabled`
|
||||
|
||||
Defines whether the web interface for this service is accessible. (Users can still use SFTP.)
|
||||
|
||||
### `ht_path`
|
||||
|
||||
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
|
||||
|
||||
Extract messages to be translated from the source files and into a Portable Object Template file:
|
||||
```
|
||||
xgettext --from-code=UTF-8 --no-wrap -d messages -p locales/ --from-code=UTF-8 *.php */*.php */*/*.php
|
||||
```shell
|
||||
xgettext --from-code=UTF-8 --no-wrap -d messages -p locales/ *.php */*.php */*/*.php
|
||||
mv locales/messages.po locales/messages.pot
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
|
@ -17,7 +17,7 @@ msgmerge --no-wrap locales/fr/C/LC_MESSAGES/messages.po locales/messages.pot -o
|
|||
|
||||
### To start a new translation
|
||||
|
||||
```
|
||||
```shell
|
||||
mkdir -p locales/fr/C/LC_MESSAGES/
|
||||
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
|
||||
* 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
|
||||
|
||||
To compile Portable Objects into Machine Objects:
|
||||
```
|
||||
```shell
|
||||
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 = ""
|
||||
service_name = "ServNest"
|
||||
service_emoji = "🪺"
|
||||
services[reg] = "enabled"
|
||||
services[ns] = "enabled"
|
||||
services[ht] = "enabled"
|
||||
|
||||
[dns]
|
||||
knotc_path = "/usr/sbin/knotc"
|
||||
kdig_path = "/usr/bin/kdig"
|
||||
|
||||
[reg]
|
||||
enabled = true
|
||||
suffixes[servnest.test.] = "approved"
|
||||
suffixes[test.servnest.test.] = "all"
|
||||
suffixes[old.sernnest.test.] = "none"
|
||||
|
@ -21,7 +23,6 @@ ttl = 86400
|
|||
address = "[::1]:42053"
|
||||
|
||||
[ns]
|
||||
enabled = true
|
||||
knot_zones_path = "/srv/servnest/ns"
|
||||
servers[] = "ns1.servnest.test."
|
||||
servers[] = "ns2.servnest.test."
|
||||
|
@ -29,8 +30,6 @@ kzonecheck_path = "/usr/bin/kzonecheck"
|
|||
public_soa_email = "hostmaster.invalid."
|
||||
|
||||
[ht]
|
||||
enabled = true
|
||||
|
||||
ht_path = "/srv/servnest/ht"
|
||||
|
||||
subpath_domain = "ht.servnest.test"
|
||||
|
|
|
@ -4,11 +4,11 @@ CREATE TABLE IF NOT EXISTS "params" (
|
|||
"value" TEXT NOT NULL,
|
||||
PRIMARY KEY("name")
|
||||
);
|
||||
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("secret_key", "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('instance_bucket_tokens', '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_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
|
||||
CREATE TABLE IF NOT EXISTS "users" (
|
||||
"id" 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_last_update" INTEGER NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"services" TEXT NOT NULL,
|
||||
PRIMARY KEY("id")
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS "approval-keys" (
|
||||
|
|
19
fn/ht.php
19
fn/ht.php
|
@ -1,5 +1,24 @@
|
|||
<?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) {
|
||||
// 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))
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
msgid ""
|
||||
msgstr ""
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Language: fr\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
||||
#: pages.php:9
|
||||
msgid "Authentication"
|
||||
|
@ -272,11 +272,15 @@ msgstr "Supprimer un accès"
|
|||
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"
|
||||
|
||||
#: 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."
|
||||
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."
|
||||
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"
|
||||
msgstr "Anonyme"
|
||||
|
||||
#: view.php:41
|
||||
#: view.php:44
|
||||
#, php-format
|
||||
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."
|
||||
|
||||
#: view.php:48
|
||||
#: view.php:51
|
||||
#, php-format
|
||||
msgid "%sSource code%s available under %s."
|
||||
msgstr "%sCode source%s disponible sous %s."
|
||||
|
@ -314,7 +318,7 @@ msgstr "<strong>Erreur de l'utilisataire</strong> : "
|
|||
msgid "<strong>Server error</strong>: "
|
||||
msgstr "<strong>Erreur du serveur</strong> : "
|
||||
|
||||
#: fn/common.php:133
|
||||
#: fn/common.php:129
|
||||
msgid "Wrong proof."
|
||||
msgstr "Preuve incorrecte."
|
||||
|
||||
|
@ -322,7 +326,7 @@ msgstr "Preuve incorrecte."
|
|||
msgid "IP address malformed."
|
||||
msgstr "Adresse IP malformée."
|
||||
|
||||
#: fn/dns.php:67 fn/ht.php:6
|
||||
#: fn/dns.php:67 fn/ht.php:25
|
||||
msgid "Domain malformed."
|
||||
msgstr "Domaine malformé."
|
||||
|
||||
|
@ -372,7 +376,12 @@ msgstr "Cet identifiant est déjà pris."
|
|||
msgid "Account deletion must be confirmed."
|
||||
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."
|
||||
msgstr "Compte supprimé."
|
||||
|
||||
|
@ -566,7 +575,7 @@ msgid "Approved"
|
|||
msgstr "Approuvé"
|
||||
|
||||
#: 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 :"
|
||||
|
||||
#: pg-view/auth/index.php:30
|
||||
|
|
|
@ -271,11 +271,15 @@ msgstr ""
|
|||
msgid "Delete an existing HTTP access from a subdirectory of the SFTP space"
|
||||
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."
|
||||
msgstr ""
|
||||
|
||||
#: router.php:136
|
||||
#: router.php:149
|
||||
msgid "This account doesn't exist anymore. Log out to end this ghost session."
|
||||
msgstr ""
|
||||
|
||||
|
@ -283,12 +287,12 @@ msgstr ""
|
|||
msgid "Anonymous"
|
||||
msgstr ""
|
||||
|
||||
#: view.php:41
|
||||
#: view.php:44
|
||||
#, php-format
|
||||
msgid "This form won't be accepted because you need to %slog in%s first."
|
||||
msgstr ""
|
||||
|
||||
#: view.php:48
|
||||
#: view.php:51
|
||||
#, php-format
|
||||
msgid "%sSource code%s available under %s."
|
||||
msgstr ""
|
||||
|
@ -313,7 +317,7 @@ msgstr ""
|
|||
msgid "<strong>Server error</strong>: "
|
||||
msgstr ""
|
||||
|
||||
#: fn/common.php:133
|
||||
#: fn/common.php:129
|
||||
msgid "Wrong proof."
|
||||
msgstr ""
|
||||
|
||||
|
@ -321,7 +325,7 @@ msgstr ""
|
|||
msgid "IP address malformed."
|
||||
msgstr ""
|
||||
|
||||
#: fn/dns.php:67 fn/ht.php:6
|
||||
#: fn/dns.php:67 fn/ht.php:25
|
||||
msgid "Domain malformed."
|
||||
msgstr ""
|
||||
|
||||
|
@ -371,7 +375,12 @@ msgstr ""
|
|||
msgid "Account deletion must be confirmed."
|
||||
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."
|
||||
msgstr ""
|
||||
|
||||
|
@ -565,7 +574,7 @@ msgid "Approved"
|
|||
msgstr ""
|
||||
|
||||
#: 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 ""
|
||||
|
||||
#: pg-view/auth/index.php:30
|
||||
|
|
|
@ -21,25 +21,9 @@ insert('users', [
|
|||
'bucket_tokens' => 0,
|
||||
'bucket_last_update' => 0,
|
||||
'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();
|
||||
startSession();
|
||||
|
||||
|
|
|
@ -3,24 +3,34 @@
|
|||
if (!isset($_POST['delete']))
|
||||
output(403, _('Account deletion must be confirmed.'));
|
||||
|
||||
foreach (query('select', 'registry', ['username' => $_SESSION['id']], 'domain') as $domain)
|
||||
regDeleteDomain($domain);
|
||||
$user_services = explode(',', query('select', 'users', ['username' => $_SESSION['id']], 'services')[0]);
|
||||
|
||||
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
|
||||
nsDeleteZone($zone);
|
||||
foreach (SERVICES_USER as $service)
|
||||
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)
|
||||
htDeleteSite($site['address'], $site['type']);
|
||||
if (in_array('reg', $user_services, true))
|
||||
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 ($code !== 0)
|
||||
output(500, 'Can\'t remove Tor keys directory.');
|
||||
if (in_array('ns', $user_services, true))
|
||||
foreach (query('select', 'zones', ['username' => $_SESSION['id']], 'zone') as $zone)
|
||||
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);
|
||||
if ($code !== 0)
|
||||
output(500, 'Can\'t remove user\'s directory.');
|
||||
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)
|
||||
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']]);
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</dd>
|
||||
<dt><span aria-hidden="true">👤 </span><em><?= _('Approved') ?></em></dt>
|
||||
<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>
|
||||
<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>
|
||||
|
|
|
@ -1,26 +1,17 @@
|
|||
<nav>
|
||||
<dl>
|
||||
<dt><a class="auth" href="auth/"><?= PAGES['auth']['index']['title'] ?></a></dt>
|
||||
<dd>
|
||||
<?= PAGES['auth']['index']['description'] ?>
|
||||
</dd>
|
||||
<?php if (CONF['reg']['enabled'] === true) { ?>
|
||||
<dt><a class="reg" href="reg/"><?= PAGES['reg']['index']['title'] ?></code></a></dt>
|
||||
<dd>
|
||||
<?= PAGES['reg']['index']['description'] ?>
|
||||
</dd>
|
||||
<?php } ?>
|
||||
<?php if (CONF['ns']['enabled'] === true) { ?>
|
||||
<dt><a class="ns" href="ns/"><?= PAGES['ns']['index']['title'] ?></a></dt>
|
||||
<dd>
|
||||
<?= 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 } ?>
|
||||
<?php
|
||||
|
||||
foreach (array_merge(['auth' => 'enabled'], CONF['common']['services']) as $service => $status) {
|
||||
if ($status !== 'enabled' AND $status !== 'error')
|
||||
continue;
|
||||
?>
|
||||
<?= ($status === 'error') ? '<s>' : '' ?>
|
||||
<dt><a class="<?= $service ?>" href="<?= $service ?>/"><?= PAGES[$service]['index']['title'] ?></a></dt>
|
||||
<dd>
|
||||
<?= PAGES[$service]['index']['description'] ?>
|
||||
</dd>
|
||||
<?= ($status === 'error') ? '</s>' : '' ?>
|
||||
<?php } ?>
|
||||
</dl>
|
||||
</nav>
|
||||
|
|
36
router.php
36
router.php
|
@ -15,13 +15,15 @@ setlocale(LC_MESSAGES, 'C.UTF-8');
|
|||
bindtextdomain('messages', 'locales/' . LOCALE);
|
||||
header('Content-Language: ' . LOCALE);
|
||||
|
||||
const SERVICES_USER = ['reg', 'ns', 'ht'];
|
||||
|
||||
const LF = "\n";
|
||||
|
||||
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_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 'pages.php';
|
||||
|
@ -38,7 +40,6 @@ define('PAGE_URL', $pageAddress);
|
|||
define('PAGE_ADDRESS', $pageAddress . ((substr($pageAddress, -1) === '/' OR $pageAddress === '') ? 'index' : ''));
|
||||
define('PAGE_LINEAGE', explode('/', PAGE_ADDRESS));
|
||||
define('SERVICE', dirname(PAGE_ADDRESS));
|
||||
define('PAGE', basename(PAGE_ADDRESS, '.php'));
|
||||
|
||||
function getPageInformations($pages, $pageElements) {
|
||||
if (!isset($pages['index']) OR $pageElements[0] === 'index')
|
||||
|
@ -87,6 +88,7 @@ if (isset($_COOKIE[SESSION_COOKIE_NAME]))
|
|||
startSession(); // Resume session
|
||||
|
||||
if (isset($_SESSION['id'])) {
|
||||
// Decrypt display username
|
||||
if (!isset($_COOKIE['display-username-decryption-key']))
|
||||
output(403, 'The display username decryption key has not been sent.');
|
||||
$decryption_result = htmlspecialchars(sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||
|
@ -98,17 +100,18 @@ if (isset($_SESSION['id'])) {
|
|||
if ($decryption_result === false)
|
||||
output(403, 'Unable to decrypt display username.');
|
||||
define('DISPLAY_USERNAME', $decryption_result);
|
||||
}
|
||||
|
||||
if (in_array(SERVICE, ['reg', 'ns', 'ht']) AND CONF[SERVICE]['enabled'] !== true)
|
||||
output(403, 'Ce service est désactivé.');
|
||||
// Enable not already enabled services for this user
|
||||
$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
|
||||
if ($_POST !== []) {
|
||||
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>).');
|
||||
DB->prepare('UPDATE users SET services = :services WHERE id = :id')
|
||||
->execute([':services' => implode(',', $user_services), ':id' => $_SESSION['id']]);
|
||||
|
||||
if (SERVICE === 'ht')
|
||||
htSetupUserFs($_SESSION['id']);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_SERVER['SERVER_NAME']) !== true)
|
||||
|
@ -125,18 +128,27 @@ function displayFinalMessage($data) {
|
|||
}
|
||||
|
||||
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 (isset($_SESSION['id']) !== true)
|
||||
output(403, _('You need to be logged in to do this.'));
|
||||
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.'));
|
||||
}
|
||||
|
||||
if (file_exists('pg-act/' . PAGE_ADDRESS . '.php'))
|
||||
require 'pg-act/' . PAGE_ADDRESS . '.php';
|
||||
}
|
||||
|
||||
function displayPage($data) {
|
||||
|
||||
require 'view.php';
|
||||
exit();
|
||||
}
|
||||
|
|
3
view.php
3
view.php
|
@ -35,6 +35,9 @@
|
|||
<main>
|
||||
<?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';
|
||||
|
||||
if ($_POST === [] AND PAGE_METADATA['require-login'] ?? true !== false AND !isset($_SESSION['id']) AND PAGE_TERMINAL)
|
||||
|
|
Loading…
Reference in a new issue