import argon2 from "argon2"; import jwt from "jsonwebtoken"; import type { User, Session } from "../../generated/prisma/client.js"; import { getDB } from "../../store/store.js"; import type { IUserLogin, IUserRegistration } from "./types.js"; import { getJwtSecret } from "./helpers.js"; const registerUser = async ( registration: IUserRegistration, ): Promise => { const existingUserUsername = await getDB().user.findUnique({ where: { username: registration.username }, }); if (existingUserUsername) { return null; } if (registration.email) { const existingUserEmail = await getDB().user.findUnique({ where: { email: registration.email }, }); if (existingUserEmail) { return null; } } const passwordHash = await hashPassword(registration.password); let newUser: User | null = null; try { newUser = await getDB().user.create({ data: { username: registration.username, passwordHash: passwordHash, email: registration.email ?? null, }, }); } catch { return null; } return newUser; }; const loginUser = async (login: IUserLogin): Promise => { const user = await getDB().user.findUnique({ where: { username: login.username }, }); if (!user || !user.passwordHash) { return null; } const passwordCorrect = await argon2.verify( user.passwordHash, login.password, ); if (!passwordCorrect) { return null; } await getDB().user.update({ data: { lastLogin: new Date(), }, where: { id: user.id, }, }); return await getDB().session.create({ data: { token: createToken(user.id), userId: user.id, }, }); }; const hashPassword = async (password: string): Promise => { return await argon2.hash(password, { type: argon2.argon2id, memoryCost: 2 ** 16, timeCost: 4, parallelism: 1, }); }; const createToken = (userId: string) => { return jwt.sign({ sub: userId }, getJwtSecret()); }; export { registerUser, loginUser, hashPassword };