Telegram is optional: a key you make up is the door - #31
Merged
Merged
Conversation
A deployment refused to finish setting up without ADMIN_BOT_TOKEN and OWNER_TELEGRAM_ID, and the web console could only be signed into with a pairing code that the Telegram console bot was the only thing able to issue. Between them, somebody with no Telegram account could not use their own copy of this at all — the first wall on the path a judge or a new owner walks, and one nothing on the product needs. There are two doors now and either one alone is a finished deployment. CONSOLE_KEY is a string the owner makes up, at least sixteen characters, and POST /admin/claim trades it for the same thirty day session the pairing code has always ended in. One place mints a token, so the two doors cannot drift in how long somebody stays signed in or in what is written down about them. The key is compared in constant time and never stored: only a hash of it, beside a hash of the token. Length is the whole of the rule, and there is no attempt limit, because sixteen characters is far past what can be guessed — a limit would defend against an attack nobody can mount while adding a number for the owner to wonder about. The setup page offers a generated key rather than leaving the owner to invent one. Changing the key takes it back. A session opened with a key remembers which key, and ends the moment that is no longer the key: without that, "change CONSOLE_KEY" stopped the next sign in and nothing else, and every browser already holding a token kept working — which is exactly the case a leaked key is changed for. A session paired from Telegram carries no such mark. It was the console bot that vouched for that person, not a setting. WEB_OWNER_ID is 0: a legal row in a table keyed by Telegram account id, and an account Telegram has never heard of. findOwner now excludes it, because both of its callers use what comes back as a chat id, and a deployment with both doors would otherwise have stopped alerting the moment the console row happened to be the older of the two. The deploy form asks for one box. It reads .dev.vars.example, and that file now lists CONSOLE_KEY and nothing else: a row of empty boxes at the first step reads as work to do before anything happens, and there is none. A console bot is added afterwards from the Worker's own settings, and the setup page says how. A short key stops a deployment only when it is the only door. Adding a weak one to a working Telegram console is trying something, not breaking something, and the page says it is set and not being used rather than taking the deployment down. The rest follows the same fact. The five READMEs ask for three things and offer Telegram as the extra; the deploy script decides on the record /health publishes rather than by matching words in a rendered page; the smoke test walks the door the form actually asks for, which nothing had ever exercised; the installer can set the key; and `muxel init` no longer makes --owner-telegram-id a required flag. Verified against a real Worker on an empty database, twice: a console key alone reaches "ready", the wrong key is refused, the right one mints a token, and the console API answers it. And live: sign in, change the key in the Worker's settings, and the same browser is refused while the new key works. 904 tests, the new ones each checked by putting the bug back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FMFyy3oXb9u2AxoYQKRXHu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A deployment refused to finish setting up without
ADMIN_BOT_TOKENandOWNER_TELEGRAM_ID, and the web console could only be signed into with a pairing code that the Telegram console bot was the only thing able to issue. Between them, somebody with no Telegram account could not use their own copy of this at all — the first wall on the path a judge or a new owner walks, and one nothing on the product needs.There are two doors now, and either one alone is a finished deployment.
The key
CONSOLE_KEYis a string the owner makes up, at least sixteen characters, andPOST /admin/claimtrades it for the same thirty-day session the pairing code has always ended in. One place mints a token, so the two doors cannot drift in how long somebody stays signed in or in what is written down about them. The key is compared in constant time and never stored — only a hash of it, beside a hash of the token.Length is the whole of the rule, and there is deliberately no attempt limit: sixteen characters is far past what can be guessed, so a limit would defend against an attack nobody can mount while adding a number for the owner to wonder about. The setup page offers a generated key rather than leaving the owner to invent one.
Changing the key takes it back
A session opened with a key remembers which key, and ends the moment that is no longer the key. Without it, "change
CONSOLE_KEY" stopped the next sign-in and nothing else — every browser already holding a token kept working, which is exactly the case a leaked key is changed for. A session paired from Telegram carries no such mark: it was the console bot that vouched for that person, not a setting.One box
The deploy form reads
.dev.vars.example, and that file now listsCONSOLE_KEYand nothing else. A row of empty boxes at the first step reads as work to do before anything happens, and there is none. A console bot is added afterwards from the Worker's own settings, and the setup page says how.Two things found on the way
WEB_OWNER_IDis0— a legal row in a table keyed by Telegram account id, and an account Telegram has never heard of.findOwnernow excludes it, because both of its callers use what comes back as a chat id, and a deployment with both doors would otherwise have stopped alerting the moment the console row happened to be the older of the two.The rest follows the same fact
The five READMEs ask for three things and offer Telegram as the extra;
scripts/deploy.mjsdecides on the record/healthpublishes rather than by matching words in a rendered page (a keyword heuristic that was already wrong);scripts/smoke.mjswalks the door the form actually asks for, which nothing had ever exercised; the installer can set the key; andmuxel initno longer makes--owner-telegram-ida required flag.Verified against a real Worker, not only in tests
On an empty database with a console key and no Telegram at all:
/health→awaiting_setup, the first screen → 200 "Your console is connected",/health→ready, wrong key → 401, right key → a token, console API with that token → 200, without it → 401.And live: sign in, change
CONSOLE_KEYin the Worker's settings, restart — the same browser is refused, the new key works, the old one is refused.904 tests; the new ones each checked by putting the bug back.
🤖 Generated with Claude Code
https://claude.ai/code/session_01FMFyy3oXb9u2AxoYQKRXHu