import { call, os } from "@orpc/server"; import { z } from "zod"; import { randomUUID } from "crypto"; import { createKV } from "@/server/lib/create-kv"; import { config } from "dotenv"; // Load environment variables from .env file config(); const UserSchema = z.object({ id: z.string(), username: z.string().min(3, "Benutzername muss mindestens 3 Zeichen lang sein"), email: z.string().email("Ungültige E-Mail-Adresse"), passwordHash: z.string(), role: z.enum(["customer", "owner"]), createdAt: z.string(), }); const SessionSchema = z.object({ id: z.string(), userId: z.string(), expiresAt: z.string(), createdAt: z.string(), }); type User = z.output; type Session = z.output; const usersKV = createKV("users"); const sessionsKV = createKV("sessions"); // Simple password hashing (in production, use bcrypt or similar) const hashPassword = (password: string): string => { return Buffer.from(password).toString('base64'); }; const verifyPassword = (password: string, hash: string): boolean => { return hashPassword(password) === hash; }; // Export hashPassword for external use (e.g., generating hashes for .env) export const generatePasswordHash = hashPassword; // Initialize default owner account const initializeOwner = async () => { const existingUsers = await usersKV.getAllItems(); if (existingUsers.length === 0) { const ownerId = randomUUID(); // Get admin credentials from environment variables const adminUsername = process.env.ADMIN_USERNAME || "owner"; const adminPasswordHash = process.env.ADMIN_PASSWORD_HASH || hashPassword("admin123"); const adminEmail = process.env.ADMIN_EMAIL || "owner@stargirlnails.de"; const owner: User = { id: ownerId, username: adminUsername, email: adminEmail, passwordHash: adminPasswordHash, role: "owner", createdAt: new Date().toISOString(), }; await usersKV.setItem(ownerId, owner); console.log(`✅ Admin account created: username="${adminUsername}", email="${adminEmail}"`); } }; // Initialize on module load initializeOwner(); const login = os .input(z.object({ username: z.string(), password: z.string(), })) .handler(async ({ input }) => { const users = await usersKV.getAllItems(); const user = users.find(u => u.username === input.username); if (!user || !verifyPassword(input.password, user.passwordHash)) { throw new Error("Invalid credentials"); } // Create session const sessionId = randomUUID(); const expiresAt = new Date(); expiresAt.setHours(expiresAt.getHours() + 24); // 24 hours const session: Session = { id: sessionId, userId: user.id, expiresAt: expiresAt.toISOString(), createdAt: new Date().toISOString(), }; await sessionsKV.setItem(sessionId, session); return { sessionId, user: { id: user.id, username: user.username, email: user.email, role: user.role, }, }; }); const logout = os .input(z.string()) // sessionId .handler(async ({ input }) => { await sessionsKV.removeItem(input); return { success: true }; }); const verifySession = os .input(z.string()) // sessionId .handler(async ({ input }) => { const session = await sessionsKV.getItem(input); if (!session) { throw new Error("Invalid session"); } if (new Date(session.expiresAt) < new Date()) { await sessionsKV.removeItem(input); throw new Error("Session expired"); } const user = await usersKV.getItem(session.userId); if (!user) { throw new Error("User not found"); } return { user: { id: user.id, username: user.username, email: user.email, role: user.role, }, }; }); const changePassword = os .input(z.object({ sessionId: z.string(), currentPassword: z.string(), newPassword: z.string(), })) .handler(async ({ input }) => { const session = await sessionsKV.getItem(input.sessionId); if (!session) { throw new Error("Invalid session"); } const user = await usersKV.getItem(session.userId); if (!user) { throw new Error("User not found"); } if (!verifyPassword(input.currentPassword, user.passwordHash)) { throw new Error("Current password is incorrect"); } const updatedUser = { ...user, passwordHash: hashPassword(input.newPassword), }; await usersKV.setItem(user.id, updatedUser); return { success: true }; }); export const router = { login, logout, verifySession, changePassword, };