aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/config.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-01 11:06:47 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-01 11:06:47 +0200
commitb6c15f35d570d4f54901b811654991847502ca82 (patch)
treea3d0a42c3b48aa7ac618094cedc59b5b3f329376 /packages/meshbay-hub/src/meshbay_hub/config.py
parent1c8eb6577e36e1e4a150afd0cdda8d283172385e (diff)
downloadmeshbay-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.py18
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