aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/config.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/config.py')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/config.py58
1 files changed, 17 insertions, 41 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/config.py b/packages/meshbay-hub/src/meshbay_hub/config.py
index e618510..f710ead 100644
--- a/packages/meshbay-hub/src/meshbay_hub/config.py
+++ b/packages/meshbay-hub/src/meshbay_hub/config.py
@@ -66,33 +66,15 @@ class JWTConfig:
@dataclass
class CaptchaConfig:
- site_key: str = ""
- secret_key: str = ""
- # Hostnames a solved captcha may have come from, checked against the one
- # `siteverify` reports. Empty means "do not check", which is right while
- # the reCAPTCHA key does its own origin check — it is then already done.
- #
- # Set this when that check is turned off in the reCAPTCHA console, which is
- # what the desktop client needs: its page is served from `app://meshbay`,
- # so the hostname Google sees is not the hub's and never can be. See
- # docs/MESHBAY_DESIGN.md §7.7.
- allowed_hosts: list[str] = field(default_factory=list)
- # A solve from a page Google cannot attribute to a domain reports an empty
- # hostname — `app://meshbay` does, measured live, and so does any other
- # non-web client. No `allowed_hosts` entry can match that, and a blank
- # entry is not the answer: the parser drops blanks because in a TOML list
- # a blank is a typo far more often than an intention. Hence a named flag,
- # which also states the trade at the place it is made.
- allow_unattributed_host: bool = False
-
- @property
- def enabled(self) -> bool:
- return bool(self.site_key and self.secret_key)
-
- @property
- def host_check(self) -> frozenset[str] | None:
- """The set to hand `verify_captcha`, or None for "do not check"."""
- return frozenset(self.allowed_hosts) if self.allowed_hosts else None
+ # The proof of work on registration and password reset (captcha.py). On
+ # unless a configuration turns it off, which is for development and for a
+ # hub nobody can reach.
+ enabled: bool = True
+ # The work asked of the page: it tries numbers from 0 until one matches, so
+ # half of this on average and all of it at worst. Sized for the slowest
+ # phone that signs up — about three seconds there, solved while the form is
+ # being filled in — not for the desktop, which takes a fraction of that.
+ max_number: int = 500_000
@dataclass
@@ -183,12 +165,12 @@ def load_config(path: Path | None = None) -> HubConfig:
):
setattr(cfg.mail, name, ml.get(name, getattr(cfg.mail, name)))
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)
- if hosts := cap.get("allowed_hosts"):
- cfg.captcha.allowed_hosts = [str(h).strip() for h in hosts if str(h).strip()]
- if "allow_unattributed_host" in cap:
- cfg.captcha.allow_unattributed_host = bool(cap["allow_unattributed_host"])
+ cfg.captcha.enabled = bool(cap.get("enabled", cfg.captcha.enabled))
+ cfg.captcha.max_number = max(1, int(cap.get("max_number", cfg.captcha.max_number)))
+ if "site_key" in cap or "secret_key" in cap:
+ log.warning("captcha.site_key and captcha.secret_key are no longer "
+ "read: registration is gated by a proof of work, with "
+ "no third party; remove them from the configuration")
break
# Env var overrides
@@ -204,13 +186,7 @@ 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
- if captcha_hosts := os.environ.get("MESHBAY_CAPTCHA_ALLOWED_HOSTS"):
- cfg.captcha.allowed_hosts = [h.strip() for h in captcha_hosts.split(",") if h.strip()]
- if unattributed := os.environ.get("MESHBAY_CAPTCHA_ALLOW_UNATTRIBUTED_HOST"):
- cfg.captcha.allow_unattributed_host = unattributed.lower() in ("1", "true", "yes")
+ if captcha := os.environ.get("MESHBAY_CAPTCHA_ENABLED"):
+ cfg.captcha.enabled = captcha.lower() in ("1", "true", "yes")
return cfg