aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/src/meshbay_hub/auth.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/src/meshbay_hub/auth.py')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/auth.py15
1 files changed, 15 insertions, 0 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/auth.py b/packages/meshbay-hub/src/meshbay_hub/auth.py
index 28f13a5..2bf59db 100644
--- a/packages/meshbay-hub/src/meshbay_hub/auth.py
+++ b/packages/meshbay-hub/src/meshbay_hub/auth.py
@@ -189,6 +189,21 @@ def decrypt_email(stored: str) -> str:
return AESGCM(_email_key).decrypt(nonce, ct, None).decode()
+def hash_email_blind(email: str) -> str:
+ """Deterministic HMAC-SHA256 of the lowercased email for uniqueness checks.
+
+ The encrypted email uses a random nonce, so two encryptions of the same
+ address produce different ciphertexts. This blind index allows a DB-level
+ uniqueness constraint without decrypting every row.
+ """
+ if _email_key is None:
+ raise RuntimeError("Hub keypair not loaded")
+ import hmac as _hmac
+ return _hmac.new(
+ _email_key, email.strip().lower().encode(), hashlib.sha256,
+ ).hexdigest()
+
+
# ── Refresh tokens ────────────────────────────────────────────────────────────
def generate_refresh_token() -> tuple[str, str]: