36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
'use server';
|
|
|
|
import { headers } from 'next/headers';
|
|
import { redirect } from 'next/navigation';
|
|
import { createAdminSession, clearAdminSession } from '@/lib/adminAuth';
|
|
import { checkRateLimit, getClientIp } from '@/lib/rateLimit';
|
|
|
|
function safeNext(next: FormDataEntryValue | null) {
|
|
const path = String(next ?? '');
|
|
return path.startsWith('/') && !path.startsWith('//') ? path : '/admin/orders';
|
|
}
|
|
|
|
export async function loginAdmin(formData: FormData) {
|
|
const username = String(formData.get('username') ?? '');
|
|
const password = String(formData.get('password') ?? '');
|
|
const next = safeNext(formData.get('next'));
|
|
|
|
const ip = getClientIp(headers());
|
|
const { allowed } = await checkRateLimit(`login:admin:${ip}`, 5, 15 * 60 * 1000);
|
|
if (!allowed) {
|
|
redirect(`/admin/login?error=rate_limited&next=${encodeURIComponent(next)}`);
|
|
}
|
|
|
|
if (username !== process.env.ADMIN_USER || password !== process.env.ADMIN_PASSWORD) {
|
|
redirect(`/admin/login?error=invalid&next=${encodeURIComponent(next)}`);
|
|
}
|
|
|
|
await createAdminSession();
|
|
redirect(next);
|
|
}
|
|
|
|
export async function logoutAdmin() {
|
|
clearAdminSession();
|
|
redirect('/admin/login');
|
|
}
|