servnest/router.php

126 lines
5.1 KiB
PHP
Raw Normal View History

2023-07-17 19:15:18 +00:00
<?php declare(strict_types=1);
require 'init.php';
$pageAddress = substr($_SERVER['REQUEST_URI'], strlen(CONF['common']['prefix']) + 1);
if (strpos($pageAddress, '?') !== false) {
parse_str(substr($pageAddress, strpos($pageAddress, '?') + 1), $_GET);
$pageAddress = substr($pageAddress, 0, strpos($pageAddress, '?'));
}
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));
2023-10-29 13:12:28 +00:00
function getPageInformations(array $pages, array $pageElements): array { // Recursively retrieves page metadata from pages.php
2022-10-12 22:40:19 +00:00
if (!isset($pages['index']) OR $pageElements[0] === 'index')
2022-09-16 22:49:07 +00:00
return [
'titles_lineage' => [$pages[$pageElements[0]]['title'] ?? false],
'page_metadata' => $pages[$pageElements[0]] ?? NULL,
'terminal' => $pageElements[0] !== 'index'
2022-09-16 22:49:07 +00:00
];
$result = $pages['index']['title'];
2022-09-09 18:16:48 +00:00
if (!isset($pageElements[1]))
unset($pages['index']);
2022-09-09 18:16:48 +00:00
else
$pages = $pages[array_shift($pageElements)] ?? false;
2022-09-16 22:49:07 +00:00
$results = getPageInformations($pages, $pageElements);
$results['titles_lineage'][] = $result;
2022-09-09 18:16:48 +00:00
return $results;
2022-09-09 18:15:10 +00:00
}
2022-09-16 22:49:07 +00:00
$pageInformations = getPageInformations(PAGES, PAGE_LINEAGE);
define('TITLES_LINEAGE', array_reverse($pageInformations['titles_lineage']));
define('PAGE_METADATA', $pageInformations['page_metadata']);
define('PAGE_TERMINAL', $pageInformations['terminal']);
2022-09-09 18:15:10 +00:00
if (!TITLES_LINEAGE[array_key_last(TITLES_LINEAGE)]) {
http_response_code(404);
exit('Page not found.');
}
2023-03-27 22:18:37 +00:00
if (isset($_SERVER['SERVER_NAME']) !== true)
exit('Missing <code>$_SERVER[\'SERVER_NAME\']</code>');
if (in_array($_SERVER['SERVER_NAME'], CONF['common']['public_domains'], true) !== true)
exit('The current <code>$_SERVER[\'SERVER_NAME\']</code> is not allowed in configuration.');
define('SERVER_NAME', $_SERVER['SERVER_NAME']);
2023-01-29 20:09:00 +00:00
const SESSION_COOKIE_NAME = 'servnest-session-key';
2023-06-19 22:36:58 +00:00
function startSession(): void {
2022-09-09 19:53:31 +00:00
session_start([
2022-11-26 19:10:37 +00:00
'name' => SESSION_COOKIE_NAME,
2022-09-09 19:53:31 +00:00
'sid_length' => 64,
'sid_bits_per_character' => 6,
'cookie_secure' => true,
'cookie_httponly' => true,
'cookie_samesite' => 'Strict',
'cookie_path' => CONF['common']['prefix'] . '/',
'cookie_lifetime' => 432000, // = 60*60*24*5 = 5 days
'gc_maxlifetime' => 10800,
'use_strict_mode' => true,
'use_cookies' => true,
'use_only_cookies' => true,
]);
}
if (isset($_COOKIE[SESSION_COOKIE_NAME]))
startSession(); // Resume session
2022-09-09 19:53:31 +00:00
if (isset($_SESSION['id'])) {
if (!isset(query('select', 'users', ['id' => $_SESSION['id']], ['id'])[0]))
logout();
2023-03-09 00:35:30 +00:00
// Decrypt display username
if (!isset($_COOKIE['display-username-decryption-key']))
output(403, 'The display username decryption key has not been sent.');
$decryption_result = sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
$_SESSION['display-username-cyphertext'],
2023-02-07 21:25:16 +00:00
'',
$_SESSION['display-username-nonce'],
base64_decode($_COOKIE['display-username-decryption-key'])
);
if ($decryption_result === false)
output(403, 'Unable to decrypt display username.');
define('DISPLAY_USERNAME', htmlspecialchars($decryption_result));
2023-03-09 00:35:30 +00:00
// Enable not already enabled services for this user
$user_services = array_filter(explode(',', query('select', 'users', ['id' => $_SESSION['id']], ['services'])[0]));
foreach (SERVICES_USER as $service)
if (!in_array($service, $user_services, true) AND CONF['common']['services'][$service] === 'enabled') {
$user_services[] = $service;
2022-09-09 19:53:31 +00:00
DB->prepare('UPDATE users SET services = :services WHERE id = :id')
->execute([':services' => implode(',', $user_services), ':id' => $_SESSION['id']]);
2023-03-09 00:35:30 +00:00
if ($service === 'ht')
htSetupUserFs($_SESSION['id']);
}
2022-11-21 23:28:19 +00:00
}
2023-06-19 22:36:58 +00:00
function displayFinalMessage(?array $data): void {
if (isset($data['final_message'])) {
echo $data['final_message'];
unset($data['final_message']);
}
}
if ($_POST !== []) {
if (!in_array(CONF['common']['services']['auth'], ['enabled', 'no-registration'], true) OR (in_array(SERVICE, SERVICES_USER, true) AND CONF['common']['services'][SERVICE] !== 'enabled'))
2023-03-09 00:35:30 +00:00
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 (!in_array($_SERVER['HTTP_SEC_FETCH_SITE'], ['none', 'same-origin'], true))
output(403, 'The <code>Sec-Fetch-Site</code> HTTP header must be <code>same-origin</code> or <code>none</code> when submitting a POST request to prevent Cross-Site Request Forgery (<abbr>CSRF</abbr>).');
2023-03-09 00:35:30 +00:00
if (PAGE_METADATA['require-login'] ?? true AND !isset($_SESSION['id']))
output(403, _('You need to be logged in to do this.'));
2023-03-09 00:35:30 +00:00
if (file_exists(ROOT_PATH . '/pg-act/' . PAGE_ADDRESS . '.php'))
require ROOT_PATH . '/pg-act/' . PAGE_ADDRESS . '.php';
}
2022-09-09 19:53:31 +00:00
2023-06-19 22:36:58 +00:00
function displayPage(?array $data): never {
require ROOT_PATH . '/view.php';
2022-09-09 19:53:31 +00:00
exit();
}
displayPage($data ??= NULL);