Init
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { compareSync } from "bcryptjs";
|
||||
import { jwtVerify, SignJWT } from "jose";
|
||||
import { cookies } from "next/headers";
|
||||
import { redirect } from "next/navigation";
|
||||
import { db, initDatabase } from "./db";
|
||||
import { getAuthSecret } from "./env";
|
||||
import type { SessionUser, UserRole } from "./types";
|
||||
|
||||
type SessionPayload = {
|
||||
id: number;
|
||||
exp: number;
|
||||
};
|
||||
|
||||
export const SESSION_COOKIE = "moped_session";
|
||||
const SESSION_TTL_SECONDS = 60 * 60 * 24 * 30;
|
||||
|
||||
function getSecretKey() {
|
||||
return new TextEncoder().encode(getAuthSecret());
|
||||
}
|
||||
|
||||
export async function signSession(user: SessionUser) {
|
||||
return new SignJWT({ id: user.id })
|
||||
.setProtectedHeader({ alg: "HS256" })
|
||||
.setIssuedAt()
|
||||
.setExpirationTime(`${SESSION_TTL_SECONDS}s`)
|
||||
.sign(getSecretKey());
|
||||
}
|
||||
|
||||
export async function setSessionCookie(user: SessionUser) {
|
||||
const token = await signSession(user);
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set(SESSION_COOKIE, token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "lax",
|
||||
maxAge: SESSION_TTL_SECONDS,
|
||||
path: "/",
|
||||
priority: "high",
|
||||
});
|
||||
}
|
||||
|
||||
export async function clearSessionCookie() {
|
||||
(await cookies()).delete(SESSION_COOKIE);
|
||||
}
|
||||
|
||||
export async function getSessionUser(): Promise<SessionUser | null> {
|
||||
const token = (await cookies()).get(SESSION_COOKIE)?.value;
|
||||
if (!token) return null;
|
||||
|
||||
try {
|
||||
const result = await jwtVerify(token, getSecretKey());
|
||||
const payload = result.payload as unknown as SessionPayload;
|
||||
initDatabase();
|
||||
const user = db
|
||||
.prepare("SELECT id, name, email, role FROM users WHERE id = ?")
|
||||
.get(Number(payload.id)) as
|
||||
| { id: number; name: string; email: string; role: UserRole }
|
||||
| undefined;
|
||||
return user ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function requireSessionUser() {
|
||||
const user = await getSessionUser();
|
||||
if (!user) redirect("/login");
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function requireAdminUser() {
|
||||
const user = await requireSessionUser();
|
||||
if (user.role !== "admin") redirect("/?error=Nur%20f%C3%BCr%20Administratoren.");
|
||||
return user;
|
||||
}
|
||||
|
||||
export function authenticateUser(email: string, password: string): SessionUser | null {
|
||||
initDatabase();
|
||||
const user = db
|
||||
.prepare("SELECT id, name, email, role, password_hash FROM users WHERE email = ?")
|
||||
.get(email.trim().toLowerCase()) as
|
||||
| (SessionUser & { password_hash: string })
|
||||
| undefined;
|
||||
|
||||
if (!user || !compareSync(password, user.password_hash)) return null;
|
||||
return { id: user.id, name: user.name, email: user.email, role: user.role };
|
||||
}
|
||||
Reference in New Issue
Block a user