feat(nano): give a Mojang player's name back to them, by prefixing the squatter
A premium player and a third-party player sharing a username could not both be online. Whichever logged in second was kicked with "You are already connected to this proxy!" -- even though the UUID rewrite had already made them two distinct players on the backend. Velocity's player registry is keyed on the NAME (lowercased), not the UUID, so two identities holding one name are one player as far as the proxy is concerned, and the reclaim invariant the rewrite buys is invisible to it. The fix needs no plugin and no state, because Velocity honours the name in the hasJoined RESPONSE rather than pinning the one the client sent at login-start -- established by a real login, not by reading the source. So the multiplexer hands back a different name and the collision is simply gone. A third-party player whose name belongs to a Mojang account now joins as PREFIX_name (LS_steve). Everyone else keeps their own name: the rename fires only on an actual collision, decided by asking api.mojang.com whether the name is registered. The name's owner is never the one renamed, which is 正版优先 falling out for free -- the identity source is never rewritten, so there is no policy to encode and no 30-day hold to track. The premium-name answer is cached asymmetrically, because the two directions have very different costs. "Taken" is nearly permanent (Mojang does not recycle names) and is trusted for a day; "free" can stop being true the moment someone buys that name, and a stale "free" leaves a squatter holding a name its real owner has just bought, so it is trusted for ten minutes. A lookup that fails with nothing cached fails CLOSED -- assume premium, rename the third-party player: a Mojang outage must not become an opportunity to hold someone else's name, and being wrong that way costs a cosmetic prefix while being wrong the other way bounces the name's owner off the proxy. The lookup gets its own 2s client rather than sharing the 5s auth client, since it is a SECOND Mojang round-trip on a login that already spent one. prefix is a required, unique, 1-4 character config field rather than something derived from the tag, because it is player-visible and no derivation can know that "littleskin" is meant to read LS. Two sources sharing a prefix would rewrite their same-named players onto one name, so uniqueness is enforced case-insensitively -- the proxy folds case, and LS/ls would collide there while reading as distinct here. Also close a pre-existing hole on the path this touches: a third-party source's profile name was relayed verbatim, so a hostile or sloppy Yggdrasil root could put "§4admin", an empty string, or 200 characters straight into the proxy's player list. The name is now checked against the Minecraft username charset and a bad one is a 204, the same way a bad UUID already was. Verified end to end on the deploy host (Velocity 3.5.1 + Paper 26.2), both branches: premium FLYEMOJ1 -> 195fadbd-f72e-4b9b-9f8f-f92586fe16ad, name unchanged LittleSkin FLYEMOJ1 -> LS_FLYEMOJ1, f1b7b6ae-f250-348a-b069-a2ec0fcae668 both online at once, zero "already connected" rejections LittleSkin FelisNyaTest01 -> joins as FelisNyaTest01, no prefix, UUID still v3 The last line is the one that matters: an ordinary third-party player collides with nobody and keeps their name, while the rewrite that keeps identities apart still ran. Paper's "LS_FLYEMOJ1 (formerly known as li_FLYEMOJ1) joined the game" is the other half of it -- the rename moved the player's display name and their playerdata came along untouched, because every server-side key is the UUID and the UUID does not depend on the name. Known ceiling, left alone deliberately: two players of one source whose names agree on their first 16-len(prefix)-1 characters truncate onto the same in-game name, and a prefixed name may itself happen to be a premium name. Both cost an "already connected" bounce, not an identity -- the UUID rewrite does not depend on the name at all. BREAKING CHANGE: every [[auth_source]] now requires prefix = "XX" (1-4 letters or digits, unique across sources). An existing nano felis.toml without it fails to load with an error naming the field, rather than silently keeping the collision.
This commit is contained in:
6 files changed
+370
-16
No files matched your search
@@ -1178,8 +1178,15 @@ write_nano_config() {
|
||||
# Add each third-party Yggdrasil root below (priority = order). url is the FULL
|
||||
# hasJoined endpoint. After editing: sudo systemctl restart felis-nano
|
||||
#
|
||||
# prefix is required, 1-4 letters/digits, unique per source. A player of this source
|
||||
# whose name belongs to a Mojang account joins as PREFIX_name (LS_steve) instead —
|
||||
# otherwise the proxy, which keys its player list on the NAME, refuses to have both
|
||||
# online at once ("You are already connected to this proxy!"). Everyone else keeps
|
||||
# their own name.
|
||||
#
|
||||
# [[auth_source]]
|
||||
# tag = "littleskin"
|
||||
# prefix = "LS"
|
||||
# url = "https://littleskin.cn/api/yggdrasil/sessionserver/session/minecraft/hasJoined"
|
||||
EOF
|
||||
chmod 0644 "$target"
|
||||
|
||||
Reference in new issue
Block a user