Repository navigation
Releases
WelcomeWagon 0.6.1
Two small fixes found by Leaf Juice's checks against 0.6.0.
- Signing a player out everywhere now reports how many live sessions it ended, the same number
session listshowed. It still deletes their expired session files too. Before, the two could disagree, for example "signed in on 1 browser" followed by "signed out of 2". - The README named the old short command. It's
/ww.
Installing
Drop the jar in over 0.6.0. Nothing to rename or move.
Tested
Unit and HTTP tests pass, including a new test for the sign-out count. Not tried on a live server.
WelcomeWagon 0.6.0
A new name (D197): WelcomeWagon, the neighbors who roll up to greet newcomers. How it works is unchanged. As the owner asked (D196), it keeps no old names.
Installing over the previous version
With the server stopped:
- Rename its plugin folder to
plugins/WelcomeWagon. Invites, sessions and settings are inside. - In LuckPerms, move its permissions to the matching
welcomewagon.*nodes. - Use
/welcomewagon(short form/ww) for admin commands. Players still type/login. - Install the matching Sheriff, BlueMapAuth and Waystation releases, and Leaf Juice's update, at the same time. They find WelcomeWagon by its new name.
Browsers that were signed in sign in once more, because the session cookie has a new name.
Tested
Unit and HTTP tests pass. The rename was checked with the other plugins on a throwaway server.
Latchkey 0.5.1
The in-game command for a sign-in link is now /login.
Changed
/loginreplaces/signinin game (the owner's choice, 2026-11-14). The page's hints and messages say/logintoo. The web page's own address for signing in is still/signin, and the link a player clicks hasn't changed.- The permission keeps its name,
latchkey.signin, so existing grants keep working.
Upgrading
Replace the jar and restart. Tell players to type /login from now on. /signin no longer exists.
Tested
265 unit and HTTP tests pass, including that the page says /login. The bot test now types /login, but it wasn't rerun for this release.
Latchkey 0.5.0
The join page gets its own switches, can live on a host or under a path, and invites become links and tickets (D187).
Changes
- Three switches.
landing.enabledturns the page on.invites.enabledlets players use invite codes, andsessions.enabledlets them sign a browser in. Each is off until set, and the page only offers what's on. With invites off, admins can't make invites, so no code goes out that can't work. With sign-in off, a used invite still puts the player on the whitelist but signs no browser in, and/signingives no link. - A join page on its own host, or under a path.
landing.public-urlcan behttps://join.example.orgorhttps://example.org/join, with up to three lowercase path parts. Under a path, Latchkey answers only that path, and its cookies stay on it. - Invite links. An invite link carries the code after
#, so it never reaches a web log. Opening it fills the code in, and the player still presses Continue. In game,invite createnow also shows the admin that link. - Tickets for Leaf Juice. While invites can be used,
invite create --jsonadds aticketwithserver,join,link(join+#{code}) andexpires. The code stays in theonce/file as before, so the console never sees it. - The map is unchanged. It still goes through Mapkeeper's hand-off.
Upgrading
Replace the jar. Invites and sign-in are off after the upgrade until you add enabled: true under invites: and sessions: in plugins/Latchkey/config.yml, then run /latchkey reload. /latchkey status names each one that's off.
To move the page to a join host:
- Point the new name at Latchkey in your proxy.
- Set
landing.public-urlto the new address. - Reload.
Tested
264 unit and HTTP tests pass, 24 of them new:
- each switch on its own, off by default, and that a switch can't open a part another check stops;
- the page under a path, including a whole invite under
/joinand its cookie path; - the code-from-link script, allowed by hash;
- the ticket in the JSON answer, never carrying the code.
Not tried yet: a real proxy at a join host or a path, a real browser opening an invite link, or Leaf Juice printing a ticket.
Latchkey 0.4.0
The invite page becomes one box, and a player who uses their invite gets a welcome page with the address to join.
Changes
- Code only. The page asks for the invite code alone. A code that matches an open invite shows "This invite is for " and uses nothing up; "Yes, that's me" uses it, puts the player on the whitelist and signs that browser in. No Microsoft sign-in, ever: the server checks the account the first time they join. (Owner's choices, 2026-11-10.)
- The welcome view. A signed-in browser sees the server's logo and name, the address to join (with a copy button), and first steps. All of it is set under
page:inconfig.yml. The address is never in a page anyone can open: only in this view, served withCache-Control: no-store. - A logo, read only from
plugins/Latchkey/, PNG or WebP by its own bytes, at most 512 KB. - HTTPS with Caddy. docs/https-with-caddy.md explains putting Caddy in front of a playit HTTPS tunnel, and the trust boundary that keeps per-visitor rate limits working.
Upgrading
Replace the jar and restart. config.yml gains a page: section; until you fill it in, the page shows "Join the server" and two general first steps. Anything that read the old two-field form (code and username) must send the code alone and then confirm.
Tested
204 unit and HTTP tests, 11 new: the play address is absent from every answer to a browser that isn't signed in (the code page, the "This invite is for…" page, errors, 404s, wrong methods, sign-out, the logo) and present after the invite is used; looking at an invite uses nothing up; eight browsers racing one confirm get one admission; the logo checks. The bot test with Usher 0.4.1 passed 45/45 on Paper 26.1.2. Not tried yet: HTTPS through playit and Caddy, a real browser, a real client.
Also in 0.4.0
- Open the map. A signed-in browser can be handed to the map once, with a one-time link that works for a minute. The map checks the whitelist and bans when it takes the hand-off and again while it's open. It's for Mapkeeper.
- The playit preset.
/latchkey tunnelprints the tunnel settings, anddocs/has a ready Caddyfile matched to the tunnel's ports, with the map host. - A health check from outside, and the landing page's own paths are reserved.
- An internal failure gets the plain error page.
- Rewild is told what Latchkey owns, so it's never rewilded.
Tested on a copy of a real server
On an APFS copy of a real server (2026-11-14), on Paper 26.2 and then 26.3 build 249, with bots: the plugin loads and its checks pass. On 26.3 the bots can't walk (ViaVersion clients are refused for moving), so checks that need walking ran on 26.2 only.
Latchkey 0.3.0
The lobby: where arriving players start, with a welcome for first-timers and events other plugins can use. Works with or without Multiverse or Waystation.
Needs
- Paper 26.1 or later and Java 25.
- Everything 0.2.0 needed for invites and sign-in. The lobby needs only a loaded world.
New in 0.3.0
- The lobby. Set
lobby.world(and optionallylobby.spawn) and arriving players start there.lobby.sendisfirst-joinby default, oralwaysornever. First-timers get a title and chat lines fromlobby.welcome. Who is new comes from the server's own record, so nothing more about players is stored. If the world isn't loaded, nobody is sent anywhere and the console says how to fix it. These defaults are the owner's decision of 2026-11-10. - For other plugins.
FirstJoinEvent,PlayerArrivedEventon every join, andlobbyLocation(), read by name with no dependency. Waystation 0.5.0 uses them for its lobby gate. - Lists in pages.
/latchkey invite list --jsonanswers{"items": [...], "next": ...}, the shared Signalbox format, withlimitandcursor. Signalbox 0.3.0 is inside the jar. describemarks optional arguments.
Upgrading from 0.2.0
Replace the jar and restart. The lobby stays off until you set lobby.world, so nothing changes until you do. Leaf Juice or scripts that read invite list --json should read items instead of invites.
Tested
193 unit and HTTP tests. The bot test passes 44/44 on throwaway Paper 26.1.2 and 26.3 servers with Usher 0.4.1: a first join sent to the lobby spot and welcomed, a returning player left where they were, and a profile made unsafe after its invite refused at use. Waystation's arrival suite used this jar for its lobby gate, 29/29 on 26.3.
Not tried: a real game client (the lobby title can't be seen by a bot), HTTPS through a real tunnel, or a real server.
Latchkey 0.2.0
Invites, a landing page and browser sign-in for whitelisted Paper servers. A player gets a six-character code, types it on your page with their username, and they're on the whitelist.
Needs
- Paper 26.1 or later and Java 25.
online-mode=trueand the whitelist on. Latchkey refuses invites and sign-in otherwise.- An HTTPS address in front of the page: a tunnel or a proxy. The page listens on 127.0.0.1 and refuses to run without one.
- Optional: Usher, which checks and applies the profiles named on an invite.
New in 0.2.0
- Invites.
/latchkey invite create <player> [profiles] [lifetime]makes a single-use code for one username, lasting 14 days by default and 30 at most. Only a salted hash is stored. In game the code goes privately to the admin; on the console it goes to an owner-only file, never the log. - The landing page. One form, which works without JavaScript and with a keyboard and screen reader. Form tokens, refusal of posts from other sites, rate limits, the same answer for every kind of wrong code, fixed security headers.
- Browser sessions, kept by Latchkey.
/signinlinks now sign a browser in on Latchkey's own page. A session lasts a day by default and 30 at most, and is kept open a day at a time while the player is actually playing, at most 7 days in a row. Taking a player off the whitelist, banning them or turning the whitelist off ends their sessions. - Safe setup or no setup. Unsafe settings switch off only the part they affect, with one console line saying how to fix it. There's no override.
- Commands are the API.
/latchkeycommands answer people in plain words, and tools with one machine-readable line when given--json <id>(the Signalbox format)./latchkey describelists them. - Events for other plugins:
InviteCheckEventwhen an invite names profiles,InviteRedeemedEventwhen one is used.
Upgrading from 0.1.0
sign-in-pagestill works while the landing page is off, so a server that serves the page elsewhere carries on as before. Once the landing page is on, links go to it instead.latchkey.signinis still op-only by default. To let players sign in, grant it:lp group default permission set latchkey.signin true.- New permissions for the commands are op-only by default. See the README.
Tested, and not
185 unit and HTTP tests pass. A bot test with Usher passed 38/38 on throwaway Paper 26.1.2, 26.2 and 26.3 servers. It covers the safe-setup refusal, Usher's checks, redeeming on the page, codes never in the log, sign-in to a session file, activity keeping a session open, and whitelist removal, bans and whitelist-off ending sessions. Bots can't join an online-mode server, so those runs used -Dlatchkey.allowOfflineForTesting=true, for throwaway servers only.
Not tested yet: HTTPS through a real tunnel, a real browser, a real game client, or a real server. On 26.2 and 26.3 the bots can't walk, so "playing" was shown there by interaction only.
MIT licensed.
Latchkey 0.1.0
The first release. A player types /signin and gets a one-time link, sent privately in chat, that signs their browser in to a web page. Being on the server proves who they are, so there's no password.
Needs
- Paper 26.1 or later. Paper 1.21.11 and Spigot aren't supported.
- Java 25.
online-mode=true. Latchkey refuses to make links with it off, so a server behind a proxy isn't supported yet.- A page that reads the links. Latchkey doesn't serve one itself. Leaf Juice does.
Install
- Put
Latchkey-0.1.0.jarinplugins/and start the server once. - Set the page's address in
plugins/Latchkey/config.yml. It has to start withhttps://:sign-in-page: "https://example.com"
- Restart the server.
/signinneeds thelatchkey.signinpermission, which ops have by default, and the player must be on the allowlist.
How it behaves
- A link works once and lasts two minutes. Asking again cancels the last one.
- Only a hash of the secret is written to disk, in
plugins/Latchkey/pending/. The secret comes after a#in the link, so a browser never sends it in a web request. - The link goes to whoever typed the command, so
/execute as <player> run signincan't make one for someone else. - Links left waiting are cleared when the server starts and stops.
Tested, and not
Unit tests cover how links are made and stored. Leaf Juice's real sign-in test ran this plugin on throwaway Paper 26.1.2, 26.2 and 26.3 servers with bots. It checked the permission, the allowlist, single use, that the secret stays out of the console and log, the execute as cases, and cleanup on stop.
Bots can't join an online-mode server, so those runs used -Dlatchkey.allowOfflineForTesting=true. That flag is for throwaway servers only.
Not tested yet: a real game client clicking a link, a real server, LuckPerms granting the permission (the tests used op), and Bedrock players through Geyser, who may not be able to click a chat link.
MIT licensed.