101 lines
2.2 KiB
TypeScript
101 lines
2.2 KiB
TypeScript
import bcryptjs from "bcryptjs";
|
|
import { prisma } from "./prisma";
|
|
import { ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
|
|
import { cookies } from "next/headers";
|
|
import { User } from "@prisma/client";
|
|
|
|
/**
|
|
* Hash a password using bcryptjs
|
|
*/
|
|
export async function hashPassword(password: string): Promise<string> {
|
|
const salt = await bcryptjs.genSalt(10);
|
|
return bcryptjs.hash(password, salt);
|
|
}
|
|
|
|
/**
|
|
* Verify a password against its hash
|
|
*/
|
|
export async function verifyPassword(
|
|
password: string,
|
|
hash: string
|
|
): Promise<boolean> {
|
|
return bcryptjs.compare(password, hash);
|
|
}
|
|
|
|
/**
|
|
* Create a session token for a user (30-day expiration)
|
|
*/
|
|
export async function createSession(
|
|
userId: string
|
|
): Promise<{ token: string; expiresAt: Date }> {
|
|
const token = Buffer.from(
|
|
`${userId}:${Date.now()}:${Math.random()}`
|
|
).toString("hex");
|
|
|
|
const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000); // 30 days
|
|
|
|
await prisma.session.create({
|
|
data: {
|
|
token,
|
|
userId,
|
|
expiresAt,
|
|
},
|
|
});
|
|
|
|
return { token, expiresAt };
|
|
}
|
|
|
|
/**
|
|
* Validate a session token and return the associated user
|
|
*/
|
|
export async function validateSession(token: string): Promise<User | null> {
|
|
const session = await prisma.session.findUnique({
|
|
where: { token },
|
|
include: { user: true },
|
|
});
|
|
|
|
if (!session) {
|
|
return null;
|
|
}
|
|
|
|
// Check if session has expired
|
|
if (session.expiresAt < new Date()) {
|
|
await prisma.session.delete({ where: { token } });
|
|
return null;
|
|
}
|
|
|
|
return session.user;
|
|
}
|
|
|
|
/**
|
|
* Delete a session token
|
|
*/
|
|
export async function deleteSession(token: string): Promise<void> {
|
|
await prisma.session.delete({
|
|
where: { token },
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get session from cookies object
|
|
*/
|
|
export async function getSessionFromCookies(
|
|
cookieStore: ReadonlyRequestCookies
|
|
): Promise<User | null> {
|
|
const sessionToken = cookieStore.get("sessionToken")?.value;
|
|
|
|
if (!sessionToken) {
|
|
return null;
|
|
}
|
|
|
|
return validateSession(sessionToken);
|
|
}
|
|
|
|
/**
|
|
* Get the current user from request cookies
|
|
*/
|
|
export async function getCurrentUser(): Promise<User | null> {
|
|
const cookieStore = await cookies();
|
|
return getSessionFromCookies(cookieStore);
|
|
}
|