diff --git a/contributors.yml b/contributors.yml index 3fb834d3ddd..7664e08abf2 100644 --- a/contributors.yml +++ b/contributors.yml @@ -569,6 +569,7 @@ - amir-ziaei - mrkhosravian - tanerijun +- naveed-fida - toufiqnuur - ally1002 - defjosiah diff --git a/packages/remix-node/__tests__/sessions-test.ts b/packages/remix-node/__tests__/sessions-test.ts index b10b33bda93..5aa8c24f52a 100644 --- a/packages/remix-node/__tests__/sessions-test.ts +++ b/packages/remix-node/__tests__/sessions-test.ts @@ -2,7 +2,7 @@ import path from "node:path"; import { promises as fsp } from "node:fs"; import os from "node:os"; -import { createFileSessionStorage } from "../sessions/fileStorage"; +import { createFileSessionStorage, getFile } from "../sessions/fileStorage"; function getCookieFromSetCookie(setCookie: string): string { return setCookie.split(/;\s*/)[0]; @@ -62,6 +62,39 @@ describe("File session storage", () => { await expect(destroySession(session)).resolves.not.toThrowError(); }); + it("saves expires to file if expires provided to commitSession when creating new cookie", async () => { + let { getSession, commitSession } = createFileSessionStorage({ + dir, + cookie: { secrets: ["secret1"] }, + }); + let session = await getSession(); + session.set("user", "mjackson"); + let date = new Date(Date.now() + 1000 * 60); + let cookieHeader = await commitSession(session, { expires: date }); + let createdSession = await getSession(cookieHeader); + + let { id } = createdSession; + let fileContents = await fsp.readFile(getFile(dir, id), "utf8"); + let fileData = JSON.parse(fileContents); + expect(fileData.expires).toEqual(date.toISOString()); + }); + + it("saves expires to file if maxAge provided to commitSession when creating new cookie", async () => { + let { getSession, commitSession } = createFileSessionStorage({ + dir, + cookie: { secrets: ["secret1"] }, + }); + let session = await getSession(); + session.set("user", "mjackson"); + let cookieHeader = await commitSession(session, { maxAge: 60 }); + let createdSession = await getSession(cookieHeader); + + let { id } = createdSession; + let fileContents = await fsp.readFile(getFile(dir, id), "utf8"); + let fileData = JSON.parse(fileContents); + expect(typeof fileData.expires).toBe("string"); + }); + describe("when a new secret shows up in the rotation", () => { it("unsigns old session cookies using the old secret and encodes new cookies using the new secret", async () => { let { getSession, commitSession } = createFileSessionStorage({ diff --git a/packages/remix-node/sessions/fileStorage.ts b/packages/remix-node/sessions/fileStorage.ts index a7eedf3b8cb..042539710cf 100644 --- a/packages/remix-node/sessions/fileStorage.ts +++ b/packages/remix-node/sessions/fileStorage.ts @@ -103,7 +103,7 @@ export function createFileSessionStorage({ }); } -function getFile(dir: string, id: string): string { +export function getFile(dir: string, id: string): string { // Divide the session id up into a directory (first 2 bytes) and filename // (remaining 6 bytes) to reduce the chance of having very large directories, // which should speed up file access. This is a maximum of 2^16 directories, diff --git a/packages/remix-server-runtime/sessions.ts b/packages/remix-server-runtime/sessions.ts index bf809b65414..2d4a6c90806 100644 --- a/packages/remix-server-runtime/sessions.ts +++ b/packages/remix-server-runtime/sessions.ts @@ -277,11 +277,17 @@ export const createSessionStorageFactory = }, async commitSession(session, options) { let { id, data } = session; + let expires = + options?.maxAge != null + ? new Date(Date.now() + options.maxAge * 1000) + : options?.expires != null + ? options.expires + : cookie.expires; if (id) { - await updateData(id, data, cookie.expires); + await updateData(id, data, expires); } else { - id = await createData(data, cookie.expires); + id = await createData(data, expires); } return cookie.serialize(id, options);