diff --git a/public/index.php b/public/index.php index 0847726..7c3b8da 100644 --- a/public/index.php +++ b/public/index.php @@ -1,24 +1,21 @@ -uri(0); // redirect depending on installation status installRedirect($route); // route to the relevant module -if ($route == '/') return HomeModule::home(); -if ($route == 'install') return InstallModule::handle(); -if ($route == 'gate') return GateModule::handle(); - -// 404 -http_response_code(404); -echo '404: ' . $route; - -// cleanup -$app->cleanup(); +$app->route('/', 'HomeModule') + ->route('/install', 'InstallModule') + ->route('/gate', 'GateModule') + ->handle($route) + ->cleanup(); diff --git a/server/app/App.php b/server/app/App.php index 4fa657f..3e50706 100644 --- a/server/app/App.php +++ b/server/app/App.php @@ -6,19 +6,18 @@ class App { + private array $routes = []; public static Database $db; - private static string $dbPath; public static Request $req; public static Auth $auth; public static array $s = []; // game settings public static array $flashes = []; // flash messages - public function __construct(string $dbPath) + public function __construct(Database $db, Request $req, Auth $auth) { - self::$req = new Request(); // the current request - self::$db = new Database($dbPath); // the database - self::$dbPath = $dbPath; // the database path - self::$auth = new Auth(); + self::$req = $req; // the current request + self::$db = $db; // the database + self::$auth = $auth; // the auth system // load game settings $s = self::$db->q('SELECT * FROM settings WHERE id = 1;'); @@ -33,19 +32,24 @@ class App self::$flashes = $_SESSION['flash'] ?? []; } - public static function performDatabaseReset(): void - { - if (file_exists(self::$dbPath)) { - unlink(self::$dbPath); - self::$db = new Database(self::$dbPath); - } - } - public static function auth(): bool { return self::$auth->good(); } + public function route(string $uri, string $module): App + { + $this->routes[$uri] = $module; + return $this; + } + + public function handle(string $uri): App + { + if (!isset($this->routes[$uri])) return self::fourOhFour($uri); + $this->routes[$uri]::handle(); + return $this; + } + public static function flash(string $key, mixed $value = null): mixed { // get a flash message @@ -54,12 +58,20 @@ class App // set a flash message $_SESSION['flash'][$key] = $value; self::$flashes[$key] = $value; + + return null; } public function cleanup() { // clean up flash messages $_SESSION['flash'] = []; - unset($_SESSION['flash']); + self::$flashes = []; + } + + public static function fourOhFour(string $uri): void + { + http_response_code(404); + echo "404: $uri"; } } diff --git a/server/app/Auth.php b/server/app/Auth.php index 6d2f49c..804dd91 100644 --- a/server/app/Auth.php +++ b/server/app/Auth.php @@ -13,11 +13,6 @@ class Auth // id of the player public static int $id = 0; - public function __construct() - { - - } - public function login(string $identifier, string $password, bool $remember = false): bool { // delete the old session @@ -82,4 +77,25 @@ class Auth return false; } + + public static function boot(): void + { + // adjust session settings + ini_set('session.gc_maxlifetime', 604800); // 1 week in seconds + ini_set('session.cookie_lifetime', 604800); // 1 week in seconds + + // ensure secure session handling + ini_set('session.use_strict_mode', 1); + ini_set('session.cookie_httponly', 1); + ini_set('session.cookie_secure', 1); // only if using HTTPS + + // start the session + session_start(); + + // regenerate session ID to prevent session fixation + if (!isset($_SESSION['initiated'])) { + session_regenerate_id(true); + $_SESSION['initiated'] = true; + } + } } diff --git a/server/app/Database.php b/server/app/Database.php index 536b092..2d579fd 100644 --- a/server/app/Database.php +++ b/server/app/Database.php @@ -13,6 +13,7 @@ class Database private int $queries = 0; private array $log = []; private float $time = 0; + private string $path = ''; public function __construct(string $path, array $opts = []) { @@ -25,6 +26,7 @@ class Database $this->c = new PDO("sqlite:$path", null, null, $opts); $this->c->exec('PRAGMA foreign_keys = ON;'); // Enable foreign keys $this->c->exec('PRAGMA journal_mode = WAL;'); // Enable WAL + $this->path = $path; } catch (PDOException $e) { throw $e; } @@ -82,6 +84,11 @@ class Database return $this->time; } + public function path(): string + { + return $this->path; + } + public function lastInsertID(): int { return $this->c->lastInsertId(); diff --git a/server/boot/Autoloader.php b/server/boot/Autoloader.php new file mode 100644 index 0000000..ae1437b --- /dev/null +++ b/server/boot/Autoloader.php @@ -0,0 +1,34 @@ + 'path/to/class.php', + + // server-level classes + 'App' => SERVER.'/app/App.php', + 'Database' => SERVER.'/app/Database.php', + 'Request' => SERVER.'/app/Request.php', + 'Auth' => SERVER.'/app/Auth.php', + + // modules + 'HomeModule' => SERVER.'/modules/HomeModule.php', + 'InstallModule' => SERVER.'/modules/InstallModule.php', + 'GateModule' => SERVER.'/modules/GateModule.php', + + // models + 'Classes' => SERVER.'/models/Classes.php', + 'Player' => SERVER.'/models/Player.php', + 'Spell' => SERVER.'/models/Spell.php', + 'Session' => SERVER.'/models/Session.php', + ]; + + // autoloader + public static function boot(): void + { + spl_autoload_register(function($class) { + if (isset(self::MAP[$class])) require_once self::MAP[$class]; + }); + } +} \ No newline at end of file diff --git a/server/boot/Boot.php b/server/boot/Boot.php new file mode 100644 index 0000000..9544938 --- /dev/null +++ b/server/boot/Boot.php @@ -0,0 +1,31 @@ + \ No newline at end of file +*/ \ No newline at end of file diff --git a/server/bootstrap.php b/server/bootstrap.php deleted file mode 100644 index 89160c0..0000000 --- a/server/bootstrap.php +++ /dev/null @@ -1,62 +0,0 @@ - 'path/to/class.php', - - // server-level classes - 'App' => SERVER.'/app/App.php', - 'Database' => SERVER.'/app/Database.php', - 'Request' => SERVER.'/app/Request.php', - 'Auth' => SERVER.'/app/Auth.php', - - // modules - 'HomeModule' => SERVER.'/modules/HomeModule.php', - 'InstallModule' => SERVER.'/modules/InstallModule.php', - 'GateModule' => SERVER.'/modules/GateModule.php', - - // models - 'Classes' => SERVER.'/models/Classes.php', - 'Player' => SERVER.'/models/Player.php', - 'Spell' => SERVER.'/models/Spell.php', - 'Session' => SERVER.'/models/Session.php', -]; - -// autoloader -spl_autoload_register(function($class) { - if (isset(MAP[$class])) require_once MAP[$class]; -}); diff --git a/server/modules/HomeModule.php b/server/modules/HomeModule.php index 78236a7..f1cb3bf 100644 --- a/server/modules/HomeModule.php +++ b/server/modules/HomeModule.php @@ -2,9 +2,14 @@ class HomeModule { + public static function handle() + { + return self::home(); + } + public static function home() { - foreach ($_SESSION['flash'] as $key => $value) { + foreach (($_SESSION['flash'] ?? []) as $key => $value) { echo '
- ' . $value . '
'; } diff --git a/server/modules/InstallModule.php b/server/modules/InstallModule.php index d3f2a4f..269d793 100644 --- a/server/modules/InstallModule.php +++ b/server/modules/InstallModule.php @@ -29,8 +29,8 @@ class InstallModule $complete = $_POST['mode'] == 'complete'; // complete or partial setup $defaults = SERVER.'/database/packs/Default/'; - // if the database already exists, have the app remake it - App::performDatabaseReset(); + // if the database already exists, delete and remake it + if (file_exists(DB) && unlink(DB)) App::$db = new Database(DB); // @Settings App::$db->q("CREATE TABLE IF NOT EXISTS 'settings' (