Unverified Commit 2d1592bf authored by Lemon-miaow's avatar Lemon-miaow
Browse files

fix(mods): 加载器 mod 仅在正版验证的独立服务器上签发绑定码,README 标明只用 limbo token 及其风险

parent f1414b5c
Loading
Loading
Loading
Loading
+21 −3
Changes for plugins/README.md: 21 added lines, 3 removed lines.
Original line number Diff line number Diff line
# Felis server-side plugins

These are the in-cluster and edge plugins for Felis. The Velocity proxy and the three loader
mods ship the in-game first leg of the §10 account-link flow: a player who is already online
mods (these on a standalone online-mode server only, see the warning under the module table)
ship the in-game first leg of the §10 account-link flow: a player who is already online
(so Mojang has verified their UUID) runs `/link`; the plugin asks felis-api to
mint a one-time code for that UUID and shows it in chat. The player then enters
the code on the web console → **Account** page (the second leg), which binds the
@@ -40,6 +41,21 @@ no `felis-fabric`/`felis-forge`/`felis-neoforge` jar anywhere. They build from t
the commands under [Building](#building) and are deployed by hand; the account-link flow they
carry works, but nothing installs them for you.

> **The loader mods are for a standalone server only.** Inside a Felis network the proxy's
> `/link` already serves every backend and shadows a backend's own, so user game servers need
> no mod. A mod answers `/link` only when its server runs `online-mode=true`: an offline-mode
> server is either behind a proxy (whose `/link` applies) or cracked, where the UUID is
> whatever the client claims.
>
> **The token a mod holds is a real credential.** It mints a link code for any UUID the mod
> asks about, so whoever can read that server's files — its operator, any plugin or mod on
> it, a copied backup — can bind a not-yet-linked player's Minecraft account to their own web
> account. Put a mod only on a server whose operator you would trust with that, and give it
> the `limbo` token: it opens the link-code, link-status and blacklist routes and nothing
> else. The `velocity` token also approves op-logins and wakes or claims servers for any
> player; it stays on the proxy host. `sudo felis rotate-token limbo` replaces a leaked
> token (the login gate restarts onto the new value; copy it to the mod by hand).

## Architecture

Each platform is an **independent** Gradle build with its own `settings.gradle`,
@@ -232,8 +248,10 @@ Velocity), then set `api-base-url` and `service-token` — or provide
precedence. The token is one of felis-api's per-caller internal tokens: the
Velocity proxy uses the `velocity` token (Secret `felis/felis-service-token`), the
login gate the `limbo` token (`felis-limbo-token`), and each serves only its own
routes (a token on another caller's route gets `403 wrong_caller`). Treat it as a
secret; `sudo felis rotate-token <caller>` replaces it.
routes (a token on another caller's route gets `403 wrong_caller`). A loader mod
takes the `limbo` token, on a standalone online-mode server only (see the warning
under the module table). Treat it as a secret; `sudo felis rotate-token <caller>`
replaces it.

On **Velocity**, also set `root-domain` (and optionally `lobby-server`) in the
same file to turn on §11 routing, and make sure `online-mode=true` in
+6 −0
Changes for plugins/fabric/src/main/java/best/lolicon/felis/fabric/FelisFabricMod.java: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import best.lolicon.felis.link.LinkCode;
import best.lolicon.felis.link.LinkConfig;
import best.lolicon.felis.link.LinkConfigLoader;
import best.lolicon.felis.link.LinkException;
import best.lolicon.felis.link.ModLinkPolicy;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -68,6 +69,11 @@ public final class FelisFabricMod implements DedicatedServerModInitializer {
                source.sendFailure(Component.literal("/link 只能由玩家执行 / /link can only be run by a player."));
                return 0;
            }
            if (!source.getServer().usesAuthentication()) {
                LOGGER.warn(ModLinkPolicy.OFFLINE_LOG);
                source.sendFailure(Component.literal(ModLinkPolicy.OFFLINE_REPLY));
                return 0;
            }
            requestAndReply(source.getServer(), player);
            return 1;
        }));
+6 −0
Changes for plugins/forge/src/main/java/best/lolicon/felis/forge/FelisForgeMod.java: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import best.lolicon.felis.link.LinkCode;
import best.lolicon.felis.link.LinkConfig;
import best.lolicon.felis.link.LinkConfigLoader;
import best.lolicon.felis.link.LinkException;
import best.lolicon.felis.link.ModLinkPolicy;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -73,6 +74,11 @@ public final class FelisForgeMod {
                source.sendFailure(Component.literal("/link 只能由玩家执行 / /link can only be run by a player."));
                return 0;
            }
            if (!source.getServer().usesAuthentication()) {
                LOGGER.warn(ModLinkPolicy.OFFLINE_LOG);
                source.sendFailure(Component.literal(ModLinkPolicy.OFFLINE_REPLY));
                return 0;
            }
            requestAndReply(source.getServer(), player);
            return 1;
        }));
+6 −0
Changes for plugins/neoforge/src/main/java/best/lolicon/felis/neoforge/FelisNeoForgeMod.java: 6 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import best.lolicon.felis.link.LinkCode;
import best.lolicon.felis.link.LinkConfig;
import best.lolicon.felis.link.LinkConfigLoader;
import best.lolicon.felis.link.LinkException;
import best.lolicon.felis.link.ModLinkPolicy;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
@@ -77,6 +78,11 @@ public final class FelisNeoForgeMod {
                source.sendFailure(Component.literal("/link 只能由玩家执行 / /link can only be run by a player."));
                return 0;
            }
            if (!source.getServer().usesAuthentication()) {
                LOGGER.warn(ModLinkPolicy.OFFLINE_LOG);
                source.sendFailure(Component.literal(ModLinkPolicy.OFFLINE_REPLY));
                return 0;
            }
            requestAndReply(source.getServer(), player);
            return 1;
        }));
+24 −0
Changes for plugins/shared/src/main/java/best/lolicon/felis/link/ModLinkPolicy.java: 24 added lines, 0 removed lines.
Original line number Diff line number Diff line
package best.lolicon.felis.link;

/**
 * ModLinkPolicy is what the Fabric, Forge and NeoForge mods say when they refuse
 * {@code /link}. A mod mints a link code for the UUID its server reports, and only an
 * online-mode server has checked that UUID with Mojang. Behind a proxy the backend runs
 * offline-mode and the proxy's own {@code /link} already serves every backend; on a
 * cracked server the UUID is whatever the client claims, so a code minted there would
 * let anyone link someone else's Minecraft account. The mods therefore link only on a
 * standalone online-mode server.
 */
public final class ModLinkPolicy {
    /** OFFLINE_REPLY is the chat line a player gets on an offline-mode server. */
    public static final String OFFLINE_REPLY =
            "此服务器未开启正版验证,不能在这里绑定 / This server runs with online-mode off, so /link is unavailable here.";

    /** OFFLINE_LOG is the server-log line for the same refusal. */
    public static final String OFFLINE_LOG =
            "Felis link: refused /link because online-mode is off. The mod links only on a standalone "
                    + "online-mode server; behind the Felis proxy, the proxy serves /link.";

    private ModLinkPolicy() {
    }
}