feat: update AUTH_SECRET handling and improve session management
Build and Push Docker Image / build (push) Successful in 1m23s

fix: add credentials to POST request in NewCompanyPage
fix: update Docker image pull policy for app service
This commit is contained in:
hwinkel
2026-05-03 09:24:41 +02:00
parent b22e5baa5c
commit 38c8304336
5 changed files with 38 additions and 16 deletions
+2 -3
View File
@@ -8,7 +8,6 @@ import { Textarea } from "@/components/ui/textarea";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { calcItemAmounts, calcItemAmountsKleinunternehmer, calcInvoiceTotals, formatCurrency, TAX_RATES } from "@/lib/tax";
import { Plus, Trash2 } from "lucide-react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
interface Customer {
id: string;
@@ -301,7 +300,7 @@ export function InvoiceForm({ customers, companyId, onSubmit, defaultValues, def
value={descValue}
onChange={(e) => setValue(`items.${index}.description`, e.target.value)}
onFocus={() => setOpenDropdown(index)}
onBlur={() => setOpenDropdown(null)}
onBlur={() => setTimeout(() => setOpenDropdown(null), 100)}
placeholder="Leistungsbeschreibung"
className="text-sm"
autoComplete="off"
@@ -315,7 +314,7 @@ export function InvoiceForm({ customers, companyId, onSubmit, defaultValues, def
className="w-full text-left px-3 py-2 text-sm hover:bg-gray-50 flex flex-col"
onMouseDown={(e) => {
e.preventDefault();
setValue(`items.${index}.description`, s.description ?? s.name);
setValue(`items.${index}.description`, s.name);
setValue(`items.${index}.unit`, s.unit ?? "Stück");
setValue(`items.${index}.unitPrice`, String(s.unitPrice));
setValue(`items.${index}.taxRate`, String(s.taxRate));
+1
View File
@@ -19,6 +19,7 @@ export default function NewCompanyPage() {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
credentials: "include",
});
if (res.ok) {
+29 -11
View File
@@ -1,10 +1,18 @@
import { createCookieSessionStorage, redirect } from "react-router";
import bcrypt from "bcryptjs";
import { randomBytes } from "crypto";
import prisma from "@/lib/prisma.server";
import { log } from "@/lib/logger.server";
if (!process.env.AUTH_SECRET) {
throw new Error("AUTH_SECRET environment variable is required");
/**
* AUTH_SECRET wird nur aus .env gelesen, falls die Umgebungsvariable nicht existiert.
* Falls nicht gesetzt, wird eine zufällige generiert.
* Bei jedem Containerstart mit ephemerem Secret werden alle bestehenden Sessions invalidiert.
*/
const AUTH_SECRET = process.env.AUTH_SECRET || randomBytes(32).toString("base64");
if (!AUTH_SECRET) {
throw new Error("AUTH_SECRET could not be generated");
}
const sessionStorage = createCookieSessionStorage({
@@ -14,7 +22,7 @@ const sessionStorage = createCookieSessionStorage({
maxAge: 60 * 60 * 4, // 4 Stunden
path: "/",
sameSite: "lax",
secrets: [process.env.AUTH_SECRET],
secrets: [AUTH_SECRET],
secure: process.env.NODE_ENV === "production",
},
});
@@ -64,14 +72,24 @@ export async function createUserSession(
}
export async function getUserSession(request: Request) {
const session = await sessionStorage.getSession(
request.headers.get("Cookie")
);
return {
userId: session.get("userId") as string | undefined,
userName: session.get("userName") as string | undefined,
userRole: session.get("userRole") as string | undefined,
};
try {
const session = await sessionStorage.getSession(
request.headers.get("Cookie")
);
return {
userId: session.get("userId") as string | undefined,
userName: session.get("userName") as string | undefined,
userRole: session.get("userRole") as string | undefined,
};
} catch (error) {
// Session-Cookie ist ungültig (z.B. nach Neustart mit neuem AUTH_SECRET)
// Gib eine leere Session zurück, damit der Nutzer zum Login weitergeleitet wird
return {
userId: undefined,
userName: undefined,
userRole: undefined,
};
}
}
export async function requireUser(request: Request) {