Files
2026-07-13 13:32:57 +08:00

79 lines
2.7 KiB
TypeScript

import { redirect, type ActionFunctionArgs } from "@remix-run/server-runtime";
import { z } from "zod";
import { prisma } from "~/db.server";
import {
commitSession as commitMessageSession,
getSession as getMessageSession,
setErrorMessage,
setSuccessMessage,
} from "~/models/message.server";
import { requireUserId } from "~/services/session.server";
import {
commitAuthenticatedSession,
getAllowedSessionOptions,
getEffectiveSessionDuration,
isAllowedSessionDuration,
} from "~/services/sessionDuration.server";
import { getUserSession } from "~/services/sessionStorage.server";
const FormSchema = z.object({
sessionDuration: z.coerce.number().int().positive(),
});
const REDIRECT_PATH = "/account/security";
async function redirectWithError(request: Request, message: string) {
const messageSession = await getMessageSession(request.headers.get("cookie"));
setErrorMessage(messageSession, message);
return redirect(REDIRECT_PATH, {
headers: { "Set-Cookie": await commitMessageSession(messageSession) },
});
}
export async function action({ request }: ActionFunctionArgs) {
const userId = await requireUserId(request);
const formData = await request.formData();
const parsed = FormSchema.safeParse(Object.fromEntries(formData));
if (!parsed.success) {
return redirectWithError(request, "Invalid session duration value.");
}
const { sessionDuration } = parsed.data;
if (!isAllowedSessionDuration(sessionDuration)) {
return redirectWithError(request, "Invalid session duration value.");
}
const { orgCapSeconds, durationSeconds } = await getEffectiveSessionDuration(userId);
const allowed = getAllowedSessionOptions(orgCapSeconds, durationSeconds);
if (!allowed.some((o) => o.value === sessionDuration)) {
return redirectWithError(
request,
"Your organization's policy does not allow that session duration."
);
}
await prisma.user.update({
where: { id: userId },
data: { sessionDuration },
});
// Re-issue the cookie with the new maxAge and reset issuedAt so the user
// gets a fresh window matching their new selection right away. This also
// restamps `User.nextSessionEnd` against the new effective duration.
const authSession = await getUserSession(request);
const authCookie = await commitAuthenticatedSession(authSession, userId);
const messageSession = await getMessageSession(request.headers.get("cookie"));
setSuccessMessage(messageSession, "Session duration updated.");
const messageCookie = await commitMessageSession(messageSession);
const headers = new Headers();
headers.append("Set-Cookie", authCookie);
headers.append("Set-Cookie", messageCookie);
return redirect(REDIRECT_PATH, { headers });
}