import { createUser, findUserByUsername, validatePassword, createSession, createGuestSession, deleteSession, getUserPermissions, getAllUsers, grantPermission, revokePermission, } from "../db"; import { getUser, requirePermission, setSessionCookie, clearSessionCookie, getClientInfo, } from "../auth"; import { config } from "../config"; import { state } from "../state"; import { getOrCreateUser, userHasPermission } from "./helpers"; // Auth: signup export async function handleSignup(req: Request, server: any): Promise { try { const { username, password } = await req.json(); if (!username || !password) { return Response.json({ error: "Username and password required" }, { status: 400 }); } if (username.length < 3 || password.length < 6) { return Response.json({ error: "Username min 3 chars, password min 6 chars" }, { status: 400 }); } const existing = findUserByUsername(username); if (existing) { return Response.json({ error: "Username already taken" }, { status: 400 }); } const user = await createUser(username, password); const userAgent = req.headers.get("user-agent") ?? undefined; const ipAddress = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? server.requestIP(req)?.address ?? undefined; const token = createSession(user.id, userAgent, ipAddress); console.log(`[AUTH] Signup: user="${username}" id=${user.id} admin=${user.is_admin} session=${token} ip=${ipAddress} ua="${userAgent?.slice(0, 50)}..."`); state.library.logActivity("account_created", { title: user.is_admin ? "admin" : "user" }, { id: user.id, username: user.username }); return Response.json( { user: { id: user.id, username: user.username, isAdmin: user.is_admin } }, { headers: { "Set-Cookie": setSessionCookie(token) } } ); } catch (e) { return Response.json({ error: "Signup failed" }, { status: 500 }); } } // Auth: login export async function handleLogin(req: Request, server: any): Promise { try { const { username, password } = await req.json(); const user = findUserByUsername(username); if (!user || !(await validatePassword(user, password))) { console.log(`[AUTH] Login failed: user="${username}"`); return Response.json({ error: "Invalid username or password" }, { status: 401 }); } const userAgent = req.headers.get("user-agent") ?? undefined; const ipAddress = req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? server.requestIP(req)?.address ?? undefined; const token = createSession(user.id, userAgent, ipAddress); console.log(`[AUTH] Login: user="${username}" id=${user.id} session=${token} ip=${ipAddress} ua="${userAgent?.slice(0, 50)}..."`); return Response.json( { user: { id: user.id, username: user.username, isAdmin: user.is_admin } }, { headers: { "Set-Cookie": setSessionCookie(token) } } ); } catch (e) { return Response.json({ error: "Login failed" }, { status: 500 }); } } // Auth: logout export function handleLogout(req: Request): Response { const token = req.headers.get("cookie")?.match(/blastoise_session=([^;]+)/)?.[1]; if (token) { const { validateSession } = require("../db"); const user = validateSession(token); console.log(`[AUTH] Logout: user="${user?.username ?? "unknown"}" session=${token}`); deleteSession(token); } return Response.json( { success: true }, { headers: { "Set-Cookie": clearSessionCookie() } } ); } // Auth: get current user export function handleGetMe(req: Request, server: any): Response { const { user, headers } = getOrCreateUser(req, server); if (!user) { return Response.json({ user: null }); } const permissions = getUserPermissions(user.id); const effectivePermissions = [...permissions]; if (config.defaultPermissions) { for (const perm of config.defaultPermissions) { if (user.is_guest && perm === "control") continue; effectivePermissions.push({ id: 0, user_id: user.id, resource_type: "channel", resource_id: null, permission: perm, }); } } return Response.json({ user: { id: user.id, username: user.username, isAdmin: user.is_admin, isGuest: user.is_guest }, permissions: effectivePermissions, }, { headers }); } // Kick all other clients for current user export function handleKickOthers(req: Request, server: any): Response { const { user } = getOrCreateUser(req, server); if (!user) { return Response.json({ error: "Not authenticated" }, { status: 401 }); } const connections = state.userConnections.get(user.id); if (!connections || connections.size === 0) { return Response.json({ kicked: 0 }); } let kickedCount = 0; for (const ws of connections) { ws.send(JSON.stringify({ type: "kick", reason: "Kicked by another session" })); kickedCount++; } console.log(`[Kick] User ${user.username} kicked ${kickedCount} other clients`); return Response.json({ kicked: kickedCount }); } // Admin: list users export function handleListUsers(req: Request, server: any): Response { try { requirePermission(req, "global", null, "admin", server); return Response.json(getAllUsers()); } catch (e) { if (e instanceof Response) return e; return Response.json({ error: "Failed" }, { status: 500 }); } } // Admin: grant permission export async function handleGrantPermission(req: Request, server: any, userId: number): Promise { try { requirePermission(req, "global", null, "admin", server); const { resourceType, resourceId, permission } = await req.json(); grantPermission(userId, resourceType, resourceId, permission); return Response.json({ success: true }); } catch (e) { if (e instanceof Response) return e; return Response.json({ error: "Failed" }, { status: 500 }); } } // Admin: revoke permission export async function handleRevokePermission(req: Request, server: any, userId: number): Promise { try { requirePermission(req, "global", null, "admin", server); const { resourceType, resourceId, permission } = await req.json(); revokePermission(userId, resourceType, resourceId, permission); return Response.json({ success: true }); } catch (e) { if (e instanceof Response) return e; return Response.json({ error: "Failed" }, { status: 500 }); } }