comms: source admin token from seeder access tokens
This commit is contained in:
parent
b2c7ca8cf1
commit
caa6b73336
@ -1,12 +1,12 @@
|
||||
# services/comms/oneoffs/synapse-admin-ensure-job.yaml
|
||||
# One-off job for comms/synapse-admin-ensure-11.
|
||||
# Purpose: synapse admin ensure 11 (see container args/env in this file).
|
||||
# One-off job for comms/synapse-admin-ensure-12.
|
||||
# Purpose: synapse admin ensure 12 (see container args/env in this file).
|
||||
# Run by setting spec.suspend to false, reconcile, then set it back to true.
|
||||
# Safe to delete the finished Job/pod; it should not run continuously.
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: synapse-admin-ensure-11
|
||||
name: synapse-admin-ensure-12
|
||||
namespace: comms
|
||||
spec:
|
||||
suspend: false
|
||||
@ -49,14 +49,10 @@ spec:
|
||||
python - <<'PY'
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import string
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
import bcrypt
|
||||
import psycopg2
|
||||
|
||||
VAULT_ADDR = os.environ.get("VAULT_ADDR", "http://vault.vault.svc.cluster.local:8200").rstrip("/")
|
||||
@ -112,51 +108,16 @@ spec:
|
||||
headers={"X-Vault-Token": token, "Content-Type": "application/json"},
|
||||
method="POST",
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
resp.read()
|
||||
|
||||
def random_password(length: int = 32) -> str:
|
||||
alphabet = string.ascii_letters + string.digits
|
||||
return "".join(secrets.choice(alphabet) for _ in range(length))
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
resp.read()
|
||||
|
||||
def ensure_admin_creds(token: str) -> dict:
|
||||
data = vault_get(token, "comms/synapse-admin")
|
||||
username = (data.get("username") or "").strip() or "synapse-admin"
|
||||
password = (data.get("password") or "").strip()
|
||||
if not password:
|
||||
password = random_password()
|
||||
username = (data.get("username") or "").strip() or "othrys-seeder"
|
||||
data["username"] = username
|
||||
data["password"] = password
|
||||
vault_put(token, "comms/synapse-admin", data)
|
||||
return data
|
||||
|
||||
def ensure_user(cur, cols, user_id, password, admin):
|
||||
now_ms = int(time.time() * 1000)
|
||||
values = {
|
||||
"name": user_id,
|
||||
"password_hash": bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode(),
|
||||
"creation_ts": now_ms,
|
||||
}
|
||||
|
||||
def add_flag(name, flag):
|
||||
if name not in cols:
|
||||
return
|
||||
if cols[name]["type"] in ("smallint", "integer"):
|
||||
values[name] = int(flag)
|
||||
else:
|
||||
values[name] = bool(flag)
|
||||
|
||||
add_flag("admin", admin)
|
||||
add_flag("deactivated", False)
|
||||
add_flag("shadow_banned", False)
|
||||
add_flag("is_guest", False)
|
||||
|
||||
columns = list(values.keys())
|
||||
placeholders = ", ".join(["%s"] * len(columns))
|
||||
updates = ", ".join([f"{col}=EXCLUDED.{col}" for col in columns if col != "name"])
|
||||
query = f"INSERT INTO users ({', '.join(columns)}) VALUES ({placeholders}) ON CONFLICT (name) DO UPDATE SET {updates};"
|
||||
cur.execute(query, [values[c] for c in columns])
|
||||
|
||||
def get_cols(cur):
|
||||
cur.execute(
|
||||
"""
|
||||
@ -174,33 +135,6 @@ spec:
|
||||
}
|
||||
return cols
|
||||
|
||||
def ensure_access_token(cur, user_id, token_value):
|
||||
cur.execute("SELECT COALESCE(MAX(id), 0) + 1 FROM access_tokens")
|
||||
token_id = cur.fetchone()[0]
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO access_tokens (id, user_id, token, device_id, valid_until_ms)
|
||||
VALUES (%s, %s, %s, %s, NULL)
|
||||
ON CONFLICT (token) DO NOTHING
|
||||
""",
|
||||
(token_id, user_id, token_value, "ariadne-admin"),
|
||||
)
|
||||
|
||||
def ensure_device(cur, user_id, device_id):
|
||||
cur.execute(
|
||||
"SELECT 1 FROM devices WHERE user_id = %s AND device_id = %s",
|
||||
(user_id, device_id),
|
||||
)
|
||||
if cur.fetchone():
|
||||
return
|
||||
cur.execute(
|
||||
"""
|
||||
INSERT INTO devices (user_id, device_id, display_name, last_seen, ip, user_agent, hidden)
|
||||
VALUES (%s, %s, %s, %s, NULL, NULL, FALSE)
|
||||
""",
|
||||
(user_id, device_id, "ariadne-admin", int(time.time() * 1000)),
|
||||
)
|
||||
|
||||
def admin_token_valid(token: str, user_id: str) -> bool:
|
||||
if not token or not SYNAPSE_ADMIN_URL:
|
||||
return False
|
||||
@ -242,15 +176,24 @@ spec:
|
||||
user=PGUSER,
|
||||
password=pg_password,
|
||||
)
|
||||
token_value = f"syt_{secrets.token_urlsafe(32)}"
|
||||
device_id = "ariadne-admin"
|
||||
try:
|
||||
with conn:
|
||||
with conn.cursor() as cur:
|
||||
cols = get_cols(cur)
|
||||
ensure_user(cur, cols, user_id, admin_data["password"], True)
|
||||
ensure_device(cur, user_id, device_id)
|
||||
ensure_access_token(cur, user_id, token_value)
|
||||
if "admin" not in cols:
|
||||
raise RuntimeError("users.admin column missing")
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT token FROM access_tokens
|
||||
WHERE user_id = %s AND valid_until_ms IS NULL
|
||||
ORDER BY id DESC LIMIT 1
|
||||
""",
|
||||
(user_id,),
|
||||
)
|
||||
row = cur.fetchone()
|
||||
if not row:
|
||||
raise RuntimeError(f"no access token found for {user_id}")
|
||||
token_value = row[0]
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user