From bee14adc2d649988ef812307f4ace450e4d2551f Mon Sep 17 00:00:00 2001 From: Brandon Black Date: Sun, 18 Oct 2026 19:44:09 -0700 Subject: [PATCH] rpc: say to delete a token wider than 0600 chmod keeps a secret that may already have been read. The node mints a new token only when the file is gone. Co-authored-by: Cursor --- changelog.d/rpc-token-wide-file.md | 5 +++++ crates/rbitcoin-node/src/cli.rs | 2 +- crates/rbitcoin-rpc/src/auth.rs | 3 ++- docs/operator/interfaces.md | 4 +++- docs/operator/operations.md | 2 +- docs/rpc.md | 2 +- 6 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 changelog.d/rpc-token-wide-file.md diff --git a/changelog.d/rpc-token-wide-file.md b/changelog.d/rpc-token-wide-file.md new file mode 100644 index 0000000000..b4489a3082 --- /dev/null +++ b/changelog.d/rpc-token-wide-file.md @@ -0,0 +1,5 @@ +Changed + +- A Unix `{datadir}/rpc.token` with group or world bits still refuses startup. + Delete that file and start again. The node mints a new token only when the + file is gone. chmod to 0600 keeps the secret that was already readable. diff --git a/crates/rbitcoin-node/src/cli.rs b/crates/rbitcoin-node/src/cli.rs index 089876ab6e..d1463e11ef 100644 --- a/crates/rbitcoin-node/src/cli.rs +++ b/crates/rbitcoin-node/src/cli.rs @@ -374,7 +374,7 @@ SV2: --sv2-tp-listen ADDR serves the Stratum v2 Template Distribution Protocol ( --sv2-tp-stale-grace SECS keeps a replaced tip's templates answering for SECS, at most 86400 (default 10).\n\ --sv2-tp-fee-delta SATS pushes a same-tip template once its fees gain SATS over the last one sent (default 1000).\n\ --sv2-tp-template-interval SECS checks for that gain every SECS, 1 to 86400 (default 5).\n\ -RPC: --rpc unix socket {{datadir}}/rpc.sock; --rpc-listen [ADDR] adds TCP (default 127.0.0.1 and Core-matching port). Token {{datadir}}/rpc.token (Bearer), created mode 0600; an existing token must be owner-only on Unix (Windows has no mode bits). --rpc-cookie-file opts TCP into Core cookie HTTP Basic. --rpc-cookie-perms owner|group|all (default owner) is the widest Unix mode that file may have (owner 0600, group 0640, all 0644); the node never creates or chmods it. Windows has no mode bits. No --rpcuser. --rest turns on unauthenticated /rest/ on those listeners (off unless set).\n\ +RPC: --rpc unix socket {{datadir}}/rpc.sock; --rpc-listen [ADDR] adds TCP (default 127.0.0.1 and Core-matching port). Token {{datadir}}/rpc.token (Bearer), created mode 0600; an existing token must be owner-only on Unix. Delete a wider file and start again so the node mints a new token (Windows has no mode bits). --rpc-cookie-file opts TCP into Core cookie HTTP Basic. --rpc-cookie-perms owner|group|all (default owner) is the widest Unix mode that file may have (owner 0600, group 0640, all 0644); the node never creates or chmods it. Windows has no mode bits. No --rpcuser. --rest turns on unauthenticated /rest/ on those listeners (off unless set).\n\ Cold files: --datadir-cold PATH puts append-only IBD files under PATH/store\n\ (seqsigwit, txstat, input, and blockfilter / sp_tweaks once enabled).\n\ Default (flag omitted): those files live under --datadir. --prune-seqsigwit\n\ diff --git a/crates/rbitcoin-rpc/src/auth.rs b/crates/rbitcoin-rpc/src/auth.rs index 3189c2f87b..8e32fd4acd 100644 --- a/crates/rbitcoin-rpc/src/auth.rs +++ b/crates/rbitcoin-rpc/src/auth.rs @@ -188,7 +188,7 @@ pub fn read_token_file(path: &Path) -> Result { & 0o777; if mode & 0o077 != 0 { return Err(format!( - "RPC token {}: mode {mode:o} is wider than 0600", + "RPC token {}: mode {mode:o} is wider than 0600. Delete the file and start again so the node mints a new token. chmod 0600 would keep this secret, and it may already have been readable", path.display() )); } @@ -399,6 +399,7 @@ mod tests { fs::set_permissions(&path, fs::Permissions::from_mode(0o644)).unwrap(); let err = read_token_file(&path).unwrap_err(); assert!(err.contains("0600"), "{err}"); + assert!(err.contains("Delete the file"), "{err}"); fs::set_permissions(&path, fs::Permissions::from_mode(0o640)).unwrap(); assert!(read_token_file(&path).is_err()); fs::set_permissions(&path, fs::Permissions::from_mode(0o600)).unwrap(); diff --git a/docs/operator/interfaces.md b/docs/operator/interfaces.md index e814c34d06..85120c6533 100644 --- a/docs/operator/interfaces.md +++ b/docs/operator/interfaces.md @@ -340,7 +340,9 @@ Optional HTTP JSON-RPC subset (default **off**). `--rpc` binds client in rbitcoin's group can connect without traversing the `0700` datadir. `--rpc-listen` adds TCP on `127.0.0.1:` when ADDR is omitted (mainnet 8332, testnet 18332, signet 38332, regtest 18443). TCP auth is -`Authorization: Bearer` from `{datadir}/rpc.token` (0600), plus optional Core +`Authorization: Bearer` from `{datadir}/rpc.token` (0600). Group or world +bits refuse startup. Delete that file and start again so the node mints a +new token. chmod 0600 keeps the same secret. Plus optional Core cookie HTTP Basic from `--rpc-cookie-file PATH`. The same listeners serve Core REST when `--rest` is set: `GET /rest/chaininfo.json`, block, headers, tx, mempool, `getutxos`, `deploymentinfo`, and `blockfilter/basic` for heights diff --git a/docs/operator/operations.md b/docs/operator/operations.md index e9b0d6432b..aeeedb9815 100644 --- a/docs/operator/operations.md +++ b/docs/operator/operations.md @@ -108,7 +108,7 @@ Clean smoke: | `--rpc` | `rpc=` | **off** — unix JSON-RPC `{datadir}/rpc.sock` (mode 0600) | | `--rpc-listen [ADDR]` | `rpc_listen=` | disabled — implies `--rpc`; omit ADDR → `127.0.0.1` and Core-matching RPC port | | `--rest` | `rest=` | **off** — unauthenticated `/rest/` on the RPC listener. Own queue. Needs `--rpc` or `--rpc-listen` | -| `--rpc-token-file PATH` | `rpc_token_file=` | `{datadir}/rpc.token` (CSPRNG hex; TCP Bearer). Created mode 0600. An existing file must stay owner-only on Unix. Windows has no mode bits | +| `--rpc-token-file PATH` | `rpc_token_file=` | `{datadir}/rpc.token` (CSPRNG hex; TCP Bearer). Created mode 0600. An existing file must stay owner-only on Unix. Delete a wider file and start again. A new token is minted only when the file is gone. chmod 0600 keeps a secret that may already have been readable. Windows has no mode bits | | `--rpc-cookie-file PATH` | `rpc_cookie_file=` | disabled — existing Core `username:password` cookie (no trailing newline) enables TCP HTTP Basic alongside Bearer | | `--rpc-cookie-perms owner\|group\|all` | `rpc_cookie_perms=` | **owner** — Unix mode ceiling. `group` is at most 0640. `all` is at most 0644. Windows ignores the flag. The node does not chmod the file. NixOS `services.rbitcoin.rpc.cookiePerms` | | `--rpc-work-queue N` | `rpc_work_queue=` | **16** in-flight HTTP RPC (Core `-rpcworkqueue`). One POST is one slot (array batches still run). Full permit is HTTP **503** `Work queue depth exceeded`. **0** is the default queue of 16. | diff --git a/docs/rpc.md b/docs/rpc.md index fd454858b2..b9eba324fd 100644 --- a/docs/rpc.md +++ b/docs/rpc.md @@ -50,7 +50,7 @@ later Core RPC is present, including descriptor-wallet calls from 0.21 | `--rpc` / conf `rpc=` | **off** | Unix JSON-RPC `{datadir}/rpc.sock` (mode 0600; filesystem auth) | | `--rpc-socket PATH` / conf `rpc_socket=` | **off** | Bind the unix socket at PATH (mode **0660**, group may connect) instead of `{datadir}/rpc.sock`. Implies `--rpc`. For a client running as another user, such as mempool's Node. | | `--rpc-listen [ADDR]` / conf `rpc_listen=` | **off** | TCP JSON-RPC; omit ADDR → `127.0.0.1` and Core-matching port (8332 / 18332 / 38332 / 18443). Implies `--rpc`. | -| `--rpc-token-file PATH` | `{datadir}/rpc.token` | CSPRNG hex token; TCP `Authorization: Bearer`. Created mode 0600. An existing file must be owner-only on Unix (group or world bits refuse startup). The node does not chmod it. Windows has no mode bits | +| `--rpc-token-file PATH` | `{datadir}/rpc.token` | CSPRNG hex token; TCP `Authorization: Bearer`. Created mode 0600. An existing file must be owner-only on Unix (group or world bits refuse startup). The node does not chmod it. Delete a wider file and start again: a new token is minted only when the file is gone. chmod 0600 keeps a secret that may already have been readable. Windows has no mode bits | | `--rpc-cookie-file PATH` / conf `rpc_cookie_file=` | **off** | Existing Core-format `username:password` file (no trailing newline) accepted as TCP HTTP Basic in addition to Bearer; it is never created or logged | | `--rpc-cookie-perms owner\|group\|all` / conf `rpc_cookie_perms=` | **owner** | Widest Unix mode the cookie file may have. `owner` is 0600. `group` is at most 0640 (group read; group write refuses startup). `all` is at most 0644. The node never chmods the file. Windows has no mode bits, so the flag is ignored there. NixOS `services.rbitcoin.rpc.cookiePerms` (default unset, so the unit argv omits the flag) | | `--sh-index` | **off** | Class B scripthash for Electrum/Esplora address history. RPC by height/hash/txid does not need it |