transient.chat/blueprints/chat.py

198 lines
5.9 KiB
Python
Raw Normal View History

2026-05-12 23:50:49 +00:00
from flask import Blueprint, request, jsonify
from datetime import datetime, timezone
import time
from models.state import (
messages,
room_users,
kicked_users,
room_owners,
banned_ips,
banned_usernames,
user_ips,
nuked_rooms,
)
chat_bp = Blueprint("chat", __name__)
@chat_bp.route("/chat", methods=["GET", "POST"])
def general_chat():
if request.method == "POST":
new_message = request.json.get("message")
if new_message:
messages.setdefault("global", []).append(
{"text": new_message, "timestamp": datetime.now(timezone.utc).isoformat()}
)
if len(messages["global"]) > 100:
messages["global"] = messages["global"][-100:]
return jsonify(messages.get("global", []))
@chat_bp.route("/chat/<room>", methods=["GET", "POST"])
def chat_room(room):
room = room.strip()
if request.method == "POST":
data = request.json
username = data.get("username")
text = data.get("text")
audio = data.get("audio")
user_ip = request.remote_addr
if (
user_ip in banned_ips
or username in banned_usernames
or (username in user_ips and user_ips[username] in banned_ips)
):
return jsonify({"error": "banned"}), 403
message = {
"username": username,
"text": text,
"audio": audio,
"timestamp": datetime.now(timezone.utc).isoformat(),
}
if "encrypted" in data:
message["encrypted"] = data["encrypted"]
if "iv" in data:
message["iv"] = data["iv"]
if "keyId" in data:
message["keyId"] = data["keyId"]
2026-05-12 23:50:49 +00:00
messages.setdefault(room, []).append(message)
if len(messages[room]) > 100:
messages[room] = messages[room][-100:]
since = request.args.get("since")
room_messages = messages.setdefault(room, [])
if since:
try:
since_time = datetime.fromisoformat(since)
new_msgs = [
m
for m in room_messages
if datetime.fromisoformat(m["timestamp"]) > since_time
]
return jsonify(new_msgs)
except ValueError:
pass # Ignore bad timestamp
return jsonify(room_messages)
@chat_bp.route("/chat/<room>/users", methods=["GET", "POST"])
def room_user_list(room):
room = room.strip()
# Check if room is temporarily locked (nuked)
if room in nuked_rooms:
if time.time() < nuked_rooms[room]:
return jsonify({"error": "Room is unavailable"}), 403
else:
nuked_rooms.pop(room, None)
if request.method == "POST":
data = request.json
username = data.get("username")
if not username:
return jsonify({"error": "No username"}), 400
if username in kicked_users.get(room, set()):
return jsonify({"error": "Kicked from room"}), 403
room_users.setdefault(room, {})
if room not in room_owners and username not in room_users[room]:
room_owners[room] = username # First user becomes the owner
from models.database import db_set_room_owner
db_set_room_owner(room, username)
2026-05-12 23:50:49 +00:00
room_users[room][username] = datetime.now(timezone.utc).isoformat()
users = room_users.get(room, {})
response = {"users": list(users.keys())}
if room in room_owners:
response["owner"] = room_owners[room]
return jsonify(response)
@chat_bp.route("/chat/<room>/kick", methods=["POST"])
def kick_user(room):
data = request.json
owner = data.get("owner")
target = data.get("target")
if not owner or not target:
return jsonify({"error": "Missing owner or target"}), 400
if room_owners.get(room) != owner:
return jsonify({"error": "Not authorized"}), 403
kicked_users.setdefault(room, set()).add(target)
room_users.get(room, {}).pop(target, None)
return jsonify({"kicked": target})
@chat_bp.route("/chat/<room>/poll", methods=["POST"])
def poll_room(room):
room = room.strip()
data = request.json or {}
username = data.get("username")
key = data.get("key")
since = data.get("since")
from blueprints.auth import verify_user_key
if not username or not key or not verify_user_key(username, key):
return jsonify({"error": "Invalid credentials"}), 403
# Check if room is temporarily locked (nuked)
if room in nuked_rooms:
if time.time() < nuked_rooms[room]:
return jsonify({"error": "Room is unavailable"}), 403
else:
nuked_rooms.pop(room, None)
if username in kicked_users.get(room, set()):
return jsonify({"error": "Kicked from room"}), 403
# Update user presence
room_users.setdefault(room, {})
if room not in room_owners and username not in room_users[room]:
room_owners[room] = username
from models.database import db_set_room_owner
db_set_room_owner(room, username)
room_users[room][username] = datetime.now(timezone.utc).isoformat()
# Restore active user session in-memory if lost on restart
from models.state import user_sessions
user_sessions[username] = {
"key": key,
"last_active": datetime.now(timezone.utc).isoformat(),
}
# Fetch messages
room_messages = messages.setdefault(room, [])
filtered_messages = room_messages
if since:
try:
since_time = datetime.fromisoformat(since)
filtered_messages = [
m
for m in room_messages
if datetime.fromisoformat(m["timestamp"]) > since_time
]
except ValueError:
pass
users_list = room_users.get(room, {})
response = {
"messages": filtered_messages,
"users": list(users_list.keys())
}
if room in room_owners:
response["owner"] = room_owners[room]
return jsonify(response)