Update app.py

This commit is contained in:
2026-05-05 21:02:28 +02:00
parent 2d538d6542
commit de9aeb64cc
+27 -25
View File
@@ -61,16 +61,14 @@ class Config:
log_level = logging.DEBUG if os.getenv("DEBUG", "false").lower() == "true" else logging.INFO log_level = logging.DEBUG if os.getenv("DEBUG", "false").lower() == "true" else logging.INFO
logging.basicConfig( logging.basicConfig(level=log_level, format="%(message)s")
level=log_level,
format="%(message)s"
)
logging.getLogger("werkzeug").setLevel(logging.ERROR) logging.getLogger("werkzeug").setLevel(logging.ERROR)
logging.getLogger("urllib3").setLevel(logging.WARNING) logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.getLogger("gunicorn.access").setLevel(logging.WARNING) logging.getLogger("gunicorn.access").setLevel(logging.WARNING)
logger = logging.getLogger("matrix-interceptor") logger = logging.getLogger("matrix-interceptor")
logger.propagate = False
def now_iso(): def now_iso():
return datetime.now(timezone.utc).isoformat() return datetime.now(timezone.utc).isoformat()
@@ -80,10 +78,6 @@ def log_event(event: str, **kwargs):
details = " ".join(f"{k}={v}" for k, v in kwargs.items()) details = " ".join(f"{k}={v}" for k, v in kwargs.items())
logger.info(f"{base} {details}") logger.info(f"{base} {details}")
def debug_log(title, data):
if config.debug:
logger.debug(f"{title}: {json.dumps(data, default=str)}")
# ============================================================ # ============================================================
# INIT # INIT
# ============================================================ # ============================================================
@@ -102,7 +96,9 @@ if missing:
KNOWN_EXTERNAL_USERS = {} KNOWN_EXTERNAL_USERS = {}
RATE_LIMIT = defaultdict(list) RATE_LIMIT = defaultdict(list)
METRICS = defaultdict(int) METRICS = defaultdict(int)
METRICS_LOCK = Lock() METRICS_LOCK = Lock()
CACHE_LOCK = Lock()
CACHE_FILE = "/app/cache/known_users.json" CACHE_FILE = "/app/cache/known_users.json"
CACHE_DIRTY = False CACHE_DIRTY = False
@@ -114,19 +110,19 @@ CACHE_DIRTY = False
def load_cache(): def load_cache():
global KNOWN_EXTERNAL_USERS global KNOWN_EXTERNAL_USERS
os.makedirs(os.path.dirname(CACHE_FILE), exist_ok=True)
if os.path.exists(CACHE_FILE): if os.path.exists(CACHE_FILE):
try: try:
with open(CACHE_FILE, "r") as f: with open(CACHE_FILE, "r") as f:
KNOWN_EXTERNAL_USERS = json.load(f) KNOWN_EXTERNAL_USERS = json.load(f)
logger.info(f"Loaded cache with {len(KNOWN_EXTERNAL_USERS)} users") logger.info(f"Loaded cache with {len(KNOWN_EXTERNAL_USERS)} users")
except Exception as e: except Exception:
logger.error(f"Cache load failed: {e}")
KNOWN_EXTERNAL_USERS = {} KNOWN_EXTERNAL_USERS = {}
else: else:
os.makedirs(os.path.dirname(CACHE_FILE), exist_ok=True)
with open(CACHE_FILE, "w") as f: with open(CACHE_FILE, "w") as f:
json.dump({}, f) json.dump({}, f)
logger.info("Initialized empty cache") logger.info("Initialized empty cache file")
def save_cache(): def save_cache():
global CACHE_DIRTY global CACHE_DIRTY
@@ -135,10 +131,11 @@ def save_cache():
return return
try: try:
os.makedirs(os.path.dirname(CACHE_FILE), exist_ok=True) with CACHE_LOCK:
with open(CACHE_FILE, "w") as f: os.makedirs(os.path.dirname(CACHE_FILE), exist_ok=True)
json.dump(KNOWN_EXTERNAL_USERS, f) with open(CACHE_FILE, "w") as f:
CACHE_DIRTY = False json.dump(KNOWN_EXTERNAL_USERS, f)
CACHE_DIRTY = False
except Exception as e: except Exception as e:
logger.error(f"Failed to save cache: {e}") logger.error(f"Failed to save cache: {e}")
@@ -167,6 +164,8 @@ def is_known_user(user_id):
if time.time() - ts > config.cache_ttl: if time.time() - ts > config.cache_ttl:
del KNOWN_EXTERNAL_USERS[user_id] del KNOWN_EXTERNAL_USERS[user_id]
global CACHE_DIRTY
CACHE_DIRTY = True
return False return False
return True return True
@@ -175,7 +174,7 @@ def remember_user(user_id):
global CACHE_DIRTY global CACHE_DIRTY
KNOWN_EXTERNAL_USERS[user_id] = time.time() KNOWN_EXTERNAL_USERS[user_id] = time.time()
CACHE_DIRTY = True CACHE_DIRTY = True
save_cache() # 🔥 critical safety write save_cache()
def is_local_room(room_id): def is_local_room(room_id):
try: try:
@@ -187,20 +186,19 @@ def get_role(user_id):
return "admin" if user_id in config.admin_users else "user" return "admin" if user_id in config.admin_users else "user"
# ============================================================ # ============================================================
# RATE LIMIT # RATE LIMIT (FIXED)
# ============================================================ # ============================================================
def is_rate_limited(domain): def is_rate_limited(domain, sender):
key = f"{domain}:{sender}"
now = time.time() now = time.time()
RATE_LIMIT[domain] = [ RATE_LIMIT[key] = [t for t in RATE_LIMIT[key] if now - t < 60]
t for t in RATE_LIMIT[domain] if now - t < 60
]
if len(RATE_LIMIT[domain]) >= config.rate_limit_per_minute: if len(RATE_LIMIT[key]) >= config.rate_limit_per_minute:
return True return True
RATE_LIMIT[domain].append(now) RATE_LIMIT[key].append(now)
return False return False
# ============================================================ # ============================================================
@@ -393,11 +391,13 @@ def invite(room_id, event_id):
domain = extract_domain(sender) domain = extract_domain(sender)
if is_rate_limited(domain): if is_rate_limited(domain, sender):
return Response(status=429) return Response(status=429)
if domain in config.domain_whitelist: if domain in config.domain_whitelist:
remember_user(sender) remember_user(sender)
with METRICS_LOCK:
METRICS["invite_allowed"] += 1
return forward_request( return forward_request(
"PUT", "PUT",
f"{config.tuwunel_url}/_matrix/federation/v2/invite/{room_id}/{event_id}", f"{config.tuwunel_url}/_matrix/federation/v2/invite/{room_id}/{event_id}",
@@ -413,6 +413,8 @@ def invite(room_id, event_id):
if is_user_in_local_rooms(sender): if is_user_in_local_rooms(sender):
remember_user(sender) remember_user(sender)
with METRICS_LOCK:
METRICS["invite_allowed"] += 1
return forward_request( return forward_request(
"PUT", "PUT",
f"{config.tuwunel_url}/_matrix/federation/v2/invite/{room_id}/{event_id}", f"{config.tuwunel_url}/_matrix/federation/v2/invite/{room_id}/{event_id}",