import fs from 'fs'; import path from 'path'; import { User } from './types'; import bcrypt from 'bcryptjs'; import { SignJWT, jwtVerify } from 'jose'; import { cookies } from 'next/headers'; const USERS_FILE = path.join(process.cwd(), 'data', 'users.json'); const SECRET_KEY = new TextEncoder().encode(process.env.JWT_SECRET || 'fallback-secret-key-change-me'); // --- User Management --- export function getUsers(): User[] { if (!fs.existsSync(USERS_FILE)) { fs.writeFileSync(USERS_FILE, JSON.stringify([])); return []; } try { const data = fs.readFileSync(USERS_FILE, 'utf8'); return JSON.parse(data); } catch (e) { return []; } } export function saveUser(user: User) { const users = getUsers(); const existingIndex = users.findIndex(u => u.username === user.username); if (existingIndex >= 0) { users[existingIndex] = user; } else { users.push(user); } fs.writeFileSync(USERS_FILE, JSON.stringify(users, null, 2)); } export function findUser(username: string): User | undefined { return getUsers().find(u => u.username === username); } // --- Security Utils --- export async function hashPassword(password: string): Promise { return await bcrypt.hash(password, 10); } export async function verifyPassword(password: string, hash: string): Promise { return await bcrypt.compare(password, hash); } // --- Session Management (JWT) --- export async function createSession(user: User) { const token = await new SignJWT({ username: user.username, chatId: user.chatId }) .setProtectedHeader({ alg: 'HS256' }) .setExpirationTime('7d') .sign(SECRET_KEY); cookies().set('session', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 60 * 60 * 24 * 7, // 7 days path: '/', }); } export async function verifySession() { const session = cookies().get('session')?.value; if (!session) return null; try { const { payload } = await jwtVerify(session, SECRET_KEY); return payload as { username: string; chatId: string }; } catch (error) { return null; } } export function destroySession() { cookies().delete('session'); }