Matrix sync: retire local @username:inference.coop accounts when a member sets a dashboard MXID (one identity per member)
This commit is contained in:
1 parent
05feed5f24
commit
92e7ddec05
1 file changed
+54
+54
@@ -923,6 +923,10 @@ async def sync_matrix_space() -> dict:
|
|||||||
headers=H)
|
headers=H)
|
||||||
invited = {m["state_key"] for m in r.json().get("chunk", [])} if r.status_code == 200 else set()
|
invited = {m["state_key"] for m in r.json().get("chunk", [])} if r.status_code == 200 else set()
|
||||||
|
|
||||||
|
# One identity per member: when a member sets a dashboard extra MXID,
|
||||||
|
# their auto-generated local account (@username:inference.coop) should
|
||||||
|
# NOT also sit in the Space. Track the desired set, then retire the
|
||||||
|
# local accounts of members whose dashboard MXID replaced them.
|
||||||
invited_count = 0
|
invited_count = 0
|
||||||
async for email, mxid in matrix_member_mxids(client):
|
async for email, mxid in matrix_member_mxids(client):
|
||||||
if not mxid or mxid in joined or mxid in invited:
|
if not mxid or mxid in joined or mxid in invited:
|
||||||
@@ -933,6 +937,56 @@ async def sync_matrix_space() -> dict:
|
|||||||
invited_count += 1
|
invited_count += 1
|
||||||
if invited_count:
|
if invited_count:
|
||||||
logger.info("Matrix space invites sent: %s", invited_count)
|
logger.info("Matrix space invites sent: %s", invited_count)
|
||||||
|
|
||||||
|
# Retire local accounts: for each member with a dashboard-set external
|
||||||
|
# MXID, kick their @username:inference.coop account if it's currently
|
||||||
|
# in the Space. Only ever touches accounts derived from that member's
|
||||||
|
# own Cloudron username — never other members' or federated accounts.
|
||||||
|
conn = get_db()
|
||||||
|
rows = conn.execute(
|
||||||
|
"SELECT email, matrix_mxid FROM members WHERE active = 1 AND matrix_mxid IS NOT NULL AND matrix_mxid != ''"
|
||||||
|
).fetchall()
|
||||||
|
conn.close()
|
||||||
|
users: dict[str, str] = {}
|
||||||
|
page = 1
|
||||||
|
async with httpx.AsyncClient(timeout=30) as uc:
|
||||||
|
while True:
|
||||||
|
r = await uc.get(
|
||||||
|
f"{CLOUDRON_API}/api/v1/users",
|
||||||
|
params={"page": page},
|
||||||
|
headers=cloudron_headers(),
|
||||||
|
)
|
||||||
|
if r.status_code != 200:
|
||||||
|
break
|
||||||
|
batch = r.json().get("users", [])
|
||||||
|
for u in batch:
|
||||||
|
if u.get("email") and u.get("username"):
|
||||||
|
users[u["email"].lower()] = u["username"]
|
||||||
|
if len(batch) < 25:
|
||||||
|
break
|
||||||
|
page += 1
|
||||||
|
retired = 0
|
||||||
|
for email, ext_mxid in rows:
|
||||||
|
username = users.get(email.lower())
|
||||||
|
if not username:
|
||||||
|
continue
|
||||||
|
local_mxid = f"@{username}:inference.coop"
|
||||||
|
if local_mxid == ext_mxid:
|
||||||
|
continue # dashboard MXID IS the local account — nothing to retire
|
||||||
|
if local_mxid in joined:
|
||||||
|
for room in [MATRIX_SPACE_ID] + ([MATRIX_GENERAL_ROOM] if MATRIX_GENERAL_ROOM else []):
|
||||||
|
import urllib.parse
|
||||||
|
enc_room = urllib.parse.quote(room, safe="")
|
||||||
|
await client.post(
|
||||||
|
f"{MATRIX_HOMESERVER}/_matrix/client/v3/rooms/{enc_room}/kick",
|
||||||
|
headers=H,
|
||||||
|
json={"user_id": local_mxid,
|
||||||
|
"reason": f"This co-op account is superseded by {ext_mxid} (set on your dashboard)"},
|
||||||
|
)
|
||||||
|
retired += 1
|
||||||
|
logger.info("Matrix sync: retired local account %s (member uses %s)", local_mxid, ext_mxid)
|
||||||
|
if retired:
|
||||||
|
logger.info("Matrix sync: retired %s local account(s)", retired)
|
||||||
return {"invited": invited_count}
|
return {"invited": invited_count}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user