From 829e10437eae82c87d07d9f26ed7deea1eda02fc Mon Sep 17 00:00:00 2001 From: Thayol Date: Wed, 8 Jul 2026 21:44:11 +0200 Subject: [PATCH] Initial commit --- .gitignore | 2 + README.md | 13 +++++ config.php.example | 7 +++ enet_probe.php | 57 ++++++++++++++++++ index.php | 141 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 220 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 config.php.example create mode 100644 enet_probe.php create mode 100644 index.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3615400 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +state.json +config.php diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e4979d --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Supercardinality Online Services + +The reference implementation for online services for Supercardinality. + +## Setup + +Create the `config.php` file based on `config.php.example`. + +Host the repo root using a PHP capable web server. + +It's a good idea to block access to your state file. +A common way to protect it from being publicly readable is to configure it to be outside of the web server. +If you store it in the default location you may want to block access to it using URL rewrite rules. diff --git a/config.php.example b/config.php.example new file mode 100644 index 0000000..8c18ccd --- /dev/null +++ b/config.php.example @@ -0,0 +1,7 @@ + []])); +} + +$state = json_decode(file_get_contents($state_file), true); + +$cutoff_timestamp = time() - $lobby_timeout_seconds; +foreach (array_keys($state["lobbies"]) as $id) { + if ($state["lobbies"][$id]["updated_at"] < $cutoff_timestamp) { + unset($state["lobbies"][$id]); + } +} + +if (isset($_GET["list"])) { + $list = []; + foreach ($state["lobbies"] as $id => $lobby) { + $list[$id] = [ + "id" => $lobby["id"], + "host" => $lobby["host"], + "name" => $lobby["name"], + "creator" => $lobby["creator"], + "version" => $lobby["version"], + "created_at" => $lobby["created_at"], + ]; + } + header("Content-Type: application/json"); + echo json_encode(["lobbies" => $list]); +} +elseif (isset($_GET["new"])) { + require "enet_probe.php"; + $host = $_SERVER['REMOTE_ADDR']; + if (!empty($_GET["host"])) { + $host = $_GET["host"]; + } + $reachable = enet_probe($host, 50403); + header("Content-Type: application/json"); + if ($reachable) { + $id = generate_uuid_v4(); + $secret = generate_uuid_v4(); + $version = $_GET["version"] ?? ""; + $creator = $_GET["creator"] ?? ""; + $name = "{$creator}'s lobby"; + if (!empty($_GET["name"])) { + $name = $_GET["name"]; + } + $lobby = [ + "id" => $id, + "secret" => $secret, + "host" => $host, + "name" => $name, + "version" => $version, + "creator" => $creator, + "updated_at" => time(), + "created_at" => time(), + ]; + $state["lobbies"][$id] = $lobby; + echo json_encode($lobby); + } + else { + http_response_code(424); + echo json_encode(["error" => "NOT_REACHABLE", "host" => $host]); + } +} +elseif (isset($_GET["update"])) { + $id = $_GET["id"]; + $secret = $_GET["secret"]; + $lobby = $state["lobbies"][$id]; + header("Content-Type: application/json"); + if (!in_array($id, array_keys($state["lobbies"])) || empty($lobby)) { + http_response_code(404); + echo json_encode(["error" => "NOT_FOUND", "id" => $id]); + } + elseif ($lobby["secret"] != $secret) { + http_response_code(403); + echo json_encode(["error" => "NOT_AUTHORIZED", "id" => $id]); + } + else { + $name = $_GET["name"] ?? ""; + if (!empty($name)) { + $lobby["name"] = $name; + } + $lobby["updated_at"] = time(); + $state["lobbies"][$id] = $lobby; + echo json_encode(["result" => "updated"]); + } +} +elseif (isset($_GET["close"])) { + $id = $_GET["id"]; + $secret = $_GET["secret"]; + $lobby = $state["lobbies"][$id]; + header("Content-Type: application/json"); + if (!in_array($id, array_keys($state["lobbies"])) || empty($lobby)) { + http_response_code(404); + echo json_encode(["error" => "NOT_FOUND", "id" => $id]); + } + elseif ($lobby["secret"] != $secret) { + http_response_code(403); + echo json_encode(["error" => "NOT_AUTHORIZED", "id" => $id]); + } + else { + unset($state["lobbies"][$id]); + echo json_encode(["result" => "closed"]); + } +} +else { + header("Content-Type: application/json"); + echo json_encode(["status" => "OK"]); +} + +file_put_contents($state_file, json_encode($state, JSON_PRETTY_PRINT));