fix(mods): 加载器 mod 仅在正版验证的独立服务器上签发绑定码,README 标明只用 limbo token 及其风险
This commit is contained in:
5 files changed
+63
-3
No files matched your search
+21
-3
@@ -1,7 +1,8 @@
|
||||
# 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
|
||||
|
||||
@@ -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;
|
||||
}));
|
||||
|
||||
@@ -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;
|
||||
}));
|
||||
|
||||
@@ -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;
|
||||
}));
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
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() {
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user