Files
logbuch/lib/session.ts
Reinhard X. Fürst a0fb6d8089 Various UX improvements and bug fixes
- Fix mustChangePassword session flag for users with pw=NULL
- Add PrF (Private Führung) as new ArtFuehrung type
- Split datetime-local into separate date + TimePicker5 (5-min steps, auto-repeat)
- Responsive Beginn/Ende layout: stacked on mobile, inline on desktop
- Sort BEOs alphabetically by Kürzel in selector
- Title shows active kuppel; hide user display in header
- Selected BEOs show Kürzel only (name stays in dropdown)
- Session timeout reduced to 1 hour
- Add CLAUDE.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 18:02:47 +02:00

63 lines
1.9 KiB
TypeScript

import { cookies } from 'next/headers';
import { SignJWT, jwtVerify } from 'jose';
const SESSION_COOKIE_NAME = 'logbuch_session';
const SESSION_DURATION = 60 * 60 * 1000;
const secretKey = process.env.AUTH_SECRET || 'logbuch-secret-change-in-production';
const key = new TextEncoder().encode(secretKey);
export interface SessionData {
kuerzel: string;
beoId: number;
beoName: string;
mustChangePassword: boolean;
isAuthenticated: boolean;
expiresAt: number;
}
async function encrypt(payload: SessionData): Promise<string> {
return new SignJWT(payload as unknown as Record<string, unknown>)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime(new Date(payload.expiresAt))
.sign(key);
}
async function decrypt(token: string): Promise<SessionData | null> {
try {
const { payload } = await jwtVerify(token, key, { algorithms: ['HS256'] });
return payload as unknown as SessionData;
} catch {
return null;
}
}
export async function createSession(data: Omit<SessionData, 'expiresAt'>): Promise<void> {
const expiresAt = Date.now() + SESSION_DURATION;
const session: SessionData = { ...data, expiresAt };
const encrypted = await encrypt(session);
const cookieStore = await cookies();
cookieStore.set(SESSION_COOKIE_NAME, encrypted, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
expires: expiresAt,
sameSite: 'lax',
path: '/',
});
}
export async function getSession(): Promise<SessionData | null> {
const cookieStore = await cookies();
const cookie = cookieStore.get(SESSION_COOKIE_NAME);
if (!cookie?.value) return null;
const session = await decrypt(cookie.value);
if (!session || session.expiresAt < Date.now()) return null;
return session;
}
export async function deleteSession(): Promise<void> {
const cookieStore = await cookies();
cookieStore.delete(SESSION_COOKIE_NAME);
}