feat(auth)!: go fully passwordless and fix cross-check review findings
Remove password authentication everywhere; the only session doors are passkey (WebAuthn), email OTP, in-game bind codes, QR scan-login, and op-login vouching. Remediates the 33-finding cross-check review across backend, CLI, panel, plugins, and docs. Backend/CLI: - Drop password routes and fields from account/user/onboard/auth handlers; align tests (new account subtests, naming reserves "console", op-login/onboard/qr-login test updates). - Add migrations 0016_op_login.sql and 0017_drop_password.sql. - Thread panel/admin hostnames from hostcfg through api.go, setup_panel.go, tui_root.go and tui_preflight.go instead of hardcoding; bootstrap.sh writes panel-hostname/admin-hostname into felis.toml. - Reword breakglass and TUI copy for passwordless flows. Panel: - Delete the ChangePassword page and all password UI; align login/auth/api/types with the passwordless contract; add the migration and op-login approval flows. - i18n: convert ImageBuildPage durations/status badges and ServerLuckPerms strings to translation keys; drop 72 orphan keys per locale; unify the title as "Felis - Console". Plugins (all six rebuilt): - Velocity waiting router returns 503 at_capacity during wake; MOTD/control-channel copy and config comments. - Paper zh menu title; Limbo bind-code TTL 600s with panel_url preference; unified /link lines in fabric/forge/neoforge; shared link-client javadoc contract fixes. Docs: openapi.yaml, sequence-diagrams.md, deploy/limbo/README.md and plugins/README.md aligned with the implementation. BREAKING CHANGE: migration 0017 irreversibly drops users.password_hash and users.must_change_password; password login cannot be restored after migrating.
This commit is contained in:
97 files changed
+1923
-1444
No files matched your search
@@ -74,7 +74,7 @@ public final class FelisNeoForgeMod {
|
||||
try {
|
||||
player = source.getPlayerOrException();
|
||||
} catch (CommandSyntaxException e) {
|
||||
source.sendFailure(Component.literal("/link can only be run by a player."));
|
||||
source.sendFailure(Component.literal("/link 只能由玩家执行 / /link can only be run by a player."));
|
||||
return 0;
|
||||
}
|
||||
requestAndReply(source.getServer(), player);
|
||||
@@ -84,18 +84,22 @@ public final class FelisNeoForgeMod {
|
||||
|
||||
private void requestAndReply(MinecraftServer server, ServerPlayer player) {
|
||||
UUID uuid = player.getUUID();
|
||||
player.sendSystemMessage(Component.literal("Requesting a link code…"));
|
||||
player.sendSystemMessage(Component.literal("正在获取绑定码… / Requesting a link code…"));
|
||||
io.submit(() -> {
|
||||
try {
|
||||
LinkCode code = linkClient.requestCode(uuid);
|
||||
server.execute(() -> player.sendSystemMessage(Component.literal(
|
||||
"Your link code: " + code.code()
|
||||
+ " — enter it on the web panel → Account (valid a few minutes).")));
|
||||
server.execute(() -> {
|
||||
player.sendSystemMessage(Component.literal(
|
||||
"绑定码 / Link code: " + code.code() + "(几分钟内有效 / valid a few minutes)"));
|
||||
player.sendSystemMessage(Component.literal(code.panelUrl() != null
|
||||
? "在此完成绑定 / Finish linking at: " + code.panelUrl()
|
||||
: "在网页控制台 → 账户 中输入 / Enter it on the web console → Account."));
|
||||
});
|
||||
} catch (LinkException e) {
|
||||
LOGGER.warn("link code request failed for {} (status={}, code={}): {}",
|
||||
uuid, e.statusCode(), e.errorCode(), e.getMessage());
|
||||
server.execute(() -> player.sendSystemMessage(Component.literal(
|
||||
"Couldn't get a link code right now. Please try again in a moment.")));
|
||||
"现在无法获取绑定码,请稍后再试 / Couldn't get a link code right now. Please try again in a moment.")));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user