diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-10-14 13:34:47 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-10-14 13:34:47 +0200 |
| commit | 51705056a578d2649a989bf14a056fbcfae58a6b (patch) | |
| tree | dfd078aba518427387fca29b9d43c3723b030008 /packages/meshbay-client/src | |
| parent | daec4bc6a2a9f9e038e5269586b06018ff327a27 (diff) | |
| download | meshbay-51705056a578d2649a989bf14a056fbcfae58a6b.tar.gz | |
feat(hub): replace reCAPTCHA with a self-hosted proof of work
Sign-up and passphrase reset sent every visitor's address and browser
details to Google, which needed a consent the sign-up form could not ask
for freely. The hub now issues its own challenge (ALTCHA's scheme, signed
with a key derived from the hub's private key, single-use, 30 minutes)
and the page solves it with SubtleCrypto while the form is filled in.
- GET /v1/users/captcha issues a challenge; 404 captcha_disabled when off.
- [captcha] enabled / max_number replace site_key / secret_key, which are
now ignored with a warning; MESHBAY_CAPTCHA_ENABLED replaces the old
variables.
- No Google origin left in the CSP of the hub, the desktop shell or the
Android shell; captcha_site_key leaves /v1/hub/info.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-client/src')
| -rw-r--r-- | packages/meshbay-client/src/main.js | 23 |
1 files changed, 5 insertions, 18 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js index 33388e8..8845b7b 100644 --- a/packages/meshbay-client/src/main.js +++ b/packages/meshbay-client/src/main.js @@ -115,29 +115,16 @@ function nodeLogHint() { // The hub is reachable under connect-src, for its API and its signaling socket. // It is deliberately absent from script-src: nothing it returns is executed, // which is the whole reason this application exists (T3). -// -// The one exception is reCAPTCHA, used to gate sign-up (and password reset) the -// same way it gates them in the browser. Its script comes from www.google.com, -// its challenge is a www.google.com iframe, and its assets sit on -// www.gstatic.com. These two hosts — and only these two — are allowed under -// `script-src`, `frame-src` and `img-src` for that purpose. It is a real, if -// small, dent in "no third-party code runs here": Google's reCAPTCHA script -// executes in the renderer. It is accepted deliberately so a native sign-up is -// gated like a web one without asking the user to do anything extra, and it is -// the *same* dependency the hub-served SPA already carries. If sign-up ever -// moves to a proof-of-work challenge, delete RECAPTCHA_SRC and the three -// directives that spread it, and the widget in auth-page.js with them. -const RECAPTCHA_SRC = 'https://www.google.com https://www.gstatic.com'; const CSP = [ "default-src 'none'", - `script-src 'self' 'wasm-unsafe-eval' ${RECAPTCHA_SRC}`, + "script-src 'self' 'wasm-unsafe-eval'", "style-src 'self' 'unsafe-inline'", - `img-src 'self' data: blob: ${RECAPTCHA_SRC}`, + "img-src 'self' data: blob:", "media-src 'self' blob:", "font-src 'self'", // Every hub call leaves from this process, so the page connects to nothing - // but its own files and reCAPTCHA; see the hub's webapp.CSP. - `connect-src 'self' ${RECAPTCHA_SRC}`, + // but its own files; see the hub's webapp.CSP. + "connect-src 'self'", "worker-src 'self'", // `blob:` here and in `frame-src` are one thing, not two: the PDF preview. // @@ -157,7 +144,7 @@ const CSP = [ // is PDFium parsing bytes that came from a node — exactly what a browser // does with the same file. "object-src blob:", - `frame-src blob: ${RECAPTCHA_SRC}`, + "frame-src blob:", "frame-ancestors 'none'", "base-uri 'none'", "form-action 'none'", |