From e2a5dd6d21bfc4ded861e29ff380cf2ab92b5b39 Mon Sep 17 00:00:00 2001
From: anima
Date: Sun, 1 Nov 2026 16:02:29 +0100
Subject: [PATCH] add attribution for self host instance
---
.dockerignore | 16 +++++------
Dockerfile | 10 +++++++
README.md | 12 ++++++++
docker/attribution/de.json | 3 ++
docker/attribution/en.js | 14 ++++++++++
docker/patch-attribution.js | 55 +++++++++++++++++++++++++++++++++++++
6 files changed, 102 insertions(+), 8 deletions(-)
create mode 100644 docker/attribution/de.json
create mode 100644 docker/attribution/en.js
create mode 100644 docker/patch-attribution.js
diff --git a/.dockerignore b/.dockerignore
index 49c31d1..078564e 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,9 +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
+# GitHub inside the Dockerfile, so only the Dockerfile and the helper scripts
+# in docker/ are needed. Runtime data (files/, source-repos/, deploy/) stays
+# out of the context - files/db holds the live MongoDB and is not readable by
+# the build user.
+!Dockerfile
+!docker
+!docker/**
+.env
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
index 2c7662e..255ddd5 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -48,6 +48,16 @@ RUN npm install --omit=dev --no-audit --no-fund \
COPY docker/patch-drm-check.js /tmp/patch-drm-check.js
RUN node /tmp/patch-drm-check.js /app/node/server.js
+# Local patch: self-host attribution (docker/patch-attribution.js).
+# The license requires a crawlable link back to https://adventure.land, and
+# the original project should not appear to support this instance. The phrase
+# ships as docker/attribution/{en.js,de.json}; other languages fall back to
+# English. Kept after the npm install so dependency layers stay cached.
+COPY --chown=node:node docker/attribution/en.js /app/languages/en/attribution.js
+COPY --chown=node:node docker/attribution/de.json /app/languages/de/attribution.json
+COPY docker/patch-attribution.js /tmp/patch-attribution.js
+RUN node /tmp/patch-attribution.js /app/htmls/contents/account_help.html
+
FROM ${NODE_IMAGE} AS runtime
diff --git a/README.md b/README.md
index bbc942c..552ed07 100644
--- a/README.md
+++ b/README.md
@@ -128,6 +128,13 @@ Der Build wendet zusätzlich den lokalen Patch aus `docker/patch-drm-check.js` a
`node/server.js`, bricht der Build mit einer klaren Meldung ab – dann das
Suchmuster im Skript anpassen.
+Ebenso ersetzt `docker/patch-attribution.js` die Hilfe-Zeile im Login
+(„E-Mail, für alles“) durch einen Self-Host-Hinweis mit Link auf
+https://adventure.land. Die Texte liegen in `docker/attribution/en.js` und
+`docker/attribution/de.json`, alle anderen Sprachen fallen auf Englisch zurück.
+Auch dieser Patch bricht den Build ab, wenn die Upstream-Vorlage nicht mehr
+passt.
+
## Gut zu wissen
- **E-Mail-Verifizierung:** AWS SES ist nicht konfiguriert. Beim Registrieren
@@ -161,6 +168,11 @@ Suchmuster im Skript anpassen.
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.
+- **Lizenz/Attribution:** Die AdventureLandOnlyUse-Lizenz verlangt einen
+ crawlable Link auf https://adventure.land. Der ersetzt deshalb die
+ „E-Mail, für alles“-Zeile im Login (siehe `docker/patch-attribution.js`).
+ Zusätzlich ist einmalig eine kurze Mail an hello@adventure.land fällig, wenn
+ die Instanz öffentlich erreichbar geht – das ist keine Code-Änderung.
- **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.
diff --git a/docker/attribution/de.json b/docker/attribution/de.json
new file mode 100644
index 0000000..41e2c51
--- /dev/null
+++ b/docker/attribution/de.json
@@ -0,0 +1,3 @@
+{
+ "pages.attribution.self-hosted": "Self-Hosted-Version von Adventure Land.
Original & Lizenz: adventure.land
Kein Support durch das Originalprojekt."
+}
diff --git a/docker/attribution/en.js b/docker/attribution/en.js
new file mode 100644
index 0000000..f62c328
--- /dev/null
+++ b/docker/attribution/en.js
@@ -0,0 +1,14 @@
+// Self-host attribution line, copied into /app/languages/en/ at image build.
+//
+// The license of Adventure Land requires a crawlable link back to
+// https://adventure.land and forbids implying that the original project
+// supports a self-hosted instance. docker/patch-attribution.js points the
+// login/selection help box at this phrase instead of the upstream
+// "Email, for anything" line.
+//
+// English is also the fallback for every language without its own
+// attribution.json, so keep the markup identical to docker/attribution/de.json.
+module.exports = {
+ "pages.attribution.self-hosted":
+ 'Self-hosted version of Adventure Land.
Original & license: adventure.land
No support by the original project.',
+};
diff --git a/docker/patch-attribution.js b/docker/patch-attribution.js
new file mode 100644
index 0000000..bca96a3
--- /dev/null
+++ b/docker/patch-attribution.js
@@ -0,0 +1,55 @@
+#!/usr/bin/env node
+// Local patch: self-host attribution box (applied at image build time).
+//
+// The AdventureLandOnlyUse license requires a crawlable link back to
+// https://adventure.land, and the original project should not appear to
+// support a self-hosted instance. The upstream login/character-selection help
+// box (htmls/contents/account_help.html) shows "Email, for anything:
+// hello@adventure.land" from a phrase. This patch points that component at
+// pages.attribution.self-hosted instead, which ships as
+// docker/attribution/{en.js,de.json}; all other languages fall back to English.
+//
+// The script fails loudly when the upstream phrase is gone or the shipped
+// catalog is incomplete, so a code update cannot silently drop the attribution.
+
+const fs = require("node:fs");
+const path = require("node:path");
+
+const template = process.argv[2] || "/app/htmls/contents/account_help.html";
+const app = path.resolve(path.dirname(template), "..", "..");
+
+const upstream_id = "pages.contents.selection_features.email-for-anything-hello-adventure-land";
+const phrase_id = "pages.attribution.self-hosted";
+const license_url = "https://adventure.land";
+
+function fail(message) {
+ console.error("patch-attribution: " + message);
+ process.exit(1);
+}
+
+const catalogs = [
+ ["en", require(path.join(app, "languages", "en", "attribution.js"))],
+ ["de", JSON.parse(fs.readFileSync(path.join(app, "languages", "de", "attribution.json"), "utf8"))],
+];
+
+for (const [language, catalog] of catalogs) {
+ const text = catalog[phrase_id];
+ if (typeof text !== "string") fail("missing " + phrase_id + " in languages/" + language + "/attribution");
+ if (!text.includes('href="' + license_url + '"')) {
+ fail("languages/" + language + "/attribution does not link to " + license_url);
+ }
+}
+
+const source = fs.readFileSync(template, "utf8");
+
+if (source.includes('"' + phrase_id + '"')) {
+ console.log("patch-attribution: already applied");
+ process.exit(0);
+}
+
+if (source.split(upstream_id).length !== 2) {
+ fail("expected exactly one occurrence of " + upstream_id + " in " + template);
+}
+
+fs.writeFileSync(template, source.replace(upstream_id, phrase_id));
+console.log("patch-attribution: applied to " + template);