import { SignJWT, jwtVerify } from 'jose' import { cookies } from 'next/headers' import { prisma } from './db' import bcrypt from 'bcryptjs' const secretValue = process.env.NEXTAUTH_SECRET if (!secretValue || secretValue.length < 32) { console.warn('[AUTH] WARNING: NEXTAUTH_SECRET is missing or too short (<32 chars). Set a strong secret in production!') } const JWT_SECRET = new TextEncoder().encode( secretValue || 'dev-only-fallback-do-not-use-in-production-' + Date.now() ) export interface UserPayload { id: string email: string name: string role: 'SERVER_ADMIN' | 'TENANT_ADMIN' | 'OPERATOR' | 'VIEWER' tenantId?: string tenantSlug?: string emailVerified?: boolean } export async function createToken(user: UserPayload, rememberMe = false): Promise { return await new SignJWT({ user }) .setProtectedHeader({ alg: 'HS256' }) .setIssuedAt() .setExpirationTime(rememberMe ? '30d' : '24h') .sign(JWT_SECRET) } export async function verifyToken(token: string): Promise { try { const { payload } = await jwtVerify(token, JWT_SECRET) return payload.user as UserPayload } catch { return null } } export async function getSession(): Promise { const cookieStore = await cookies() const token = cookieStore.get('auth-token')?.value if (!token) return null return await verifyToken(token) } export async function login( email: string, password: string ): Promise<{ success: boolean; user?: UserPayload; error?: string }> { const user = await (prisma.user.findUnique({ where: { email }, select: { id: true, email: true, name: true, password: true, role: true, emailVerified: true, }, }) as any) if (!user) { return { success: false, error: 'E-Mail oder Passwort falsch' } } const isValidPassword = await bcrypt.compare(password, user.password) if (!isValidPassword) { return { success: false, error: 'E-Mail oder Passwort falsch' } } // Track email verification status (allow login regardless) const emailVerified = (user as any).emailVerified !== false // Get first tenant membership for non-server-admins let tenantId: string | undefined let tenantSlug: string | undefined if ((user.role as string) !== 'SERVER_ADMIN') { const membership = await (prisma as any).tenantMembership.findFirst({ where: { userId: user.id }, include: { tenant: true }, orderBy: { createdAt: 'asc' }, }) if (membership) { // Check if tenant is active if (!membership.tenant.isActive) { return { success: false, error: 'Ihr Mandant wurde gesperrt. Bitte kontaktieren Sie den Administrator.' } } tenantId = membership.tenantId tenantSlug = membership.tenant.slug } } const userPayload: UserPayload = { id: user.id, email: user.email, name: user.name, role: (user.role === 'ADMIN' ? 'SERVER_ADMIN' : user.role) as UserPayload['role'], tenantId, tenantSlug, emailVerified, } return { success: true, user: userPayload } } export async function hashPassword(password: string): Promise { return await bcrypt.hash(password, 12) } export function canEdit(role: string): boolean { return role === 'SERVER_ADMIN' || role === 'TENANT_ADMIN' || role === 'OPERATOR' } export function isAdmin(role: string): boolean { return role === 'SERVER_ADMIN' || role === 'TENANT_ADMIN' } export function isServerAdmin(role: string): boolean { return role === 'SERVER_ADMIN' } export function isTenantAdmin(role: string): boolean { return role === 'TENANT_ADMIN' }