NODE_ENV=production'da cookie hep secure:true oluyordu, ama panel şu an SSL'siz sslip.io preview domain'inde (http://) çalışıyor — tarayıcı Secure cookie'yi HTTP origin'de hiç saklamıyor. Giriş "başarılı" gibi görünüp anında /login'e geri dönülüyordu. Artık gerçek istek protokolüne (Traefik'in x-forwarded-proto header'ı) bakılıyor. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
68 lines
2.3 KiB
TypeScript
68 lines
2.3 KiB
TypeScript
"use server";
|
||
|
||
import { cookies, headers } from "next/headers";
|
||
import { redirect } from "next/navigation";
|
||
import bcrypt from "bcryptjs";
|
||
import { prisma } from "@streamclipper/db";
|
||
import { createSessionToken, SESSION_COOKIE_NAME } from "../../lib/auth";
|
||
|
||
const SESSION_MAX_AGE_SEC = 60 * 60 * 24 * 30;
|
||
|
||
async function setSessionCookie(userId: string, username: string) {
|
||
const token = await createSessionToken({ sub: userId, username });
|
||
const jar = await cookies();
|
||
// NODE_ENV alone isn't a reliable signal for this — the panel is often
|
||
// served over plain HTTP (e.g. Coolify's auto-generated sslip.io preview
|
||
// domain has no TLS). A `Secure` cookie set on an HTTP origin is silently
|
||
// dropped by the browser, which made every login look successful for an
|
||
// instant and then immediately bounce back to /login. Check the actual
|
||
// request scheme instead (Traefik/Coolify sets x-forwarded-proto).
|
||
const proto = (await headers()).get("x-forwarded-proto");
|
||
jar.set(SESSION_COOKIE_NAME, token, {
|
||
httpOnly: true,
|
||
secure: proto === "https",
|
||
sameSite: "lax",
|
||
path: "/",
|
||
maxAge: SESSION_MAX_AGE_SEC,
|
||
});
|
||
}
|
||
|
||
export async function bootstrapAdmin(formData: FormData) {
|
||
const username = String(formData.get("username") ?? "").trim();
|
||
const password = String(formData.get("password") ?? "");
|
||
|
||
if (!username || password.length < 8) {
|
||
throw new Error("Kullanıcı adı gerekli, şifre en az 8 karakter olmalı.");
|
||
}
|
||
|
||
const existing = await prisma.user.count();
|
||
if (existing > 0) {
|
||
redirect("/login");
|
||
}
|
||
|
||
const passwordHash = await bcrypt.hash(password, 12);
|
||
const user = await prisma.user.create({ data: { username, passwordHash } });
|
||
|
||
await setSessionCookie(user.id, user.username);
|
||
redirect("/");
|
||
}
|
||
|
||
export async function login(formData: FormData) {
|
||
const username = String(formData.get("username") ?? "").trim();
|
||
const password = String(formData.get("password") ?? "");
|
||
|
||
const user = await prisma.user.findUnique({ where: { username } });
|
||
if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
|
||
redirect("/login?error=1");
|
||
}
|
||
|
||
await setSessionCookie(user.id, user.username);
|
||
redirect("/");
|
||
}
|
||
|
||
export async function logout() {
|
||
const jar = await cookies();
|
||
jar.delete(SESSION_COOKIE_NAME);
|
||
redirect("/login");
|
||
}
|