diff --git a/app/main.py b/app/main.py index 12183d6..5be4e12 100644 --- a/app/main.py +++ b/app/main.py @@ -973,20 +973,33 @@ async def sync_matrix_space() -> dict: 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="") + # Retire BOTH joined and invite-state local accounts: a stale invite + # leaves the local account visible in the user directory and + # accept-able from a lingering client notification, which defeats + # the one-identity rule. Revoke invites via state-event membership + # (kick 403s on invite-state users). + for room in [MATRIX_SPACE_ID] + ([MATRIX_GENERAL_ROOM] if MATRIX_GENERAL_ROOM else []): + enc_room = urllib.parse.quote(room, safe="") + if local_mxid in joined: 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) + retired += 1 + logger.info("Matrix sync: retired local account %s (member uses %s)", local_mxid, ext_mxid) + elif local_mxid in invited: + await client.put( + f"{MATRIX_HOMESERVER}/_matrix/client/v3/rooms/{enc_room}/state/m.room.member/{urllib.parse.quote(local_mxid, safe='')}", + headers=H, + json={"membership": "leave", + "reason": f"This co-op account is superseded by {ext_mxid} (set on your dashboard)"}, + ) + retired += 1 + logger.info("Matrix sync: revoked stale invite for local account %s (member uses %s)", local_mxid, ext_mxid) if retired: - logger.info("Matrix sync: retired %s local account(s)", retired) + logger.info("Matrix sync: retired %s local account(s)/invite(s)", retired) return {"invited": invited_count}