refactor: replace DB-based auth with env-based single admin user

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
mikl0s 2026-02-22 21:48:33 +00:00
parent 7eae4fde33
commit bc300f54f2

View file

@ -1,27 +1,10 @@
import bcrypt from "bcrypt"
import { cookies } from "next/headers" import { cookies } from "next/headers"
import {
createSession,
deleteSession,
getSession,
getUserByEmail,
getUserById,
createUser as dbCreateUser,
cleanExpiredSessions,
type User,
} from "./db"
const SALT_ROUNDS = 10
const SESSION_COOKIE_NAME = "session" const SESSION_COOKIE_NAME = "session"
const SESSION_DURATION_DAYS = 7 const SESSION_DURATION_MS = 7 * 24 * 60 * 60 * 1000 // 7 days
export async function hashPassword(password: string): Promise<string> { // In-memory session store. Replace this with your own session/token system.
return bcrypt.hash(password, SALT_ROUNDS) const sessions = new Map<string, { email: string; expiresAt: Date }>()
}
export async function verifyPassword(password: string, hash: string): Promise<boolean> {
return bcrypt.compare(password, hash)
}
function generateSessionId(): string { function generateSessionId(): string {
const bytes = new Uint8Array(32) const bytes = new Uint8Array(32)
@ -31,86 +14,78 @@ function generateSessionId(): string {
.join("") .join("")
} }
// ─── AUTH INTERFACE ────────────────────────────────────────────────
// To integrate your own auth (JWT, OAuth, etc.), replace these functions.
// The rest of the application only calls checkAuth(), login(), and logout().
// ───────────────────────────────────────────────────────────────────
/**
* Check if the current request is authenticated.
* Replace this function to integrate JWT, OAuth, or any other auth system.
*/
export async function checkAuth(): Promise<{ authenticated: boolean; email?: string }> {
const cookieStore = await cookies()
const sessionId = cookieStore.get(SESSION_COOKIE_NAME)?.value
if (!sessionId) return { authenticated: false }
const session = sessions.get(sessionId)
if (!session) return { authenticated: false }
if (session.expiresAt < new Date()) {
sessions.delete(sessionId)
return { authenticated: false }
}
return { authenticated: true, email: session.email }
}
/**
* Authenticate with email and password.
* Default: compares against ADMIN_EMAIL/ADMIN_PASSWORD env vars.
* Replace this function to integrate your own auth system.
*/
export async function login( export async function login(
email: string, email: string,
password: string password: string
): Promise<{ success: true; user: User } | { success: false; error: string }> { ): Promise<{ success: true } | { success: false; error: string }> {
const user = getUserByEmail(email) const adminEmail = process.env.ADMIN_EMAIL
const adminPassword = process.env.ADMIN_PASSWORD
if (!user) { if (!adminEmail || !adminPassword) {
return { success: false, error: "Admin-konfiguration mangler (ADMIN_EMAIL/ADMIN_PASSWORD)" }
}
if (email !== adminEmail || password !== adminPassword) {
return { success: false, error: "Forkert email eller adgangskode" } return { success: false, error: "Forkert email eller adgangskode" }
} }
const validPassword = await verifyPassword(password, user.passwordHash)
if (!validPassword) {
return { success: false, error: "Forkert email eller adgangskode" }
}
// Clean up old sessions periodically
cleanExpiredSessions()
// Create new session
const sessionId = generateSessionId() const sessionId = generateSessionId()
const expiresAt = new Date() const expiresAt = new Date(Date.now() + SESSION_DURATION_MS)
expiresAt.setDate(expiresAt.getDate() + SESSION_DURATION_DAYS)
createSession(sessionId, user.id, expiresAt) sessions.set(sessionId, { email, expiresAt })
// Set cookie
const cookieStore = await cookies() const cookieStore = await cookies()
cookieStore.set(SESSION_COOKIE_NAME, sessionId, { cookieStore.set(SESSION_COOKIE_NAME, sessionId, {
httpOnly: true, httpOnly: true,
secure: process.env.NODE_ENV === "production", secure: process.env.NODE_ENV === "production",
sameSite: "lax", sameSite: "strict",
expires: expiresAt, expires: expiresAt,
path: "/", path: "/",
}) })
return { return { success: true }
success: true,
user: { id: user.id, email: user.email, name: user.name, createdAt: user.createdAt },
}
} }
/**
* Log out the current session.
*/
export async function logout(): Promise<void> { export async function logout(): Promise<void> {
const cookieStore = await cookies() const cookieStore = await cookies()
const sessionId = cookieStore.get(SESSION_COOKIE_NAME)?.value const sessionId = cookieStore.get(SESSION_COOKIE_NAME)?.value
if (sessionId) { if (sessionId) {
deleteSession(sessionId) sessions.delete(sessionId)
cookieStore.delete(SESSION_COOKIE_NAME) cookieStore.delete(SESSION_COOKIE_NAME)
} }
} }
export async function getCurrentUser(): Promise<User | null> {
const cookieStore = await cookies()
const sessionId = cookieStore.get(SESSION_COOKIE_NAME)?.value
if (!sessionId) return null
const session = getSession(sessionId)
if (!session) return null
// Check if session is expired
if (session.expiresAt < new Date()) {
deleteSession(sessionId)
return null
}
return getUserById(session.userId)
}
export async function isAuthenticated(): Promise<boolean> {
const user = await getCurrentUser()
return user !== null
}
// Helper to create users (run from CLI or seed script)
export async function createUserWithPassword(
email: string,
password: string,
name: string
): Promise<User> {
const passwordHash = await hashPassword(password)
return dbCreateUser(email, passwordHash, name)
}