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
|
# services/comms/oneoffs/synapse-admin-ensure-job.yaml
|
||||||
# One-off job for comms/synapse-admin-ensure-11.
|
# One-off job for comms/synapse-admin-ensure-12.
|
||||||
# Purpose: synapse admin ensure 11 (see container args/env in this file).
|
# 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.
|
# 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.
|
# Safe to delete the finished Job/pod; it should not run continuously.
|
||||||
apiVersion: batch/v1
|
apiVersion: batch/v1
|
||||||
kind: Job
|
kind: Job
|
||||||
metadata:
|
metadata:
|
||||||
name: synapse-admin-ensure-11
|
name: synapse-admin-ensure-12
|
||||||
namespace: comms
|
namespace: comms
|
||||||
spec:
|
spec:
|
||||||
suspend: false
|
suspend: false
|
||||||
@ -49,14 +49,10 @@ spec:
|
|||||||
python - <<'PY'
|
python - <<'PY'
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import secrets
|
|
||||||
import string
|
|
||||||
import time
|
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
import bcrypt
|
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
|
||||||
VAULT_ADDR = os.environ.get("VAULT_ADDR", "http://vault.vault.svc.cluster.local:8200").rstrip("/")
|
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"},
|
headers={"X-Vault-Token": token, "Content-Type": "application/json"},
|
||||||
method="POST",
|
method="POST",
|
||||||
)
|
)
|
||||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||||
resp.read()
|
resp.read()
|
||||||
|
|
||||||
def random_password(length: int = 32) -> str:
|
|
||||||
alphabet = string.ascii_letters + string.digits
|
|
||||||
return "".join(secrets.choice(alphabet) for _ in range(length))
|
|
||||||
|
|
||||||
def ensure_admin_creds(token: str) -> dict:
|
def ensure_admin_creds(token: str) -> dict:
|
||||||
data = vault_get(token, "comms/synapse-admin")
|
data = vault_get(token, "comms/synapse-admin")
|
||||||
username = (data.get("username") or "").strip() or "synapse-admin"
|
username = (data.get("username") or "").strip() or "othrys-seeder"
|
||||||
password = (data.get("password") or "").strip()
|
|
||||||
if not password:
|
|
||||||
password = random_password()
|
|
||||||
data["username"] = username
|
data["username"] = username
|
||||||
data["password"] = password
|
|
||||||
vault_put(token, "comms/synapse-admin", data)
|
vault_put(token, "comms/synapse-admin", data)
|
||||||
return 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):
|
def get_cols(cur):
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
@ -174,33 +135,6 @@ spec:
|
|||||||
}
|
}
|
||||||
return cols
|
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:
|
def admin_token_valid(token: str, user_id: str) -> bool:
|
||||||
if not token or not SYNAPSE_ADMIN_URL:
|
if not token or not SYNAPSE_ADMIN_URL:
|
||||||
return False
|
return False
|
||||||
@ -242,15 +176,24 @@ spec:
|
|||||||
user=PGUSER,
|
user=PGUSER,
|
||||||
password=pg_password,
|
password=pg_password,
|
||||||
)
|
)
|
||||||
token_value = f"syt_{secrets.token_urlsafe(32)}"
|
|
||||||
device_id = "ariadne-admin"
|
|
||||||
try:
|
try:
|
||||||
with conn:
|
with conn:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cols = get_cols(cur)
|
cols = get_cols(cur)
|
||||||
ensure_user(cur, cols, user_id, admin_data["password"], True)
|
if "admin" not in cols:
|
||||||
ensure_device(cur, user_id, device_id)
|
raise RuntimeError("users.admin column missing")
|
||||||
ensure_access_token(cur, user_id, token_value)
|
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:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user