1
0
Fork 0
Lightning-Tracker/src/bootstrap.php

164 lines
5.7 KiB
PHP

<?php
declare(strict_types = 1);
use Logging\Log;
use Routing\Request;
use Routing\Router;
use Routing\RouterException;
use Routing\UrlString;
use function Pages\Actions\message;
define('TRACKER_PUBLIC_VERSION', '0.1');
define('TRACKER_MIGRATION_VERSION', 10);
define('TRACKER_RESOURCE_VERSION', ''); // autogenerated
define('CONFIG_FILE', __DIR__.'/config.php');
define('CONFIG_BACKUP_FILE', __DIR__.'/config.old.php');
define('VERSION_FILE', __DIR__.'/version.php');
define('VERSION_TMP_FILE', __DIR__.'/version.tmp.php');
setlocale(LC_ALL, 'C');
date_default_timezone_set('UTC');
header_remove('x-powered-by');
// Bootstrap
spl_autoload_extensions('.php');
spl_autoload_register(static function($class){
// default autoload implementation is garbage because
// it converts paths to lowercase and breaks on linux
/** @noinspection PhpIncludeInspection */
require __DIR__.'/'.str_replace('\\', '/', $class).'.php';
});
require_once 'utils.php';
if (!file_exists(CONFIG_FILE)){
require_once 'install.php';
return;
}
/** @noinspection PhpIncludeInspection */
require_once CONFIG_FILE;
/** @noinspection PhpIncludeInspection */
require_once VERSION_FILE;
if (!defined('DEBUG')){
define('DEBUG', false);
}
// Base URL
$base_url_split = mb_strpos(BASE_URL, '://');
if ($base_url_split === false){
die('Base URL is invalid.');
}
$base_url_path = rtrim(parse_url(BASE_URL, PHP_URL_PATH) ?? '', '/');
$base_url_protocol = mb_substr(BASE_URL, 0, $base_url_split + 3);
$base_url_domain_path = mb_substr(BASE_URL, $base_url_split + 3);
define('BASE_PATH', $base_url_path);
define('BASE_PATH_ENC', (new UrlString($base_url_path))->encoded());
define('BASE_URL_ENC', $base_url_protocol.(new UrlString($base_url_domain_path))->encoded());
// Migration
if (TRACKER_MIGRATION_VERSION > MIGRATION_VERSION){
require_once 'update.php';
}
elseif (MIGRATION_TASK !== 0){
die('The update process did not finish cleanly. Please check the server logs and finish the update process, or revert back to the previous version.');
}
// Protection
if (!empty($_POST) && isset($_SERVER['HTTP_ORIGIN'])){
$hostname = parse_url($_SERVER['HTTP_ORIGIN'] ?? 'null', PHP_URL_HOST);
// Checking the Origin header and setting SameSite=Lax on the login
// token cookie should be sufficient for preventing CSRF.
if ($hostname === null || $hostname !== parse_url(BASE_URL, PHP_URL_HOST)){
die('Could not validate the origin of your request.');
}
}
// Route
require_once 'Pages/Actions/actions.php';
$route = $_GET['route'] ?? '';
unset($_GET['route']);
$router = new Router();
$router->add('&/', 'Root/ProjectsController');
$router->add('&/about', 'Root/AboutController');
$router->add('&/users', 'Root/UsersController');
$router->add('&/users/:id', 'Root/UserEditController');
$router->add('&/users/:id/delete', 'Root/UserDeleteController');
$router->add('&/settings', 'Root/SettingsGeneralController');
$router->add('&/settings/roles', 'Root/SettingsRolesController');
$router->add('&/settings/roles/:id', 'Root/SettingsRoleEditController');
$router->add('project/:project/&', 'Project/DashboardController');
$router->add('project/:project/&/issues', 'Project/IssuesController');
$router->add('project/:project/&/issues/new', 'Project/IssueEditController');
$router->add('project/:project/&/issues/new/:type', 'Project/IssueEditController');
$router->add('project/:project/&/issues/:id', 'Project/IssueDetailController');
$router->add('project/:project/&/issues/:id/edit', 'Project/IssueEditController');
$router->add('project/:project/&/issues/:id/delete', 'Project/IssueDeleteController');
$router->add('project/:project/&/milestones', 'Project/MilestonesController');
$router->add('project/:project/&/milestones/:id', 'Project/MilestoneEditController');
$router->add('project/:project/&/milestones/:id/delete', 'Project/MilestoneDeleteController');
$router->add('project/:project/&/members', 'Project/MembersController');
$router->add('project/:project/&/members/:id', 'Project/MemberEditController');
$router->add('project/:project/&/members/:id/remove', 'Project/MemberRemoveController');
$router->add('project/:project/&/settings', 'Project/SettingsGeneralController');
$router->add('project/:project/&/settings/description', 'Project/SettingsDescriptionController');
$router->add('project/:project/&/settings/roles', 'Project/SettingsRolesController');
$router->add('project/:project/&/settings/roles/:id', 'Project/SettingsRoleEditController');
$router->add('project/:project/&/delete', 'Root/ProjectDeleteController');
foreach(['&/', 'project/:project/&/'] as $base){
$router->add($base.'login', 'Mixed/LoginController');
$router->add($base.'register', 'Mixed/RegisterController');
$router->add($base.'account', 'Mixed/AccountController');
$router->add($base.'account/appearance', 'Mixed/AccountAppearanceController');
$router->add($base.'account/security', 'Mixed/AccountSecurityController');
}
$router->add('&/favicon.ico', 'Root/FaviconController');
function handle_error(int $code, string $title, string $message, ?Request $req = null): void{
http_response_code($code);
message($req ?? Request::empty(), $title, $message)->execute();
}
try{
$router->route($route);
}catch(RouterException $e){
Log::critical($e);
$code = $e->getCode();
$req = $e->getReq();
if ($code === RouterException::STATUS_FORBIDDEN){
handle_error($code, 'Permission Error', 'You do not have permission to perform this action.', $req);
}
elseif ($code === RouterException::STATUS_NOT_FOUND){
handle_error($code, 'Not Found', $e->getMessage(), $req);
}
else{
handle_error($code, 'Fatal Error', 'An error occurred while handling your request.', $req);
}
}catch(Exception $e){
Log::critical($e);
handle_error(RouterException::STATUS_SERVER_ERROR, 'Fatal Error', 'An error occurred while handling your request.');
}
?>