From 3de09009d6951ff7751c53883dd6fa3faa49034c Mon Sep 17 00:00:00 2001 From: anima Date: Mon, 2 Nov 2026 02:16:44 +0100 Subject: [PATCH] fix mail verify --- Dockerfile | 10 ++- README.md | 32 +++++++-- docker/patch-auto-verify-email.js | 106 ++++++++++++++++++++++++++++++ files/config/options.js | 6 +- verify_user.sh | 14 ++++ 5 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 docker/patch-auto-verify-email.js create mode 100644 verify_user.sh diff --git a/Dockerfile b/Dockerfile index 773e42f..dc5756e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,13 +59,21 @@ COPY docker/patch-attribution.js /tmp/patch-attribution.js RUN node /tmp/patch-attribution.js /app/htmls/contents/account_help.html # Local patch: custom game values and elements (docker/patch-custom-game.js). -# Hooks the loader into main.js and the game server, makes the Lone Wolf rates +# Hooks the loader into main.js and the game server, makes the e.g. Lone Wolf rates # data-driven, and merges phrase overrides into the language catalogs. The # loader itself is copied to /app/docker/ in the runtime stage; the custom file # is mounted at runtime from ./files/custom. COPY docker/patch-custom-game.js /tmp/patch-custom-game.js RUN node /tmp/patch-custom-game.js /app +# Local patch: optional email auto-verification (docker/patch-auto-verify-email.js). +# A self-hosted server without SES cannot deliver verification links, so every +# new account would stay "Not Verified". The patch marks accounts verified at +# signup and login when options.auto_verify_email is enabled; without the +# option the upstream behaviour is unchanged. +COPY docker/patch-auto-verify-email.js /tmp/patch-auto-verify-email.js +RUN node /tmp/patch-auto-verify-email.js /app + FROM ${NODE_IMAGE} AS runtime diff --git a/README.md b/README.md index d87d7fb..fd9d954 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,12 @@ passt. Backend und Game-Server ein und macht die Lone-Wolf-Raten datengetrieben (siehe „Spieldaten anpassen“). Fehlt ein Anker, bricht der Build ebenfalls ab. +`docker/patch-auto-verify-email.js` markiert bei aktivem +`options.auto_verify_email` neue Konten beim Signup und bestehende beim nächsten +Login als verifiziert und überspringt die Verifikationsmail. Ohne den Schalter +bleibt das Upstream-Verhalten unverändert. Auch dieser Patch bricht den Build +ab, wenn ein Anker in `api.js` fehlt. + ## Spieldaten anpassen (`files/custom/game.js`) Werte bestehender Elemente und neue Elemente lassen sich ohne Quelltextänderung @@ -183,12 +189,13 @@ Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten. ## 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: +- **E-Mail-Verifizierung:** AWS SES ist nicht konfiguriert. Deshalb setzt + `options.auto_verify_email: true` neue Konten beim Signup und bestehende beim + nächsten Login auf „verifiziert“; die Verifikationsmail wird übersprungen. Der + „Not Verified“-Debuff (Gold/Glück −25 %) tritt damit nicht mehr auf. Auf + `false` gestellt, gilt wieder der Upstream-Ablauf: Im Backend-Log erscheint + `send_email error InvalidClientTokenId`, und der Verifizierungslink muss + manuell geöffnet werden: ```sh docker compose exec al-mongo mongosh --quiet adventureland --eval \ @@ -197,7 +204,18 @@ Custom-Datei zurückgesetzt werden; dann den Game-Server neu starten. ``` Link im Browser öffnen, danach neu einloggen. Alternativ `info.verified` direkt - auf `true` setzen (siehe Admin-Befehl oben). + auf `true` setzen (siehe Admin-Befehl oben). Die `/ev`-Route bleibt in beiden + Fällen funktionsfähig. + +- **Tutorial-Belohnung (`c0`):** Jedes Konto mit `auth_id` (Steam/MAS) kann nach + abgeschlossenem Tutorial einmal `c0` abholen. Die Belohnung ist ein zufälliger + kosmetischer Look aus dem `cosmo0`-Pool (über 100 Varianten). Der Game-Server + prüft dafür `player.verified` **und** `player.auth_id` + (`node/server.js:5272`). Bei reinen Web-Accounts ohne Steam/MAS bleibt + `auth_id` leer, deshalb ist die Belohnung trotz Auto-Verifizierung weiterhin + gesperrt. Die alten Klassen-Belohnungen (`creward`) sind in + `design/classes.js` auskommentiert und werden vom Client nicht angefragt; + Hardcore-Rewards gelten nur auf dem Hardcore-Server. - **„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 diff --git a/docker/patch-auto-verify-email.js b/docker/patch-auto-verify-email.js new file mode 100644 index 0000000..4d7b2fb --- /dev/null +++ b/docker/patch-auto-verify-email.js @@ -0,0 +1,106 @@ +#!/usr/bin/env node +// Local patch: optional email auto-verification for self-hosted servers. +// +// Adventure Land normally emails a verification link after signup. A +// self-hosted server without SES/SMTP cannot deliver it, so every new account +// stays "Not Verified" (luck/gold -25%) until an admin verifies it manually. +// +// With options.auto_verify_email enabled, this patch: +// - marks new accounts verified before they are saved, +// - verifies existing accounts on their next login, +// - keeps accounts verified when they change their email address, +// - skips the verification emails that cannot be delivered. +// +// Upstream behaviour is unchanged when the option is absent or false. Every +// edit is idempotent and fails loudly if the anchor is gone. + +const fs = require("node:fs"); +const path = require("node:path"); + +const app = path.resolve(process.argv[2] || "/app"); +const file = path.join(app, "api.js"); +let source = fs.readFileSync(file, "utf8"); + +// `options` is always present in production, but some upstream tests load +// api.js without it. Keep the patched code loadable there too. +const autoVerify = 'typeof options !== "undefined" && options.auto_verify_email'; + +function fail(message) { + console.error("patch-auto-verify-email: " + message); + process.exit(1); +} + +function edit(label, from, to) { + if (source.includes(to)) { + console.log("patch-auto-verify-email: " + label + " already patched"); + return; + } + const occurrences = source.split(from).length - 1; + if (occurrences !== 1) { + fail(label + ": expected 1 occurrence of the anchor, found " + occurrences); + } + source = source.replace(from, to); + console.log("patch-auto-verify-email: patched " + label); +} + +// 1. Existing accounts: verify them when they log in. +edit( + "login", + `\t\t\t\t\tR.auth = get_new_auth(R.user); +\t\t\t\t\tawait tx_save(R.user);`, + `\t\t\t\t\t// Local: keep accounts verified without an email service. +\t\t\t\t\tif (${autoVerify}) R.user.info.verified = true; +\t\t\t\t\tR.auth = get_new_auth(R.user); +\t\t\t\t\tawait tx_save(R.user);`, +); + +// 2. New accounts: set the flag before the user document is written. +edit( + "signup", + `\t\t\t\tblobs: ["info"], +\t\t\t}; +\t\t\tR.auth = get_new_auth(R.user);`, + `\t\t\t\tblobs: ["info"], +\t\t\t}; +\t\t\t// Local: new accounts are verified immediately without an email service. +\t\t\tif (${autoVerify}) R.user.info.verified = true; +\t\t\tR.auth = get_new_auth(R.user);`, +); + +// 3. Signup: do not try to send a verification email when auto-verify is on. +edit( + "signup email", + `\tset_cookie(args.res, options.cookie_key, get_id(R.user) + "-" + R.auth, domain.domain); +\tsend_verification_email(domain, R.user); +\targs.res.infs.push({ type: "success", message: phrase_html("server.api.signup_complete") });`, + `\tset_cookie(args.res, options.cookie_key, get_id(R.user) + "-" + R.auth, domain.domain); +\tif (!(${autoVerify})) send_verification_email(domain, R.user); +\targs.res.infs.push({ type: "success", message: phrase_html("server.api.signup_complete") });`, +); + +// 4. Email changes: keep the account verified. +edit( + "email change verification", + `\t\t\tif (gf(R.user, "verified", 0)) delete R.user.info.verified;`, + `\t\t\t// Local: keep the account verified after an email change. +\t\t\tif (${autoVerify}) R.user.info.verified = true; +\t\t\telse if (gf(R.user, "verified", 0)) delete R.user.info.verified;`, +); + +// 5. Email changes: skip the verification email and its "re-sent" message. +edit( + "email change email", + `\tif (R.failed) return { failed: true, reason: R.reason || "operation_failed" }; +\tsend_verification_email(domain, R.user); +\targs.res.infs.push({ type: "success", message: phrase_html("server.api.email_changed_verification_email_re_sent_refresh_the_page") });`, + `\tif (R.failed) return { failed: true, reason: R.reason || "operation_failed" }; +\tif (${autoVerify}) { +\t\targs.res.infs.push({ type: "success", message: phrase_html("server.api.setting_changed") }); +\t} else { +\t\tsend_verification_email(domain, R.user); +\t\targs.res.infs.push({ type: "success", message: phrase_html("server.api.email_changed_verification_email_re_sent_refresh_the_page") }); +\t}`, +); + +fs.writeFileSync(file, source); +console.log("patch-auto-verify-email: wrote " + file); diff --git a/files/config/options.js b/files/config/options.js index 2549f09..5ed5620 100644 --- a/files/config/options.js +++ b/files/config/options.js @@ -50,7 +50,11 @@ module.exports = { port: 8090, close_timeout: 4000, ip_limit: 3, - character_limit: 18, + character_limit: 3, + // Without an email service, mark new accounts as verified at signup and + // keep existing accounts verified on login. Set to false to restore the + // upstream verification flow (requires AWS SES). + auto_verify_email: true, fast_sdk: 0, machines: machines, servers: servers, diff --git a/verify_user.sh b/verify_user.sh new file mode 100644 index 0000000..5a69570 --- /dev/null +++ b/verify_user.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# fallback script for mail verify + +set -euo pipefail + +JS='db.user.find({}, {"info.email": 1, "info.everification": 1}).forEach((u) => + print("http://localhost:8090/ev/" + u._id + "/" + u.info.everification))' + +docker compose exec -T al-mongo mongosh --quiet adventureland --eval "$JS" \ + | while IFS= read -r url; do + [[ "$url" == http* ]] || continue + code=$(curl -s -o /dev/null -w '%{http_code}' "$url") + echo "$code $url" + done \ No newline at end of file