81 lines
2.0 KiB
TypeScript
81 lines
2.0 KiB
TypeScript
import { cookies } from "next/headers";
|
|
import { SignJWT, jwtVerify } from "jose";
|
|
import bcrypt from "bcryptjs";
|
|
import { prisma } from "./db";
|
|
|
|
const SESSION_COOKIE_NAME = "ftp_session";
|
|
const SESSION_MAX_AGE = 60 * 60 * 24 * 7; // 7 days
|
|
|
|
type SessionPayload = {
|
|
userId: string;
|
|
email: string;
|
|
};
|
|
|
|
function getJwtSecret() {
|
|
const secret = process.env.JWT_SECRET;
|
|
if (!secret) {
|
|
throw new Error("JWT_SECRET is not set");
|
|
}
|
|
return new TextEncoder().encode(secret);
|
|
}
|
|
|
|
export async function hashPassword(password: string) {
|
|
return bcrypt.hash(password, 10);
|
|
}
|
|
|
|
export async function verifyPassword(password: string, hash: string) {
|
|
return bcrypt.compare(password, hash);
|
|
}
|
|
|
|
export async function createSessionToken(payload: SessionPayload) {
|
|
const secret = getJwtSecret();
|
|
return new SignJWT(payload)
|
|
.setProtectedHeader({ alg: "HS256" })
|
|
.setIssuedAt()
|
|
.setExpirationTime(`${SESSION_MAX_AGE}s`)
|
|
.sign(secret);
|
|
}
|
|
|
|
export async function verifySessionToken(token: string) {
|
|
try {
|
|
const { payload } = await jwtVerify<SessionPayload>(token, getJwtSecret());
|
|
return payload;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export async function setSessionCookie(token: string) {
|
|
const store = await cookies();
|
|
store.set(SESSION_COOKIE_NAME, token, {
|
|
httpOnly: true,
|
|
sameSite: "lax",
|
|
secure: process.env.NODE_ENV === "production",
|
|
path: "/",
|
|
maxAge: SESSION_MAX_AGE,
|
|
});
|
|
}
|
|
|
|
export async function clearSessionCookie() {
|
|
const store = await cookies();
|
|
store.delete(SESSION_COOKIE_NAME);
|
|
}
|
|
|
|
export async function getSessionUser() {
|
|
const store = await cookies();
|
|
const token = store.get(SESSION_COOKIE_NAME)?.value;
|
|
if (!token) return null;
|
|
const payload = await verifySessionToken(token);
|
|
if (!payload) return null;
|
|
return payload;
|
|
}
|
|
|
|
export async function getCurrentUserRecord() {
|
|
const session = await getSessionUser();
|
|
if (!session) return null;
|
|
return prisma.user.findUnique({ where: { id: session.userId } });
|
|
}
|
|
|
|
export { SESSION_COOKIE_NAME, SESSION_MAX_AGE };
|
|
|