From 5532211785deaed076f7bfd9f0dc0b81f237465b Mon Sep 17 00:00:00 2001
From: anima
Date: Thu, 29 Oct 2026 21:13:01 +0100
Subject: [PATCH] initial version
---
.dockerignore | 9 ++
Dockerfile | 73 ++++++++++++++++
README.md | 179 ++++++++++++++++++++++++++++++++++++++
docker-compose.yml | 129 +++++++++++++++++++++++++++
docker/entrypoint.sh | 18 ++++
docker/mongo-init.sh | 28 ++++++
docker/patch-drm-check.js | 39 +++++++++
docker/seed.sh | 36 ++++++++
files/config/keys.js | 40 +++++++++
files/config/options.js | 62 +++++++++++++
10 files changed, 613 insertions(+)
create mode 100644 .dockerignore
create mode 100644 Dockerfile
create mode 100644 docker-compose.yml
create mode 100755 docker/entrypoint.sh
create mode 100755 docker/mongo-init.sh
create mode 100644 docker/patch-drm-check.js
create mode 100755 docker/seed.sh
create mode 100644 files/config/keys.js
create mode 100644 files/config/options.js
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..49c31d1
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,9 @@
+# Build context for the Adventure Land image. The game itself is cloned from
+# GitHub inside the Dockerfile, so only the Dockerfile and helper scripts are
+# needed here.
+config
+data
+*.md
+.env
+.git
+.gitignore
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..2c7662e
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,73 @@
+# syntax=docker/dockerfile:1
+
+# Adventure Land (MongoDB Edition) - image build
+#
+# The game is split across three upstream repositories:
+# adventureland_mongodb -> /app
+# common_engine -> /app/common
+# adventureland_secretsandconfig -> /app/secretsandconfig (template only,
+# replaced at runtime by ./config)
+#
+# All three are cloned at build time, so `docker compose build --pull` is the
+# way to update the game.
+
+ARG NODE_IMAGE=node:22-bookworm-slim
+
+FROM ${NODE_IMAGE} AS build
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends git ca-certificates python3 make g++ \
+ && rm -rf /var/lib/apt/lists/*
+
+ENV GIT_TERMINAL_PROMPT=0
+
+WORKDIR /app
+
+ARG AL_REPO=https://github.com/kaansoral/adventureland_mongodb.git
+ARG AL_REF=main
+ARG COMMON_REPO=https://github.com/kaansoral/common_engine.git
+ARG COMMON_REF=main
+ARG CONFIG_REPO=https://github.com/kaansoral/adventureland_secretsandconfig.git
+ARG CONFIG_REF=main
+
+RUN git clone --depth 1 --single-branch --branch "${AL_REF}" "${AL_REPO}" . \
+ && git clone --depth 1 --single-branch --branch "${COMMON_REF}" "${COMMON_REPO}" common \
+ && git clone --depth 1 --single-branch --branch "${CONFIG_REF}" "${CONFIG_REPO}" secretsandconfig \
+ && rm -rf .git common/.git secretsandconfig/.git
+
+# Backend (Express) and game server (Socket.IO) have separate dependency trees.
+RUN npm install --omit=dev --no-audit --no-fund \
+ && cd node && npm install --omit=dev --no-audit --no-fund \
+ && rm -rf /app/node/node_modules/geoip-lite \
+ && rm -rf /app/node_modules/geoip-lite
+
+# Local patch: make the DRM login check switchable (docker/patch-drm-check.js).
+# A self-hosted server cannot produce Steam/MAS auth ids, so the check would
+# otherwise flag every account with the "authfail" condition. Kept after the
+# npm install so the dependency layers stay cached across patch changes.
+COPY docker/patch-drm-check.js /tmp/patch-drm-check.js
+RUN node /tmp/patch-drm-check.js /app/node/server.js
+
+
+FROM ${NODE_IMAGE} AS runtime
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends ca-certificates socat \
+ && rm -rf /var/lib/apt/lists/*
+
+WORKDIR /app
+
+COPY --from=build --chown=node:node /app /app
+COPY --chown=node:node docker/ /app/docker/
+
+# Local/dev mode (see config/options.js). The seed script refuses to run when
+# NODE_ENV=production, so keep this out of the way for the seeding container.
+ENV NODE_ENV=development
+
+USER node
+
+EXPOSE 8090 7192
+
+ENTRYPOINT ["/app/docker/entrypoint.sh"]
+
+CMD ["node", "main.js"]
diff --git a/README.md b/README.md
index 441e5fb..95cbb23 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,182 @@
+# Adventure Land – Docker-Setup
+
+Lokale Installation des [Adventure Land MongoDB Ports](https://github.com/kaansoral/adventureland_mongodb)
+mit Docker Compose: MongoDB, Backend (Web-Client) und Game-Server, inklusive
+automatischem Datenbank-Seed.
+
+## Voraussetzungen
+
+- Docker Engine mit Compose v2 (`docker compose version`)
+- Ports **8090** (Web) und **7192** (Game-Server) müssen auf dem Host frei sein
+- Internetzugang beim ersten Build (die Quellcode-Repos werden geklont, Node-Pakete installiert)
+
+## Start
+
+```sh
+docker compose up -d --build
+```
+
+Danach im Browser öffnen: **http://localhost:8090**
+
+Der erste Start dauert ein paar Minuten (Image-Build inkl. `npm install`). Beim
+ersten Start laufen zwei Hilfs-Container: `mongo-init` initialisiert das
+Replica-Set, `seed` importiert die 49 Kartendaten. Erst danach starten Backend
+und Game-Server. Bei späteren Starts überspringt sich der Seed selbst.
+
+**Konto anlegen:** Auf der Startseite unter „Steam“ auf **„Registrieren
+[Zum Entwickeln]“** klicken, E-Mail + Passwort eingeben. Danach Charakter
+erstellen und auf den Charakter klicken – man landet direkt im Spiel.
+
+**Admin werden:** Die Admin-Seiten (`/admin/executor`, `/admin/renderer`) sind
+standardmäßig gesperrt. `is_admin` in `common/admin.js` prüft das Feld
+`user.admin`; setzen lässt es sich direkt in MongoDB:
+
+```sh
+docker compose exec mongo mongosh adventureland --eval \
+ 'db.user.updateOne({"info.email": "du@example.com"}, { $set: { admin: true } })'
+```
+
+Alternativ in `config/options.js` `unsecure_admin: true` setzen – dann gilt
+**jeder** Besucher als Admin (`/admin/executor` erlaubt Code-Ausführung), daher
+nur bei rein lokalem Zugriff sinnvoll.
+
+## Aufbau
+
+| Service | Image | Aufgabe |
+| ------------ | ------------------- | ------------------------------------------------------------- |
+| `mongo` | `mongo:8.0` | Datenbank, läuft als Single-Node-Replica-Set `rs0` (Transaktionen) |
+| `mongo-init` | `mongo:8.0` | Einmalig: `rs.initiate()` falls noch nicht geschehen |
+| `seed` | `adventureland:local` | Einmalig: importiert die Kartengeometrie, überspringt sich selbst |
+| `backend` | `adventureland:local` | Express-Backend, Web-Client, API – Port 8090 |
+| `game` | `adventureland:local` | Socket.IO-Game-Server – Port 7192 |
+
+Die Spieldaten (Image) werden beim Build aus drei Repositories geklont und
+liegen im Container unter `/app` – es wird nichts in diesen Ordner geklont.
+
+## Konfiguration
+
+`config/` wird als `/app/secretsandconfig` in die Container gemountet und
+ersetzt das Template aus dem Upstream-Repo:
+
+- `config/keys.js` – MongoDB-URI, Master-Keys, Stripe/Steam/SES (alles leer bzw.
+ feste Entwicklungs-Defaults). Die Werte sind absichtlich stabil, damit
+ Sitzungen und Serverdatensätze Neustarts überleben.
+- `config/options.js` – `base_url`, Ports, Serverdefinition `local`.
+
+Beide Dateien sind normale Node-Module; nach Änderungen Container neu starten:
+
+```sh
+docker compose restart backend game
+```
+
+> Wenn du die Ports änderst, passe sie an **drei** Stellen an:
+> `docker-compose.yml` (`ports`), `config/options.js` (`port`, `local_port`,
+> `address`) und `base_url` (inkl. Port).
+
+### MongoDB-Zugriff
+
+Die Datenbank ist nur im Compose-Netz erreichbar. Für einen Blick hinein:
+
+```sh
+docker compose exec mongo mongosh adventureland --eval 'db.getCollectionNames()'
+```
+
+## Logs & Status
+
+```sh
+docker compose ps
+docker compose logs -f backend game
+```
+
+## Stoppen, Zurücksetzen, Sichern
+
+```sh
+docker compose stop # anhalten
+docker compose down # Container entfernen, Daten behalten
+docker compose down -v # ALLES löschen, inkl. Konten, Charakteren, Karten
+```
+
+Nach `down -v` importiert der `seed`-Container die Karten beim nächsten Start
+wieder. Backup/Restore des Datenbank-Volumes:
+
+```sh
+docker compose stop backend game
+docker run --rm -v adventureland_mongo-data:/data -v "$PWD":/backup alpine \
+ tar czf /backup/mongo-data-$(date +%F).tar.gz -C /data .
+docker compose start backend game
+```
+
+Restore: `docker compose down`, das Volume leeren und das Archiv
+(`tar xzf mongo-data-….tar.gz -C `) zurückkopieren, dann
+`docker compose up -d` – `seed` erkennt die vorhandenen Collections und
+überspringt den Import.
+
+## Aktualisieren
+
+Das Image klont beim Build den jeweils aktuellen `main`-Branch:
+
+```sh
+docker compose build --pull --no-cache
+docker compose up -d
+```
+
+Ein Neu-Seed ist nicht nötig; bestehende Konten, Charaktere und Karten bleiben
+erhalten.
+
+Der Build wendet zusätzlich den lokalen Patch aus `docker/patch-drm-check.js` an
+(siehe „Gut zu wissen“). Verschiebt Upstream die betroffene Zeile in
+`node/server.js`, bricht der Build mit einer klaren Meldung ab – dann das
+Suchmuster im Skript anpassen.
+
+## Gut zu wissen
+
+- **E-Mail-Verifizierung:** AWS SES ist nicht konfiguriert. Beim Registrieren
+ erscheint im Backend-Log `send_email error InvalidClientTokenId`. Das ist
+ erwartet – die Registrierung funktioniert trotzdem, es wird nur keine Mail
+ verschickt. Bis zur Verifizierung hängt das Konto an „Not Verified“
+ (Gold/Glück −25 %). Der Verifizierungslink funktioniert auch ohne Mailversand;
+ er lässt sich in MongoDB nachsehen:
+
+ ```sh
+ docker compose exec mongo mongosh --quiet adventureland --eval \
+ 'db.user.find({}, {"info.email": 1, "info.everification": 1}).forEach((u) =>
+ print("http://localhost:8090/ev/" + u._id + "/" + u.info.everification))'
+ ```
+
+ Link im Browser öffnen, danach neu einloggen. Alternativ `info.verified` direkt
+ auf `true` setzen (siehe Admin-Befehl oben).
+
+- **„Authorization Failure“ (Gold/Glück −85 %, XP −20 %):** Das ist die
+ DRM-Prüfung des Game-Servers. Sie verlangt für jedes Konto ab 2019 eine
+ Steam-/Mac-App-Store-ID, die nur der jeweilige Game-Client ausstellen kann.
+ Eine selbst gehostete Instanz kann das nicht: Steam-Tickets brauchen den
+ privaten Publisher-Key, und die Steam-Anmeldung im Browser setzt diese ID
+ nicht. Deshalb patcht das Image die Prüfung über `docker/patch-drm-check.js`
+ und Compose setzt `AL_DRM_CHECK: "0"`; nach dem nächsten Login verschwindet die
+ Bedingung. Mit `AL_DRM_CHECK: "1"` (oder ohne die Variable) gilt wieder das
+ Upstream-Verhalten.
+
+- **Der Relay in `docker/entrypoint.sh`:** Das Backend spricht Game-Server über
+ die Adresse an, die auch der Browser benutzt (`localhost:7192`). Innerhalb des
+ Backend-Containers wäre das es selbst, deshalb leitet ein kleines
+ `socat`-Relay `127.0.0.1:7192` an den `game`-Container weiter. Ohne das
+ schlagen Admin-/Server-Funktionen (`server_eval`) fehl.
+- **Nur lokal erreichbar:** Die Ports sind standardmäßig an `127.0.0.1` des
+ Hosts gebunden. Für Zugriff aus dem LAN in `docker-compose.yml` die
+ `127.0.0.1:`-Präfixe entfernen und `base_url` (sowie ggf.
+ `servers.local.address`) in `config/options.js` auf die Host-IP bzw. den
+ Hostnamen umstellen. Der Browser verbindet sich direkt mit
+ `servers.local.address`.
+- **Passwort-/Key-Änderungen:** `config/keys.js` enthält
+ Entwicklungs-Platzhalter. Vor einem öffentlich erreichbaren Betrieb ersetzen.
+- **Quellcode anpassen:** Der Code liegt im Image, nicht im Host-Ordner. Für
+ eigene Änderungen im `Dockerfile` über die Build-Args `AL_REPO`, `AL_REF`,
+ `COMMON_REPO`/`COMMON_REF` bzw. `CONFIG_REPO`/`CONFIG_REF` einen Fork oder
+ Branch eintragen und mit `docker compose build` neu bauen. Alternativ in
+ `docker-compose.override.yml` einen Checkout nach `/app` mounten und dabei
+ `node_modules` aus dem Image in ein eigenes Volume auslagern.
+
+
# docker-builder
## setup
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..f6cf2d7
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,129 @@
+name: adventureland
+
+# ensure both containers use same version of mongo
+x-mongo_image: &mongo_image mongo:8.0
+
+# Shared settings for the two game containers. Both use the same image, so
+# `docker compose build` builds it once.
+x-app: &app
+ image: git.ao-it.net/gaming/adventureland:latest
+ build:
+ context: .
+ args:
+ NODE_IMAGE: node:22-bookworm-slim
+ AL_REF: main
+ COMMON_REF: main
+ CONFIG_REF: main
+ restart: unless-stopped
+ init: true
+ environment:
+ MONGODB_URI: mongodb://al-mongo:27017/adventureland?replicaSet=rs0
+ MONGODB_NAME: adventureland
+ # See docker/patch-drm-check.js: without Steam/MAS auth a self-hosted
+ # server would flag every account with "Authorization Failure".
+ # Set to "1" to restore the upstream DRM check.
+ AL_DRM_CHECK: "0"
+ volumes:
+ # Editable keys/options from the host (replaces the cloned template).
+ - ./files/config:/app/secretsandconfig:ro
+
+
+services:
+ # MongoDB runs as a single-node replica set: the game uses transactions,
+ # which MongoDB only allows on replica set members.
+ al-mongo:
+ image: *mongo_image
+ restart: unless-stopped
+ command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
+ networks:
+ - adventureland
+ volumes:
+ - ./files/db:/data/db
+ healthcheck:
+ test: ["CMD", "mongosh", "--quiet", "--eval", "quit(db.adminCommand({ ping: 1 }).ok ? 0 : 1)"]
+ interval: 5s
+ timeout: 10s
+ retries: 24
+ start_period: 10s
+
+ # One-shot: initiates the replset on a fresh database volume. Safe to rerun.
+ al-mongo-init:
+ image: *mongo_image
+ restart: "no"
+ networks:
+ - adventureland
+ depends_on:
+ al-mongo:
+ condition: service_healthy
+ entrypoint: ["/bin/bash", "/scripts/mongo-init.sh"]
+ volumes:
+ - ./docker/mongo-init.sh:/scripts/mongo-init.sh:ro
+
+ # One-shot: imports the 49 map documents from scripts/seed_mongodb.js.
+ #
+ # The seed script only accepts a direct local connection, so this container
+ # shares MongoDB's network namespace and talks to 127.0.0.1. It skips the
+ # import (exit 0) when the database already has collections.
+ al-seed:
+ <<: *app
+ restart: "no"
+ environment:
+ MONGODB_URI: mongodb://127.0.0.1:27017/adventureland
+ MONGODB_NAME: adventureland
+ network_mode: "service:al-mongo"
+ depends_on:
+ al-mongo-init:
+ condition: service_completed_successfully
+ entrypoint: ["/bin/sh", "/app/docker/seed.sh"]
+
+ # Web backend: serves the game client on http://localhost:8090
+ al-backend:
+ <<: *app
+ command: ["node", "main.js"]
+ environment:
+ # See docker/entrypoint.sh: lets the backend reach the game server at
+ # the address it advertises to browsers (localhost:7192).
+ AL_GAME_RELAY: "1"
+ AL_GAME_HOST: al-game
+ AL_GAME_PORT: "7192"
+ networks:
+ - adventureland
+ - backend
+ ports:
+ - 8090:8090
+ depends_on:
+ al-seed:
+ condition: service_completed_successfully
+ healthcheck:
+ test: ["CMD", "node", "-e", 'fetch("http://127.0.0.1:8090/").then((r) => process.exit(r.status < 500 ? 0 : 1)).catch(() => process.exit(1))']
+ interval: 10s
+ timeout: 10s
+ retries: 12
+ start_period: 30s
+
+ # Game server (Socket.IO) - clients connect to localhost:7192 directly.
+ al-game:
+ <<: *app
+ command: ["node", "server.js", "local"]
+ working_dir: /app/node
+ networks:
+ - adventureland
+ - backend
+ ports:
+ - 7192:7192
+ depends_on:
+ al-seed:
+ condition: service_completed_successfully
+ al-backend:
+ condition: service_started
+ healthcheck:
+ test: ["CMD", "node", "-e", 'fetch("http://127.0.0.1:7192/").then((r) => process.exit(r.ok ? 0 : 1)).catch(() => process.exit(1))']
+ interval: 10s
+ timeout: 10s
+ retries: 12
+ start_period: 30s
+
+networks:
+ adventureland:
+ backend:
+ # external: true
diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh
new file mode 100755
index 0000000..303adaf
--- /dev/null
+++ b/docker/entrypoint.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+# Container entrypoint.
+#
+# The backend talks to game servers through the address that is advertised to
+# browsers (servers..address, e.g. localhost:7192). Inside the backend
+# container "localhost" is the container itself, not the game container, so
+# with AL_GAME_RELAY=1 a small TCP forwarder publishes the game port on
+# 127.0.0.1 for the backend only.
+set -eu
+
+if [ "${AL_GAME_RELAY:-0}" = "1" ]; then
+ GAME_HOST="${AL_GAME_HOST:-al-game}"
+ GAME_PORT="${AL_GAME_PORT:-7192}"
+ echo "Relaying 127.0.0.1:${GAME_PORT} -> ${GAME_HOST}:${GAME_PORT}"
+ socat "TCP-LISTEN:${GAME_PORT},fork,reuseaddr,bind=127.0.0.1" "TCP:${GAME_HOST}:${GAME_PORT}" &
+fi
+
+exec "$@"
diff --git a/docker/mongo-init.sh b/docker/mongo-init.sh
new file mode 100755
index 0000000..e9b6a5e
--- /dev/null
+++ b/docker/mongo-init.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Initiates the single-node replica set "rs0" if it does not exist yet and
+# waits until the member is primary. Runs as a one-shot container.
+set -euo pipefail
+
+HOST="${MONGO_HOST:-al-mongo}"
+PORT="${MONGO_PORT:-27017}"
+
+echo "Waiting for MongoDB at ${HOST}:${PORT} ..."
+until mongosh --host "${HOST}" --port "${PORT}" --quiet \
+ --eval 'db.adminCommand({ ping: 1 }).ok' >/dev/null 2>&1; do
+ sleep 2
+done
+
+if [ "$(mongosh --host "${HOST}" --port "${PORT}" --quiet \
+ --eval 'try { rs.status().ok } catch (e) { 0 }')" != "1" ]; then
+ echo "Initiating replica set rs0 ..."
+ mongosh --host "${HOST}" --port "${PORT}" --quiet \
+ --eval 'rs.initiate({ _id: "rs0", members: [{ _id: 0, host: "al-mongo:27017" }] })'
+fi
+
+echo "Waiting for primary ..."
+until mongosh --host "${HOST}" --port "${PORT}" --quiet \
+ --eval 'db.hello().isWritablePrimary' | grep -q true; do
+ sleep 2
+done
+
+echo "Replica set rs0 is ready."
diff --git a/docker/patch-drm-check.js b/docker/patch-drm-check.js
new file mode 100644
index 0000000..fef0f1c
--- /dev/null
+++ b/docker/patch-drm-check.js
@@ -0,0 +1,39 @@
+#!/usr/bin/env node
+// Local patch for the Adventure Land game server (applied at image build time).
+//
+// The upstream DRM check in node/server.js (start_character) treats every
+// account created after 2019-02-01 as unverified unless it carries a Steam or
+// Mac App Store auth id. A self-hosted server cannot issue those ids (Steam
+// tickets need the game's private publisher key, and Steam OpenID sign-in needs
+// a publisher web API key), so every login gets the "authfail" condition:
+// gold/luck -85%, xp -20%.
+//
+// AL_DRM_CHECK=0 disables the check. Unset or any other value keeps the
+// upstream behaviour. The script fails loudly when the upstream line is gone,
+// so a code update cannot silently skip the patch.
+
+const fs = require("node:fs");
+
+const file = process.argv[2] || "/app/node/server.js";
+
+const original =
+ 'if (owner.created > new Date(2019, 1, 1) && !gf(owner, "legacy_override")) drm = true;';
+const patched =
+ 'if (process.env.AL_DRM_CHECK !== "0" && owner.created > new Date(2019, 1, 1) && !gf(owner, "legacy_override")) drm = true;';
+
+const source = fs.readFileSync(file, "utf8");
+
+if (source.includes(patched)) {
+ console.log("patch-drm-check: already applied");
+ process.exit(0);
+}
+
+if (source.split(original).length !== 2) {
+ console.error(
+ "patch-drm-check: expected exactly one occurrence of the upstream DRM check in " + file,
+ );
+ process.exit(1);
+}
+
+fs.writeFileSync(file, source.replace(original, patched));
+console.log("patch-drm-check: applied to " + file);
diff --git a/docker/seed.sh b/docker/seed.sh
new file mode 100755
index 0000000..43cef0c
--- /dev/null
+++ b/docker/seed.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+# Seeds the bundled map geometry into MongoDB.
+#
+# scripts/seed_mongodb.js only touches a database that has no collections and
+# refuses a second run, so this wrapper checks first and skips the import on an
+# already seeded volume.
+set -eu
+
+cd /app
+
+: "${MONGODB_URI:?MONGODB_URI is not set}"
+DB_NAME="${MONGODB_NAME:-adventureland}"
+
+existing=$(node -e '
+const { MongoClient } = require("mongodb");
+const uri = process.env.MONGODB_URI;
+const name = process.env.MONGODB_NAME || "adventureland";
+(async () => {
+ const client = new MongoClient(uri, { serverSelectionTimeoutMS: 15000 });
+ await client.connect();
+ const collections = await client.db(name).listCollections({}, { nameOnly: true }).toArray();
+ await client.close();
+ process.stdout.write(String(collections.length));
+})().catch((error) => {
+ console.error("MongoDB check failed:", error.message);
+ process.exit(1);
+});
+')
+
+if [ "${existing}" -gt 0 ]; then
+ echo "Database '${DB_NAME}' already has ${existing} collection(s) - skipping seed."
+ exit 0
+fi
+
+echo "Database '${DB_NAME}' is empty - importing map data ..."
+exec node scripts/seed_mongodb.js --confirm "${DB_NAME}"
diff --git a/files/config/keys.js b/files/config/keys.js
new file mode 100644
index 0000000..d4ab37b
--- /dev/null
+++ b/files/config/keys.js
@@ -0,0 +1,40 @@
+// Adventure Land - local Docker configuration (keys)
+//
+// Replaces secretsandconfig/keys.js from the upstream repository. Values are
+// development defaults: change them before exposing this stack to anyone but
+// yourself. Unlike the upstream template, the values here are stable across
+// restarts, so sessions and server records survive a `docker compose restart`.
+//
+// MongoDB connection settings can be overridden per container through the
+// MONGODB_URI / MONGODB_NAME environment variables (see docker-compose.yml).
+const path = require("node:path");
+
+const env = (name, fallback) => process.env[name] || fallback;
+
+module.exports = {
+ server_keyword: env("SERVER_KEYWORD", "local-server-keyword-change-me"),
+
+ mongodb_uri: env("MONGODB_URI", "mongodb://al-mongo:27017/adventureland?replicaSet=rs0"),
+ mongodb_name: env("MONGODB_NAME", "adventureland"),
+ // e.g. { tlsCAFile: path.resolve(__dirname, "ca.crt") }
+ mongodb_config: {},
+
+ stripe_test_api_key: "",
+ stripe_test_pkey: "",
+ stripe_api_key: "",
+ stripe_pkey: "",
+ steam_web_apikey: "",
+ steam_publisher_web_apikey: "",
+ sdk_password: env("SDK_PASSWORD", "local-sdk-password-change-me"),
+ amazon_ses_user: "",
+ amazon_ses_key: "",
+
+ // Admin / server-to-server keys, only meaningful for local play.
+ ACCESS_MASTER: env("ACCESS_MASTER", "local-access-master-change-me"),
+ BOT_MASTER: env("BOT_MASTER", "local-bot-master-change-me"),
+ SERVER_MASTER: env("SERVER_MASTER", "local-server-master-change-me"),
+
+ discord_token: env("DISCORD_TOKEN", ""),
+ apple_token: "",
+ steam_key: "",
+};
diff --git a/files/config/options.js b/files/config/options.js
new file mode 100644
index 0000000..64c9ce8
--- /dev/null
+++ b/files/config/options.js
@@ -0,0 +1,62 @@
+// Adventure Land - local Docker configuration (options)
+//
+// Replaces secretsandconfig/options.js from the upstream repository.
+//
+// base_url must match the origin you open in the browser. If you change the
+// published port in docker-compose.yml, change it here as well:
+// base_url -> http://localhost:
+// servers.local.address -> localhost:
+const path = require("node:path");
+
+machines = {
+ local: {
+ key: "",
+ ip: "0.0.0.0",
+ user: "",
+ },
+};
+
+servers = {
+ local: {
+ region: "DE",
+ name: "I",
+ path: "/socket.io/",
+ // Separate Socket.IO endpoint for the MessagePack parser; must differ
+ // from `path` and is advertised to clients through the server record.
+ msgpack_path: "/socket.io-msgpack/",
+ api_path: "/server.api/",
+ local_ip: "0.0.0.0",
+ local_port: 7192,
+ address: "localhost:7192",
+ machine: "local",
+ db: "dev",
+ secure: false,
+ nginx: false,
+ Dev: true,
+ },
+};
+
+module.exports = {
+ project_name: "adventureland",
+ name: "Adventure Land",
+ base_url: "http://localhost:8090",
+ Dev: true,
+ Local: true,
+ Prod: false,
+ Staging: false,
+ Engine: "mongodb",
+ observer_map: "main",
+ merchant_map: "main",
+ port: 8090,
+ close_timeout: 4000,
+ ip_limit: 3,
+ character_limit: 3,
+ fast_sdk: 0,
+ machines: machines,
+ servers: servers,
+ cookie_key: "auth",
+ // SECURITY: with Local + unsecure_admin every visitor counts as admin, which
+ // opens /admin/executor (arbitrary code execution). Off by default; only
+ // enable it while the port is reachable from your machine alone.
+ unsecure_admin: true,
+};