comms: fix guest rename job with MAS admin sessions
This commit is contained in:
parent
e44ee3ab2d
commit
47f0ff7c01
@ -6,28 +6,40 @@ metadata:
|
|||||||
namespace: comms
|
namespace: comms
|
||||||
spec:
|
spec:
|
||||||
schedule: "*/1 * * * *"
|
schedule: "*/1 * * * *"
|
||||||
suspend: true
|
suspend: false
|
||||||
jobTemplate:
|
jobTemplate:
|
||||||
spec:
|
spec:
|
||||||
backoffLimit: 0
|
backoffLimit: 0
|
||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
restartPolicy: Never
|
restartPolicy: Never
|
||||||
|
volumes:
|
||||||
|
- name: mas-admin-client
|
||||||
|
secret:
|
||||||
|
secretName: mas-admin-client-runtime
|
||||||
|
items:
|
||||||
|
- key: client_secret
|
||||||
|
path: client_secret
|
||||||
containers:
|
containers:
|
||||||
- name: rename
|
- name: rename
|
||||||
image: python:3.11-slim
|
image: python:3.11-slim
|
||||||
|
volumeMounts:
|
||||||
|
- name: mas-admin-client
|
||||||
|
mountPath: /etc/mas-admin-client
|
||||||
|
readOnly: true
|
||||||
env:
|
env:
|
||||||
- name: SYNAPSE_BASE
|
- name: SYNAPSE_BASE
|
||||||
value: http://othrys-synapse-matrix-synapse:8008
|
value: http://othrys-synapse-matrix-synapse:8008
|
||||||
- name: AUTH_BASE
|
- name: MAS_ADMIN_CLIENT_ID
|
||||||
value: http://matrix-authentication-service:8080
|
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: MAS_TOKEN_URL
|
||||||
|
value: http://matrix-authentication-service:8080/oauth2/token
|
||||||
- name: SEEDER_USER
|
- name: SEEDER_USER
|
||||||
value: othrys-seeder
|
value: othrys-seeder
|
||||||
- name: SEEDER_PASS
|
|
||||||
valueFrom:
|
|
||||||
secretKeyRef:
|
|
||||||
name: atlasbot-credentials-runtime
|
|
||||||
key: seeder-password
|
|
||||||
command:
|
command:
|
||||||
- /bin/sh
|
- /bin/sh
|
||||||
- -c
|
- -c
|
||||||
@ -35,24 +47,77 @@ spec:
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
pip install --no-cache-dir requests >/dev/null
|
pip install --no-cache-dir requests >/dev/null
|
||||||
python - <<'PY'
|
python - <<'PY'
|
||||||
import os, random, requests, urllib.parse
|
import base64
|
||||||
|
import os
|
||||||
|
import random
|
||||||
|
import requests
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
ADJ = ["brisk","calm","eager","gentle","merry","nifty","rapid","sunny","witty","zesty"]
|
ADJ = [
|
||||||
NOUN = ["otter","falcon","comet","ember","grove","harbor","meadow","raven","river","summit"]
|
"brisk","calm","eager","gentle","merry","nifty","rapid","sunny","witty","zesty",
|
||||||
|
"amber","bold","bright","crisp","daring","frosty","glad","jolly","lively","mellow",
|
||||||
|
"quiet","ripe","serene","spry","tidy","vivid","warm","wild","clever","kind",
|
||||||
|
]
|
||||||
|
NOUN = [
|
||||||
|
"otter","falcon","comet","ember","grove","harbor","meadow","raven","river","summit",
|
||||||
|
"breeze","cedar","cinder","cove","delta","forest","glade","lark","marsh","peak",
|
||||||
|
"pine","quartz","reef","ridge","sable","sage","shore","thunder","vale","zephyr",
|
||||||
|
]
|
||||||
|
|
||||||
BASE = os.environ["SYNAPSE_BASE"]
|
BASE = os.environ["SYNAPSE_BASE"]
|
||||||
AUTH_BASE = os.environ.get("AUTH_BASE", BASE)
|
MAS_ADMIN_CLIENT_ID = os.environ["MAS_ADMIN_CLIENT_ID"]
|
||||||
|
MAS_ADMIN_CLIENT_SECRET_FILE = os.environ["MAS_ADMIN_CLIENT_SECRET_FILE"]
|
||||||
|
MAS_ADMIN_API_BASE = os.environ["MAS_ADMIN_API_BASE"].rstrip("/")
|
||||||
|
MAS_TOKEN_URL = os.environ["MAS_TOKEN_URL"]
|
||||||
|
SEEDER_USER = os.environ["SEEDER_USER"]
|
||||||
ROOM_ALIAS = "#othrys:live.bstein.dev"
|
ROOM_ALIAS = "#othrys:live.bstein.dev"
|
||||||
|
|
||||||
def login(user, password):
|
def mas_admin_token():
|
||||||
r = requests.post(f"{AUTH_BASE}/_matrix/client/v3/login", json={
|
with open(MAS_ADMIN_CLIENT_SECRET_FILE, "r", encoding="utf-8") as f:
|
||||||
"type": "m.login.password",
|
secret = f.read().strip()
|
||||||
"identifier": {"type": "m.id.user", "user": user},
|
basic = base64.b64encode(f"{MAS_ADMIN_CLIENT_ID}:{secret}".encode()).decode()
|
||||||
"password": password,
|
r = requests.post(
|
||||||
})
|
MAS_TOKEN_URL,
|
||||||
|
headers={"Authorization": f"Basic {basic}"},
|
||||||
|
data={"grant_type": "client_credentials", "scope": "urn:mas:admin"},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
r.raise_for_status()
|
r.raise_for_status()
|
||||||
return r.json()["access_token"]
|
return r.json()["access_token"]
|
||||||
|
|
||||||
|
def mas_user_id(token, username):
|
||||||
|
r = requests.get(
|
||||||
|
f"{MAS_ADMIN_API_BASE}/users/by-username/{urllib.parse.quote(username)}",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
return r.json()["data"]["id"]
|
||||||
|
|
||||||
|
def mas_personal_session(token, user_id):
|
||||||
|
r = requests.post(
|
||||||
|
f"{MAS_ADMIN_API_BASE}/personal-sessions",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
json={
|
||||||
|
"actor_user_id": user_id,
|
||||||
|
"human_name": "guest-name-randomizer",
|
||||||
|
"scope": "urn:matrix:client:api:*",
|
||||||
|
"expires_in": 300,
|
||||||
|
},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
r.raise_for_status()
|
||||||
|
data = r.json().get("data", {}).get("attributes", {}) or {}
|
||||||
|
return data["access_token"], r.json()["data"]["id"]
|
||||||
|
|
||||||
|
def mas_revoke_session(token, session_id):
|
||||||
|
requests.post(
|
||||||
|
f"{MAS_ADMIN_API_BASE}/personal-sessions/{urllib.parse.quote(session_id)}/revoke",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
json={},
|
||||||
|
timeout=30,
|
||||||
|
)
|
||||||
|
|
||||||
def resolve_alias(token, alias):
|
def resolve_alias(token, alias):
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
enc = urllib.parse.quote(alias)
|
enc = urllib.parse.quote(alias)
|
||||||
@ -63,6 +128,7 @@ spec:
|
|||||||
def list_guests(token):
|
def list_guests(token):
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
users = []
|
users = []
|
||||||
|
existing_names = set()
|
||||||
from_token = None
|
from_token = None
|
||||||
while True:
|
while True:
|
||||||
url = f"{BASE}/_synapse/admin/v2/users?local=true&deactivated=false&limit=100"
|
url = f"{BASE}/_synapse/admin/v2/users?local=true&deactivated=false&limit=100"
|
||||||
@ -73,12 +139,14 @@ spec:
|
|||||||
data = res.json()
|
data = res.json()
|
||||||
for u in data.get("users", []):
|
for u in data.get("users", []):
|
||||||
disp = u.get("displayname", "")
|
disp = u.get("displayname", "")
|
||||||
|
if disp:
|
||||||
|
existing_names.add(disp)
|
||||||
if u.get("is_guest") and (not disp or disp.isdigit()):
|
if u.get("is_guest") and (not disp or disp.isdigit()):
|
||||||
users.append(u["name"])
|
users.append(u["name"])
|
||||||
from_token = data.get("next_token")
|
from_token = data.get("next_token")
|
||||||
if not from_token:
|
if not from_token:
|
||||||
break
|
break
|
||||||
return users
|
return users, existing_names
|
||||||
|
|
||||||
def set_displayname(token, room_id, user_id, name):
|
def set_displayname(token, room_id, user_id, name):
|
||||||
headers = {"Authorization": f"Bearer {token}"}
|
headers = {"Authorization": f"Bearer {token}"}
|
||||||
@ -93,10 +161,23 @@ spec:
|
|||||||
content["displayname"] = name
|
content["displayname"] = name
|
||||||
requests.put(state_url, headers=headers, json=content)
|
requests.put(state_url, headers=headers, json=content)
|
||||||
|
|
||||||
token = login(os.environ["SEEDER_USER"], os.environ["SEEDER_PASS"])
|
admin_token = mas_admin_token()
|
||||||
room_id = resolve_alias(token, ROOM_ALIAS)
|
seeder_id = mas_user_id(admin_token, SEEDER_USER)
|
||||||
guests = list_guests(token)
|
token, session_id = mas_personal_session(admin_token, seeder_id)
|
||||||
for g in guests:
|
try:
|
||||||
new = f"{random.choice(ADJ)}-{random.choice(NOUN)}"
|
room_id = resolve_alias(token, ROOM_ALIAS)
|
||||||
set_displayname(token, room_id, g, new)
|
guests, existing = list_guests(token)
|
||||||
|
for g in guests:
|
||||||
|
new = None
|
||||||
|
for _ in range(30):
|
||||||
|
candidate = f\"{random.choice(ADJ)}-{random.choice(NOUN)}\"
|
||||||
|
if candidate not in existing:
|
||||||
|
new = candidate
|
||||||
|
existing.add(candidate)
|
||||||
|
break
|
||||||
|
if not new:
|
||||||
|
continue
|
||||||
|
set_displayname(token, room_id, g, new)
|
||||||
|
finally:
|
||||||
|
mas_revoke_session(admin_token, session_id)
|
||||||
PY
|
PY
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user