fix: session cookie over plain http, console onboarding gate, webkit qa coverage
- the session cookie was Secure whenever NODE_ENV=production, so a production build on http://localhost got no cookie back in Safari: every page after signup looked signed-out. It is now Secure only when X-Forwarded-Proto says https, or when COOKIE_SECURE=1. - /app and /app/[id] now require an analyst and a Jev key, the same rule /api/analyze enforces with a 412. Closing the guide mid-way used to leave a console that could not run anything. - Playwright runs the production server (pree2e builds first) and gains a webkit project for session survival; chromium-only QA could never see a Secure-cookie rejection. - tests-e2e/session.spec.ts pins both; .env.example gains COOKIE_SECURE and stops shipping a blank APP_SECRET. - e2e: 21 passed (setup, chromium, webkit, mobile). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
5160a00db5
commit
2ebfcfb7a6
+9
-2
@@ -33,6 +33,7 @@ export function signUpNewUser(email: string, password: string): { ok: true; id:
|
||||
// next/headers is imported lazily: `node --test` loads this module to test the crypto above, and the
|
||||
// request-scoped binding must not be touched at import time.
|
||||
const jar = async () => (await import("next/headers")).cookies();
|
||||
const fwdProto = async () => ((await (await import("next/headers")).headers())).get("x-forwarded-proto") ?? "";
|
||||
|
||||
export function changeEmail(userId: string, email: string): { ok: true } | { ok: false; error: string } {
|
||||
const e = email.trim().toLowerCase();
|
||||
@@ -47,9 +48,15 @@ export function changeEmail(userId: string, email: string): { ok: true } | { ok:
|
||||
export async function startSession(userId: string) {
|
||||
const token = randomBytes(32).toString("hex");
|
||||
putSession(hashToken(token), userId, Date.now() + SESSION_DAYS * 864e5);
|
||||
const secure = process.env.COOKIE_SECURE === "1" || (await fwdProto()).includes("https");
|
||||
(await jar()).set(SESSION_COOKIE, token, {
|
||||
httpOnly: true, sameSite: "lax", secure: process.env.NODE_ENV === "production",
|
||||
path: "/", maxAge: SESSION_DAYS * 86400 });
|
||||
httpOnly: true, sameSite: "lax", secure,
|
||||
path: "/", maxAge: SESSION_DAYS * 86400,
|
||||
// NODE_ENV is the wrong signal here. A production build served over plain http://localhost would set
|
||||
// Secure, Safari then refuses to store the cookie at all, and every page after signup looks signed-out.
|
||||
// (Chromium accepts Secure on localhost, which is why a chromium-only suite could never see it.)
|
||||
// Only a TLS proxy reports https; COOKIE_SECURE=1 forces it on for a direct https deploy.
|
||||
});
|
||||
}
|
||||
export async function endSession() {
|
||||
const store = await jar();
|
||||
|
||||
Reference in New Issue
Block a user