133 lines
4.7 KiB
Python
133 lines
4.7 KiB
Python
import os
|
|
import json
|
|
import yaml
|
|
import httpx
|
|
import logging
|
|
from typing import List, Dict
|
|
from datetime import datetime, timedelta
|
|
|
|
# Setup logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(levelname)s - %(message)s'
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Load paths and config
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
CONFIG_PATH = os.path.join(BASE_DIR, "config.yaml")
|
|
REGISTRATIONS_PATH = os.path.join(BASE_DIR, "registrations.json")
|
|
|
|
def load_config() -> dict:
|
|
"""Load configuration from yaml file."""
|
|
with open(CONFIG_PATH, "r") as f:
|
|
return yaml.safe_load(f)
|
|
|
|
def load_registrations() -> List[Dict]:
|
|
"""Load current registrations from JSON file."""
|
|
try:
|
|
with open(REGISTRATIONS_PATH, "r") as f:
|
|
return json.load(f)
|
|
except (FileNotFoundError, json.JSONDecodeError):
|
|
return []
|
|
|
|
def save_registrations(registrations: List[Dict]):
|
|
"""Save updated registrations back to JSON file."""
|
|
with open(REGISTRATIONS_PATH, "w") as f:
|
|
json.dump(registrations, f, indent=2)
|
|
|
|
async def check_username_exists(username: str, homeserver: str) -> bool:
|
|
"""
|
|
Check if a username exists on the Matrix server.
|
|
Returns True if the username exists, False otherwise.
|
|
"""
|
|
url = f"https://{homeserver}/_matrix/client/v3/register/available?username={username}"
|
|
async with httpx.AsyncClient() as client:
|
|
try:
|
|
response = await client.get(url, timeout=5)
|
|
if response.status_code == 200:
|
|
# 200 OK with available=true means username exists
|
|
return response.json().get("available", False)
|
|
elif response.status_code == 400:
|
|
# 400 Bad Request means username is not available
|
|
return False
|
|
except httpx.RequestError as ex:
|
|
logger.error(f"Error checking username {username}: {ex}")
|
|
return False
|
|
return False
|
|
|
|
async def cleanup_registrations(min_age_hours: int = 24):
|
|
"""
|
|
Clean up registrations by removing entries for usernames that don't exist on the server,
|
|
but only if they're older than min_age_hours.
|
|
|
|
Never removes entries for existing Matrix users regardless of age.
|
|
"""
|
|
config = load_config()
|
|
registrations = load_registrations()
|
|
|
|
if not registrations:
|
|
logger.info("No registrations found to clean up")
|
|
return
|
|
|
|
logger.info(f"Starting cleanup of {len(registrations)} registrations")
|
|
logger.info(f"Will only remove non-existent users registered more than {min_age_hours} hours ago")
|
|
|
|
# Track which entries to keep
|
|
entries_to_keep = []
|
|
removed_count = 0
|
|
too_new_count = 0
|
|
exists_count = 0
|
|
|
|
current_time = datetime.utcnow()
|
|
|
|
for entry in registrations:
|
|
username = entry["requested_name"]
|
|
reg_date = datetime.fromisoformat(entry["datetime"])
|
|
age = current_time - reg_date
|
|
|
|
# First check if the user exists on Matrix
|
|
exists = await check_username_exists(username, config["homeserver"])
|
|
|
|
if exists:
|
|
# Always keep entries for existing Matrix users
|
|
entries_to_keep.append(entry)
|
|
exists_count += 1
|
|
logger.info(f"Keeping registration for existing user: {username}")
|
|
continue
|
|
|
|
# For non-existent users, check if they're old enough to remove
|
|
if age < timedelta(hours=min_age_hours):
|
|
# Keep young entries even if user doesn't exist yet
|
|
entries_to_keep.append(entry)
|
|
too_new_count += 1
|
|
logger.info(f"Keeping recent registration: {username} (age: {age.total_seconds()/3600:.1f} hours)")
|
|
else:
|
|
# Remove old entries where user doesn't exist
|
|
logger.info(f"Removing old registration: {username} (age: {age.total_seconds()/3600:.1f} hours)")
|
|
removed_count += 1
|
|
|
|
# Save updated registrations
|
|
save_registrations(entries_to_keep)
|
|
|
|
logger.info(f"Cleanup complete:")
|
|
logger.info(f"- Kept {exists_count} entries for existing Matrix users")
|
|
logger.info(f"- Kept {too_new_count} entries younger than {min_age_hours} hours")
|
|
logger.info(f"- Removed {removed_count} old entries for non-existent users")
|
|
logger.info(f"- Total remaining entries: {len(entries_to_keep)}")
|
|
|
|
if __name__ == "__main__":
|
|
import asyncio
|
|
import argparse
|
|
|
|
parser = argparse.ArgumentParser(description="Clean up Matrix registration entries")
|
|
parser.add_argument(
|
|
"--min-age-hours",
|
|
type=int,
|
|
default=24,
|
|
help="Minimum age in hours before removing non-existent users (default: 24)"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
asyncio.run(cleanup_registrations(args.min_age_hours))
|