aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-02 11:54:22 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-02 11:54:22 +0200
commit2d8c6bc449e343a80569e45d4ceae0423616cedd (patch)
tree09a1ee29c2a39db6189ba80315cfa0a1c463bcf3 /docs
parentbee5901f7a04d17c40e2c8d077437f10e59c8d81 (diff)
downloadmeshbay-2d8c6bc449e343a80569e45d4ceae0423616cedd.tar.gz
fix(hub): a desktop solve reports no hostname at all, not "meshbay"
Registering from the native client failed with `captcha_failed` while the checkbox was green — a worse symptom than the one being fixed, because the widget now looked fine and only the hub's own log said otherwise: captcha solved on an unexpected host ''; allowed: ['localhost', 'meshbay', 'meshbay.org'] The previous commit assumed Google would report the host component of the origin, so `app://meshbay` would come back as `meshbay` and could sit in `allowed_hosts`. It does not. A solve Google cannot attribute to a domain reports an **empty** hostname, and no allowlist entry can match that. An empty entry is not the answer either: a blank in a TOML list is a typo far more often than an intention, and `load_config` drops blanks for that reason — `captcha.allow_unattributed_host` is a named flag instead, so the trade is stated where it is made. What it admits, plainly: every non-web client, not only ours. A file:// page or somebody else's Electron application look identical from here. That is the same bar the client's own origin would have been — main.js already records that `app://meshbay` is not a credential — and it is a bar: the captcha still has to be solved, per token, in something that can render it. What is given up is the origin restriction for non-web clients, not the captcha. Off by default, and a hub without the desktop client should leave it off. The refusal now names which of the two it is, since they need different answers: an unexpected host names the host, an unattributed one says to set the flag. docs/captcha.md §6 said `meshbay` was the value and told operators to add it; it now records what was measured and why the guess was wrong. The packaged example config carries the flag with the same warning. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014UtzVrzM7e2tG9fSpkR9ML
Diffstat (limited to 'docs')
-rw-r--r--docs/captcha.md59
1 files changed, 41 insertions, 18 deletions
diff --git a/docs/captcha.md b/docs/captcha.md
index 84dadc4..4054e9f 100644
--- a/docs/captcha.md
+++ b/docs/captcha.md
@@ -415,7 +415,9 @@ solutions" on the key, and check the origin on the hub, where it belongs:
[captcha]
site_key = "6Le..."
secret_key = "6Le..."
-allowed_hosts = ["meshbay.org", "localhost", "meshbay"]
+allowed_hosts = ["meshbay.org", "localhost"]
+# Only with the desktop client. See below — this is the loose one.
+allow_unattributed_host = true
```
`verify_captcha` then refuses a solve whose reported hostname is not in that
@@ -430,20 +432,37 @@ setting keeps the behaviour it has, with reCAPTCHA doing the origin check
itself. **The two settings go together**: turning the console check off without
setting `allowed_hosts` leaves no origin check anywhere.
-**The last entry is the desktop client's own, and it is the weak one.** Any
-Electron application can claim the same scheme and host — `main.js` already
-records that `app://meshbay` is not a credential, which is why the hub's API is
-reachable from no web origin at all and every call leaves from the main
-process. So `meshbay` in that list is spoofable by someone who builds an
-equivalent application. What it still costs them is a per-token captcha solve
-inside a real Chromium, rather than a token farmed from any web page. That is
-the trade, stated plainly; a hub that does not ship the desktop client should
-leave the entry out.
+### The hostname a desktop solve reports is empty, not `meshbay`
-**Confirming the hostname.** `meshbay` is the host component of
-`app://meshbay`. If a solve is refused, `captcha.py` logs it at WARNING with
-the hostname spelled out and the allowed list beside it, which is how to read
-the value a given client actually reports rather than guess at it.
+Built first as an allowlist entry, on the assumption that Google would report
+the host component of the origin. It does not, and registration from the
+client failed with `captcha_failed` while the checkbox was green — a worse
+symptom than the one being fixed, because the widget now looked fine. The log
+line said it outright:
+
+```
+captcha solved on an unexpected host ''; allowed: ['localhost', 'meshbay', 'meshbay.org']
+```
+
+A solve Google cannot attribute to a domain reports an **empty** hostname. No
+allowlist entry can match that, and an empty entry is not the answer either:
+a blank in a TOML list is a typo far more often than an intention, and
+`load_config` drops blanks for that reason. `allow_unattributed_host` is a
+named flag instead, so the trade is stated where it is made.
+
+**What it admits, plainly.** Every non-web client, not only ours — a `file://`
+page or somebody else's Electron application report the same nothing. That is
+the same bar the client's own origin would have been (`main.js` already records
+that `app://meshbay` is not a credential; any application can claim it), and it
+*is* a bar: the captcha still has to be solved, per token, in something that
+can render it. What is given up is the origin restriction for non-web clients,
+not the captcha. A hub that does not ship the desktop client should leave the
+flag off.
+
+**Reading the value yourself.** Any refusal is logged at WARNING, with the
+hostname spelled out and the allowed list beside it when there is one. That is
+how the empty hostname was found, and it is the way to check what a given
+client actually reports rather than guess — which is what went wrong here.
---
@@ -508,7 +527,9 @@ from Google — no npm package.
site_key = "6Le..."
secret_key = "6Le..."
# Required whenever the console's origin check is off, and only then.
- allowed_hosts = ["meshbay.org", "localhost", "meshbay"]
+ allowed_hosts = ["meshbay.org", "localhost"]
+ # Only with the desktop client — §6 says what it gives up.
+ allow_unattributed_host = true
```
3. Deploy the new hub code (`deploy-hub.sh` — runs `alembic upgrade head` +
restart; no migration needed for this change).
@@ -517,6 +538,8 @@ from Google — no npm package.
solving the captcha.
5. Verify reset: open `https://meshbay.org/#/reset`, confirm the checkbox
appears. Request a reset code, confirm email arrives only after solving it.
-6. Verify the desktop client: register from it and confirm the widget solves
- rather than showing "Invalid domain for site key". A refusal logged as
- `captcha solved on an unexpected host` names the hostname to add.
+6. Verify the desktop client by actually registering from it. Two distinct
+ failures, and the first hides the second: "Invalid domain for site key"
+ inside the widget means the console's origin check is still on, while a
+ green checkbox followed by `captcha_failed` means the hub refused it — the
+ WARNING in the journal says which host, or that there was none.