aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-01 17:49:13 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-01 17:49:13 +0200
commit7d8c774e250b134222374f45726d5426714475de (patch)
treed5cf7e7df3131dc51c5c46cc0e8c7ffb4aed0240 /packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
parent99eb93a00269fbfafba7536cf1613b3d4c18c3ce (diff)
downloadmeshbay-7d8c774e250b134222374f45726d5426714475de.tar.gz
fix(hub): enforce registration captcha for every client
The server only checked the captcha when auth_key was absent โ€” but every real client (browser included, via the password split) sends auth_key, so the check was off for everyone, and a bot skipped it by including the field. The Register form still made humans solve a widget whose token was never transmitted. Gate is now unconditional on captcha.enabled. The web client (registerUser in keyderive.js) forwards captcha.token; RegisterPage resets the (single-use) token on a failed attempt. The desktop client shares this UI source and is Chromium, so it renders the same widget (see the paired meshbay-client commit for the CSP change that allows it). Tests: test_register_captcha.py. Third security review, finding M1 (Option A). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011pG75yGK3NthNfyjH74omG
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/static/keyderive.js')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/keyderive.js6
1 files changed, 5 insertions, 1 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js b/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
index 0aaa6a5..a540a94 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/keyderive.js
@@ -276,7 +276,7 @@ async function decryptBundle(bundleB64, password, username) {
*
* Returns the raw private keys for immediate use after registration.
*/
-async function registerUser(username, email, password, recoveryMnemonic) {
+async function registerUser(username, email, password, recoveryMnemonic, captchaToken) {
// No keypair here any more. Identity keys are per node: one is generated the
// first time this account joins a given node, encrypted under the passphrase,
// and left with that node. So an operator who cracks what sits on their own
@@ -291,6 +291,10 @@ async function registerUser(username, email, password, recoveryMnemonic) {
// appends it to the verification e-mail and stores it nowhere
// (docs/auth-confirm.md ยง4.4). Omitted when they chose to save it themselves.
if (recoveryMnemonic) payload.recovery_key = recoveryMnemonic;
+ // reCAPTCHA response, when the hub has a captcha configured. The widget lives
+ // in RegisterPage (auth-page.js); this function just forwards its token. A
+ // hub with no captcha configured sends nothing and the server does not check.
+ if (captchaToken) payload.captcha_token = captchaToken;
const resp = await hubCall('/v1/users/register', {
method: 'POST',