Broker: resolve uid- identities (OIDC sub) to email — email-invited users have no username

This commit is contained in:
inference-bot committed 2026-09-29 21:53:46 -06:00
1 parent b93b208659
commit 64d3c6aa83
1 file changed
+10 -6
+10 -6
View File
@@ -2042,17 +2042,18 @@ def _verify_broker_secret(request: Request) -> str:
def resolve_member_email(identity: str) -> str: def resolve_member_email(identity: str) -> str:
"""Resolve a member identity (email OR Cloudron username) to their email. """Resolve a member identity (email, Cloudron username, or uid) to email.
If it looks like an email (contains "@"), return it lowercased. Otherwise Cloudron's OIDC `sub` claim is the user ID (uid-…), and email-invited users
treat it as a Cloudron username and look up the corresponding email from have no username at all. So accept three identity shapes:
the Cloudron user list (synchronous, using urllib since this runs outside - email ("@") → return as-is
the async request path of httpx). - uid-… → match on the user id
- username → match on the username field (legacy accounts)
""" """
identity = identity.strip() identity = identity.strip()
if "@" in identity: if "@" in identity:
return identity.lower() return identity.lower()
# Username → email via Cloudron user list. # uid / username → email via Cloudron user list (one fetch covers both).
import urllib.request import urllib.request
req = urllib.request.Request( req = urllib.request.Request(
@@ -2062,6 +2063,9 @@ def resolve_member_email(identity: str) -> str:
with urllib.request.urlopen(req, timeout=15) as r: with urllib.request.urlopen(req, timeout=15) as r:
data = json.loads(r.read().decode()) data = json.loads(r.read().decode())
users = data.get("users", []) users = data.get("users", [])
for u in users:
if u.get("id") == identity:
return (u.get("email") or "").lower()
for u in users: for u in users:
if u.get("username") == identity: if u.get("username") == identity:
return (u.get("email") or "").lower() return (u.get("email") or "").lower()