Repository navigation
v1.2.0
Client addresses on /stats, and a link for every door
Two additions an operator running more than one entry path has been missing, plus release pages that finally say what changed.
Per-user client addresses
GET /stats can now report where a user's connections are coming from:
"alice": {
"connections": 2,
"connected_ips": ["198.51.100.7", "203.0.113.44"],
"last_ip": "203.0.113.44"
}connected_ips is the set of distinct addresses holding a live connection right now — sorted, deduplicated, and derived from the connection registry rather than counted separately, so it cannot drift from the connections gauge beside it. last_ip is the most recent admitted connection's address, and outlives that connection.
This is off by default, and turning it on is a decision worth making deliberately. This is a circumvention proxy: the people using it are frequently the reason it exists, and an operator's answer to "who connected from where" is also the answer available to anyone who ends up with the server. connected_ips adds no retention — those addresses are already held for the life of the connection and go with it — but last_ip outlives its connection, so a deployment that never asks accumulates nothing. Neither is written to disk in any form: usage-state-file carries quota counters alone, so no address survives a restart.
Enable it with track-client-ips = true. Behind a front proxy both fields report what the PROXY header carried, which is the client's real address — that is what makes them useful for a WEB deployment, where every connection otherwise arrives from 127.0.0.1.
New client-ips capability in the features array, so a panel can offer the switch without probing (the fields' absence is indistinguishable from an idle secret).
A link for every listener
mtg-proxy access described one door. It printed the ee secret against bind-to's port — precisely the form a client arriving on an obfuscated2 socket will not accept — so an operator who configured a [[listener]] had nothing to hand a user.
Each listener now gets its own block: that socket's port, and per user, per accepted wire form, a tg:// and t.me link with QR codes. The secret in each is the user's own sixteen key bytes spelled the way that socket expects, so handing someone a dd link does not create a second account — their quota bucket, counters and limits are the ones they already had. A loopback listener gets no links and says why in words, because that is what a WEB relay backend is supposed to look like.
Release notes
Every tag on this project is cut with a written account of what changed, and until now none of it reached anyone: the release step asked GitHub to generate notes, and GitHub's generated notes are a bare compare link when a release has no merged pull requests behind it — which is every release here. Four release pages said nothing but "Full Changelog".
The tag annotation is now read over the API and prepended to the generated notes. v1.1.0 through v1.1.3 have been backfilled by hand.
Testing
The plain wire form finally has a row in the shared entry cases, so every governance rule built on them — quota billing, expiry, disable, revocation, throttling — is now asserted on all three forms rather than two. It already held; nothing had asked.
New tests cover what the counters do when connections overlap: exact per-user attribution across users with deliberately uneven counts, one secret arriving through both doors counting into one bucket, and the connection registry draining completely once every stream ends, with a stats scraper running against live traffic throughout so the snapshot's locking is exercised under -race rather than against a quiet proxy.
A comment claiming CI runs the browser harness as its own job has been corrected. It never has — no workflow installs Node or a browser, so that test skips in CI every time and the job stays green. The false claim was worse than the gap: it is why the accept-key defect fixed in v1.1.2 was hunted through every layer except the one that had never actually executed.
Upgrading
Additive. No config key renamed or removed, no release asset renamed, default accept-modes still ["ee"], and track-client-ips defaults to off — so a deployment that changes nothing behaves exactly as it did on v1.1.3, and its /stats document gains one entry in features and nothing else.
Full Changelog: v1.1.3...v1.2.0