This commit is contained in:
ProgrammGamer
2026-07-26 12:03:57 +02:00
commit edf9514bc3
50 changed files with 9918 additions and 0 deletions
+87
View File
@@ -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 };
}