Repository navigation
feat: persisted logins, API keys, read-only role, TOML config file (WI-1741) - #115
Merged
Merged
Conversation
…741)
- Sessions (access and refresh tokens) are saved to sessions.json in the
credentials directory, hashed with SHA-256, so logins survive a restart.
Expired entries are dropped on load. An unreadable file signs everyone out
rather than refusing to start.
- API keys for automation, sent as `Authorization: Bearer rtb_...`. Stored
hashed in api-keys.json; the key is returned once, at creation. Managed by
admins through GET/POST /auth/api_keys and DELETE /auth/api_keys/{id}.
A corrupt keys file refuses to start, as credentials do.
- A read-only account, added with `rtbit auth set-read-only-user` (password on
stdin) and removed with `rtbit auth remove-read-only-user`. It may use only
GET, HEAD and OPTIONS; anything else gets 403. Works over Bearer and Basic.
Admin changes (`set_credentials`) keep it.
- The middleware resolves a role for every credential type and records it in
the request. Key management is admin-only.
- The qBittorrent compat login refuses the read-only account. Its sessions
carry no role, so allowing it would grant write access.
Verified against the built daemon: setup, read-only and admin access across
restarts, API key create/use/delete, refresh-token rotation, and that no raw
token or key is on disk.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Adds `--config PATH` (or RTBIT_CONFIG) for a TOML file of non-secret settings: http_api, network, limits, indexarr and logging. Precedence is command line, then environment, then file, then built-in default, so a flag or variable always overrides the file. - Unknown keys are errors, so a typo cannot be silently ignored. - Secrets are not accepted: the indexarr API key and passwords stay in the environment or the credentials store. - `rtbit config dump` prints the merged settings as TOML. Secrets are never included, so the output is safe to share. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…te (WI-1741) - A session is bound to the credential it was issued under (a fingerprint of the admin username and password hash, plus the read-only account for its sessions). Changing the admin password, through the UI or `rtbit auth reset-password`, ends every session. Removing or changing the read-only account ends its sessions at once. Checked on every request and on refresh. - Refresh cannot extend a login past 30 days from its first sign-in. Access and refresh tokens are both capped at that point. - Credentials are read from credentials.json on every check, and every change is applied to the file under a lock starting from what is on disk. A server no longer holds a stale copy: an account added by `rtbit auth` is seen without a restart, a removed account cannot come back when the admin password is saved, and an admin save keeps accounts added by another process. - `reset-password` keeps the read-only account when the existing file can be read. A corrupt file cannot be preserved, and that is reported. - The read-only login compares the username by SHA-256 digest and always verifies a password (against a dummy hash when there is no account), so the work done does not depend on whether the account exists or the username matched. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
…-1741) /auth/logout was behind the role gate, which refuses every POST from a read-only caller, so a read-only session could not be ended and its refresh token stayed usable. Logout now needs no session, like login and refresh: it only revokes the refresh token it is sent. This also lets a caller whose access token has expired log out. `rtbit auth set-read-only-user` and `remove-read-only-user` used CredentialStore::load, which before first-run setup made a new setup token and wrote it over the running server's setup-token file, so setup with that file's token was refused. They now use CredentialStore::open, which never touches the setup token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
WI-1741 (RT-WP12): accounts and config.
What this adds
Auth model (commits b67bafb, f208255, b754ff9)
sessions.json(stored as SHA-256 hashes, 0600). Each session is bound to the credential it was issued under, so a password change, artbit auth reset-password, or removing the read-only account ends it straight away, including on a running daemon. A login lasts at most 30 days, however often it is refreshed.Authorization: Bearer rtb_…):GET/POST /auth/api_keysandDELETE /auth/api_keys/{id}. Admin only. Keys are stored hashed and default to the read-only role. They do not depend on the admin password.rtbit auth set-read-only-user -u NAME(password read from stdin) andrtbit auth remove-read-only-user. A read-only caller can use only GET, HEAD and OPTIONS, and is refused at the WebUI API v2 compat login.reset-passwordand admin credential changes keep the read-only account. Its username is compared in constant time.Config file (commit bafc4f4)
--config FILE/RTBIT_CONFIGtakes a TOML file of non-secret settings. Unknown keys are errors. The command line and environment win over the file.rtbit config dumpprints the effective settings. Secrets are never included.Review fixes in b754ff9
/auth/logoutneeds no session, like login and refresh. It used to sit behind the role gate, so a read-only caller got 403 and its refresh token stayed usable.rtbit authread-only commands open the credentials withCredentialStore::open, which never touches the setup token. Before, running them before first-run setup replaced the server's setup-token file, and setup with that token was refused.Verification (at b754ff9)
cargo test -p swarmforge --features http-api: 200 passed, 5 ignoredcargo test -p rtbit: 19 passedcargo clippy --workspace --exclude rtbit-desktop --no-default-features --features default-tls -- -D warnings: cleancargo fmt --check: cleanrtbitbinary on loopback, with isolated data dirs: all checks pass. It covers setup-token integrity, read-only login/read/write-refusal/logout, API keys, persistence across a restart, CLI removal and reset on a running daemon, change_credentials, and config precedence and dump.Not covered: the Docker image, reverse proxy and desktop builds. The desktop build gets persisted sessions but leaves API keys off.
Not in this PR
🤖 Generated with Claude Code