communication: stage guest-helper for prune
This commit is contained in:
parent
71c58ee081
commit
6759817518
239
services/communication/guest-helper.yaml
Normal file
239
services/communication/guest-helper.yaml
Normal file
@ -0,0 +1,239 @@
|
||||
# services/communication/guest-helper.yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: guest-helper
|
||||
data:
|
||||
app.py: |
|
||||
import os, uuid, string, random
|
||||
import requests
|
||||
from fastapi import FastAPI, HTTPException, Header
|
||||
from pydantic import BaseModel
|
||||
import uvicorn
|
||||
|
||||
BASE = os.environ.get("SYNAPSE_BASE", "http://othrys-synapse-matrix-synapse:8008")
|
||||
SEED_USER = os.environ["SEEDER_USER"]
|
||||
SEED_PASS = os.environ["SEEDER_PASS"]
|
||||
SERVER_NAME = os.environ.get("SERVER_NAME", "live.bstein.dev")
|
||||
ELEMENT_URL = os.environ.get("ELEMENT_URL", "https://live.bstein.dev")
|
||||
ADMIN_TOKEN = os.environ.get("ADMIN_TOKEN")
|
||||
|
||||
app = FastAPI(title="Guest Helper", version="0.1.0")
|
||||
|
||||
|
||||
class InviteRequest(BaseModel):
|
||||
room: str # room_id or alias
|
||||
display_name: str | None = None
|
||||
|
||||
|
||||
def login(user, password):
|
||||
res = requests.post(
|
||||
f"{BASE}/_matrix/client/v3/login",
|
||||
json={
|
||||
"type": "m.login.password",
|
||||
"identifier": {"type": "m.id.user", "user": user},
|
||||
"password": password,
|
||||
},
|
||||
timeout=10,
|
||||
)
|
||||
if res.status_code != 200:
|
||||
raise HTTPException(status_code=500, detail="seeder login failed")
|
||||
return res.json()["access_token"]
|
||||
|
||||
|
||||
def resolve_room(token, room):
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
if room.startswith("!"):
|
||||
return room
|
||||
if room.startswith("#"):
|
||||
alias_enc = requests.utils.requote_uri(room)
|
||||
r = requests.get(f"{BASE}/_matrix/client/v3/directory/room/{alias_enc}", headers=headers, timeout=10)
|
||||
if r.status_code != 200:
|
||||
raise HTTPException(status_code=400, detail="room alias not found")
|
||||
return r.json()["room_id"]
|
||||
raise HTTPException(status_code=400, detail="room must be room_id or alias")
|
||||
|
||||
|
||||
def random_pwd():
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
return "".join(random.choice(alphabet) for _ in range(20))
|
||||
|
||||
|
||||
def create_guest(token, display):
|
||||
uid = f"@guest-{uuid.uuid4().hex[:8]}:{SERVER_NAME}"
|
||||
pwd = random_pwd()
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
body = {
|
||||
"password": pwd,
|
||||
"displayname": display or "Guest",
|
||||
"admin": False,
|
||||
"deactivated": False,
|
||||
}
|
||||
r = requests.put(
|
||||
f"{BASE}/_synapse/admin/v2/users/{requests.utils.requote_uri(uid)}",
|
||||
headers=headers,
|
||||
json=body,
|
||||
timeout=10,
|
||||
)
|
||||
if r.status_code not in (200, 201):
|
||||
raise HTTPException(status_code=500, detail=f"user create failed: {r.text}")
|
||||
return uid, pwd
|
||||
|
||||
|
||||
def join_room_as(token, room_id, user_id):
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
r = requests.post(
|
||||
f"{BASE}/_synapse/admin/v1/join/{requests.utils.requote_uri(room_id)}",
|
||||
headers=headers,
|
||||
json={"user_id": user_id},
|
||||
timeout=10,
|
||||
)
|
||||
if r.status_code not in (200, 202):
|
||||
raise HTTPException(status_code=500, detail=f"join failed: {r.text}")
|
||||
|
||||
|
||||
def login_token(user, password):
|
||||
r = requests.post(
|
||||
f"{BASE}/_matrix/client/v3/login",
|
||||
json={
|
||||
"type": "m.login.password",
|
||||
"identifier": {"type": "m.id.user", "user": user},
|
||||
"password": password,
|
||||
},
|
||||
timeout=10,
|
||||
)
|
||||
if r.status_code != 200:
|
||||
raise HTTPException(status_code=500, detail="guest login failed")
|
||||
data = r.json()
|
||||
return data["access_token"]
|
||||
|
||||
|
||||
@app.post("/invite")
|
||||
def invite(req: InviteRequest, x_admin_token: str | None = Header(default=None)):
|
||||
if ADMIN_TOKEN and x_admin_token != ADMIN_TOKEN:
|
||||
raise HTTPException(status_code=401, detail="unauthorized")
|
||||
admin_token = login(SEED_USER, SEED_PASS)
|
||||
room_id = resolve_room(admin_token, req.room)
|
||||
guest_id, pwd = create_guest(admin_token, req.display_name)
|
||||
join_room_as(admin_token, room_id, guest_id)
|
||||
guest_token = login_token(guest_id, pwd)
|
||||
join_url = f"{ELEMENT_URL}/#/room/{room_id}?access_token={guest_token}&user_id={guest_id}"
|
||||
return {
|
||||
"user_id": guest_id,
|
||||
"password": pwd,
|
||||
"room_id": room_id,
|
||||
"access_token": guest_token,
|
||||
"join_url": join_url,
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
uvicorn.run(app, host="0.0.0.0", port=8081)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: guest-helper
|
||||
labels:
|
||||
app: guest-helper
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: guest-helper
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: guest-helper
|
||||
spec:
|
||||
nodeSelector:
|
||||
hardware: rpi5
|
||||
containers:
|
||||
- name: api
|
||||
image: python:3.11-slim
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
pip install --no-cache-dir fastapi uvicorn requests && \
|
||||
python /app/app.py
|
||||
env:
|
||||
- name: SYNAPSE_BASE
|
||||
value: http://othrys-synapse-matrix-synapse:8008
|
||||
- name: SEEDER_USER
|
||||
value: othrys-seeder
|
||||
- name: SEEDER_PASS
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: atlasbot-credentials
|
||||
key: seeder-password
|
||||
- name: SERVER_NAME
|
||||
value: live.bstein.dev
|
||||
- name: ELEMENT_URL
|
||||
value: https://live.bstein.dev
|
||||
- name: ADMIN_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: guest-helper-admin
|
||||
key: ADMIN_TOKEN
|
||||
optional: true
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8081
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 300m
|
||||
memory: 256Mi
|
||||
volumeMounts:
|
||||
- name: code
|
||||
mountPath: /app/app.py
|
||||
subPath: app.py
|
||||
volumes:
|
||||
- name: code
|
||||
configMap:
|
||||
name: guest-helper
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: guest-helper
|
||||
spec:
|
||||
selector:
|
||||
app: guest-helper
|
||||
ports:
|
||||
- name: http
|
||||
port: 8081
|
||||
targetPort: 8081
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: guest-helper
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik
|
||||
traefik.ingress.kubernetes.io/router.entrypoints: websecure
|
||||
traefik.ingress.kubernetes.io/router.tls: "true"
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
spec:
|
||||
tls:
|
||||
- hosts:
|
||||
- live.bstein.dev
|
||||
secretName: live-othrys-tls
|
||||
rules:
|
||||
- host: live.bstein.dev
|
||||
http:
|
||||
paths:
|
||||
- path: /guest-helper
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: guest-helper
|
||||
port:
|
||||
number: 8081
|
||||
@ -22,3 +22,5 @@ resources:
|
||||
- atlasbot-deployment.yaml
|
||||
- seed-othrys-room.yaml
|
||||
- wellknown.yaml
|
||||
- synapse-federation-service.yaml
|
||||
- guest-helper.yaml
|
||||
|
||||
15
services/communication/synapse-federation-service.yaml
Normal file
15
services/communication/synapse-federation-service.yaml
Normal file
@ -0,0 +1,15 @@
|
||||
# services/communication/synapse-federation-service.yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: synapse-federation
|
||||
spec:
|
||||
clusterIP: 10.43.60.60
|
||||
selector:
|
||||
app.kubernetes.io/name: matrix-synapse
|
||||
app.kubernetes.io/instance: othrys-synapse
|
||||
ports:
|
||||
- name: federation
|
||||
port: 8448
|
||||
targetPort: 8008
|
||||
protocol: TCP
|
||||
Loading…
x
Reference in New Issue
Block a user