diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-01 11:06:47 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-01 11:06:47 +0200 |
| commit | b6c15f35d570d4f54901b811654991847502ca82 (patch) | |
| tree | a3d0a42c3b48aa7ac618094cedc59b5b3f329376 /packages/meshbay-hub/src/meshbay_hub/config.py | |
| parent | 1c8eb6577e36e1e4a150afd0cdda8d283172385e (diff) | |
| download | meshbay-b6c15f35d570d4f54901b811654991847502ca82.tar.gz | |
feat(hub): reCAPTCHA v2 on Register and Password Reset pages
Server-side verification module, CaptchaConfig in hub.toml,
captcha_site_key exposed via /v1/hub/info, useCaptcha() hook
in the SPA with stable DOM rendering (strength bar always present
to avoid Preact re-ordering the captcha widget). Native clients
(auth_key path) skip captcha. All 10 locales updated.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/config.py')
| -rw-r--r-- | packages/meshbay-hub/src/meshbay_hub/config.py | 18 |
1 files changed, 18 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/config.py b/packages/meshbay-hub/src/meshbay_hub/config.py index b508e45..48d5a6e 100644 --- a/packages/meshbay-hub/src/meshbay_hub/config.py +++ b/packages/meshbay-hub/src/meshbay_hub/config.py @@ -62,11 +62,22 @@ class JWTConfig: @dataclass +class CaptchaConfig: + site_key: str = "" + secret_key: str = "" + + @property + def enabled(self) -> bool: + return bool(self.site_key and self.secret_key) + + +@dataclass class HubConfig: db: DatabaseConfig = field(default_factory=DatabaseConfig) server: ServerConfig = field(default_factory=ServerConfig) identity: HubIdentityConfig = field(default_factory=HubIdentityConfig) jwt: JWTConfig = field(default_factory=JWTConfig) + captcha: CaptchaConfig = field(default_factory=CaptchaConfig) def load_config(path: Path | None = None) -> HubConfig: @@ -92,6 +103,9 @@ def load_config(path: Path | None = None) -> HubConfig: if jwt := raw.get("jwt", {}): cfg.jwt.access_token_ttl = jwt.get("access_token_ttl", cfg.jwt.access_token_ttl) cfg.jwt.refresh_token_ttl = jwt.get("refresh_token_ttl", cfg.jwt.refresh_token_ttl) + if cap := raw.get("captcha", {}): + cfg.captcha.site_key = cap.get("site_key", cfg.captcha.site_key) + cfg.captcha.secret_key = cap.get("secret_key", cfg.captcha.secret_key) break # Env var overrides @@ -107,5 +121,9 @@ def load_config(path: Path | None = None) -> HubConfig: cfg.identity.private_key_path = Path(kp).expanduser() if admin_users := os.environ.get("MESHBAY_ADMIN_USERS"): cfg.identity.admin_usernames = [u.strip() for u in admin_users.split(",") if u.strip()] + if captcha_site := os.environ.get("MESHBAY_CAPTCHA_SITE_KEY"): + cfg.captcha.site_key = captcha_site + if captcha_secret := os.environ.get("MESHBAY_CAPTCHA_SECRET_KEY"): + cfg.captcha.secret_key = captcha_secret return cfg |