79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
import { v4 as uuidv4 } from "uuid";
|
|
import bcrypt from "bcryptjs";
|
|
import { db } from "./db";
|
|
import { users, sessions } from "./db/schema";
|
|
import { eq, and } from "drizzle-orm";
|
|
import { cookies } from "next/headers";
|
|
|
|
const SESSION_COOKIE = "barabingo_session";
|
|
const SESSION_DAYS = 7;
|
|
|
|
export async function hashPassword(password: string): Promise<string> {
|
|
return bcrypt.hash(password, 10);
|
|
}
|
|
|
|
export async function verifyPassword(password: string, hash: string): Promise<boolean> {
|
|
return bcrypt.compare(password, hash);
|
|
}
|
|
|
|
const ADMIN_NICKNAMES = ["admin"];
|
|
|
|
export async function registerUser(nickname: string, password: string) {
|
|
const existing = db.select().from(users).where(eq(users.nickname, nickname)).get();
|
|
if (existing) return { error: "Nickname taken" };
|
|
|
|
const userCount = db.select().from(users).all().length;
|
|
const nicknameLower = nickname.toLowerCase();
|
|
const firstUser = userCount === 0;
|
|
const isAdmin = firstUser || ADMIN_NICKNAMES.includes(nicknameLower);
|
|
|
|
const id = uuidv4();
|
|
const passwordHash = await hashPassword(password);
|
|
const createdAt = new Date().toISOString();
|
|
|
|
db.insert(users).values({ id, nickname, passwordHash, isAdmin, createdAt }).run();
|
|
return { id, nickname, isAdmin };
|
|
}
|
|
|
|
export async function loginUser(nickname: string, password: string) {
|
|
const user = db.select().from(users).where(eq(users.nickname, nickname)).get();
|
|
if (!user) return { error: "User not found" };
|
|
|
|
const valid = await verifyPassword(password, user.passwordHash);
|
|
if (!valid) return { error: "Wrong password" };
|
|
|
|
const sessionId = uuidv4();
|
|
const expiresAt = new Date(Date.now() + SESSION_DAYS * 86400000).toISOString();
|
|
const createdAt = new Date().toISOString();
|
|
|
|
db.insert(sessions).values({ id: sessionId, userId: user.id, expiresAt, createdAt }).run();
|
|
|
|
return { sessionId, user: { id: user.id, nickname: user.nickname, isAdmin: user.isAdmin } };
|
|
}
|
|
|
|
export async function getSession(token?: string) {
|
|
if (!token) return null;
|
|
const session = db.select().from(sessions).where(eq(sessions.id, token)).get();
|
|
if (!session) return null;
|
|
if (new Date(session.expiresAt) < new Date()) {
|
|
db.delete(sessions).where(eq(sessions.id, token)).run();
|
|
return null;
|
|
}
|
|
const user = db.select().from(users).where(eq(users.id, session.userId)).get();
|
|
if (!user) return null;
|
|
return { id: user.id, nickname: user.nickname, isAdmin: user.isAdmin };
|
|
}
|
|
|
|
export async function deleteSession(token: string) {
|
|
db.delete(sessions).where(eq(sessions.id, token)).run();
|
|
}
|
|
|
|
export async function getServerSession() {
|
|
const cookieStore = await cookies();
|
|
const token = cookieStore.get(SESSION_COOKIE)?.value;
|
|
if (!token) return null;
|
|
return getSession(token);
|
|
}
|
|
|
|
export { SESSION_COOKIE };
|