comms: fix guest registration via MAS admin API

This commit is contained in:
Brad Stein 2026-01-07 20:02:03 -03:00
parent 70e40b281f
commit e44ee3ab2d
2 changed files with 53 additions and 44 deletions

View File

@ -14,11 +14,14 @@ data:
from urllib import error, parse, request
MAS_BASE = os.environ.get("MAS_BASE", "http://matrix-authentication-service:8080").rstrip("/")
MAS_ADMIN_API_BASE = os.environ.get("MAS_ADMIN_API_BASE", "http://matrix-authentication-service:8081/api/admin/v1").rstrip("/")
SYNAPSE_BASE = os.environ.get("SYNAPSE_BASE", "http://othrys-synapse-matrix-synapse:8008").rstrip("/")
SERVER_NAME = os.environ.get("MATRIX_SERVER_NAME", "live.bstein.dev")
MAS_ADMIN_CLIENT_ID = os.environ["MAS_ADMIN_CLIENT_ID"]
MAS_ADMIN_CLIENT_SECRET_FILE = os.environ.get("MAS_ADMIN_CLIENT_SECRET_FILE", "/etc/mas/admin-client/client_secret")
MAS_ADMIN_SCOPE = os.environ.get("MAS_ADMIN_SCOPE", "urn:mas:admin")
SESSION_TTL_SEC = int(os.environ.get("SESSION_TTL_SEC", "43200"))
RATE_WINDOW_SEC = int(os.environ.get("RATE_WINDOW_SEC", "60"))
RATE_MAX = int(os.environ.get("RATE_MAX", "30"))
@ -93,51 +96,52 @@ data:
_admin_token_at = now
return _admin_token
def _gql(admin_token, query, variables):
status, payload = _json(
"POST",
f"{MAS_BASE}/graphql",
headers={"Authorization": f"Bearer {admin_token}"},
body={"query": query, "variables": variables},
timeout=20,
)
if status != 200:
raise RuntimeError("gql_http_failed")
if payload.get("errors"):
raise RuntimeError("gql_error")
return payload.get("data") or {}
def _generate_localpart():
return "guest-" + secrets.token_hex(6)
def _generate_displayname():
return f"{random.choice(ADJ)}-{random.choice(NOUN)}"
def _add_user(admin_token, username):
data = _gql(
admin_token,
"mutation($input:AddUserInput!){addUser(input:$input){status user{id username}}}",
{"input": {"username": username, "skipHomeserverCheck": True}},
)
res = data.get("addUser") or {}
status = res.get("status")
user = res.get("user") or {}
return status, user.get("id"), user.get("username")
def _set_display_name(admin_token, user_id, displayname):
_gql(
admin_token,
"mutation($input:SetDisplayNameInput!){setDisplayName(input:$input){status}}",
{"input": {"userId": user_id, "displayName": displayname}},
def _admin_api(admin_token, method, path, body=None):
return _json(
method,
f"{MAS_ADMIN_API_BASE}{path}",
headers={"Authorization": f"Bearer {admin_token}"},
body=body,
timeout=20,
)
def _create_oauth2_session(admin_token, user_id, scope):
data = _gql(
def _create_user(admin_token, username):
status, payload = _admin_api(admin_token, "POST", "/users", {"username": username})
if status != 201:
return status, None
user = payload.get("data") or {}
return status, user.get("id")
def _create_session(admin_token, user_id, scope):
status, payload = _admin_api(
admin_token,
"mutation($input:CreateOAuth2SessionInput!){createOauth2Session(input:$input){accessToken}}",
{"input": {"userId": user_id, "scope": scope, "permanent": False}},
"POST",
"/personal-sessions",
{
"actor_user_id": user_id,
"human_name": "guest session",
"scope": scope,
"expires_in": SESSION_TTL_SEC,
},
)
if status != 201:
return None
return (payload.get("data", {}).get("attributes", {}) or {}).get("access_token")
def _set_display_name(access_token, user_id, displayname):
_json(
"PUT",
f"{SYNAPSE_BASE}/_matrix/client/v3/profile/{parse.quote(user_id, safe='')}/displayname",
headers={"Authorization": f"Bearer {access_token}"},
body={"displayname": displayname},
timeout=20,
)
return (data.get("createOauth2Session") or {}).get("accessToken")
def _rate_check(ip, now):
win, cnt = _rate.get(ip, (now, 0))
@ -216,21 +220,20 @@ data:
mas_user_id = None
for _ in range(5):
localpart = _generate_localpart()
status, mas_user_id, _ = _add_user(admin_token, localpart)
if status == "ADDED":
status, mas_user_id = _create_user(admin_token, localpart)
if status == 201 and mas_user_id:
break
mas_user_id = None
if not mas_user_id or not localpart:
raise RuntimeError("add_user_failed")
try:
_set_display_name(admin_token, mas_user_id, displayname)
except Exception:
pass
access_token = _create_oauth2_session(admin_token, mas_user_id, "urn:matrix:client:api:*")
access_token = _create_session(admin_token, mas_user_id, "urn:matrix:client:api:*")
if not access_token:
raise RuntimeError("session_failed")
try:
_set_display_name(access_token, f"@{localpart}:{SERVER_NAME}", displayname)
except Exception:
pass
except Exception:
return self._send_json(502, {"errcode": "M_UNKNOWN", "error": "guest_provision_failed"})

View File

@ -13,7 +13,7 @@ spec:
template:
metadata:
annotations:
checksum/config: guest-register-proxy-4
checksum/config: guest-register-proxy-5
labels:
app.kubernetes.io/name: matrix-guest-register
spec:
@ -43,6 +43,12 @@ spec:
value: 01KDXMVQBQ5JNY6SEJPZW6Z8BM
- name: MAS_ADMIN_CLIENT_SECRET_FILE
value: /etc/mas/admin-client/client_secret
- name: MAS_ADMIN_API_BASE
value: http://matrix-authentication-service:8081/api/admin/v1
- name: SYNAPSE_BASE
value: http://othrys-synapse-matrix-synapse:8008
- name: SESSION_TTL_SEC
value: "43200"
- name: MATRIX_SERVER_NAME
value: live.bstein.dev
- name: RATE_WINDOW_SEC