-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: redirect handler creates new session in a way that is compatible…
… with session & csrf middleware
- Loading branch information
1 parent
ce2e4f7
commit a6d5e72
Showing
15 changed files
with
145 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,13 @@ | ||
import * as arc from "@architect/functions" | ||
import oAuthRedirectHandlerFactory from "../../lib/architect/oauth/handlers/redirect" | ||
import { tokenRepositoryFactory } from "../../lib/architect/oauth/repository/TokenRepository" | ||
import userRepositoryFactory from "../../lib/architect/oauth/repository/UserRepository" | ||
import { fetchJson } from "../../lib/fetch" | ||
|
||
const impl = oAuthRedirectHandlerFactory( | ||
fetchJson, | ||
userRepositoryFactory(), | ||
tokenRepositoryFactory() | ||
) | ||
|
||
const impl = oAuthRedirectHandlerFactory() | ||
export const handler = arc.http.async(impl) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,26 @@ | ||
import { addRequestSessionID, SESSION_ID_KEY } from "./session" | ||
import { writeSessionID, readSessionID } from "./session" | ||
import { createMockRequest } from "../../../../test/support/architect" | ||
import { randomInt } from "../../../../test/support" | ||
|
||
describe("session", () => { | ||
// note process.env.SESSION_SECRET just avois some warnings | ||
beforeAll(() => (process.env.SESSION_SECRET = "session secretish")) | ||
afterAll(() => delete process.env.SESSION_SECRET) | ||
let testSessionID = beforeEach(() => { | ||
testSessionID = "session-id-" + randomInt().toString() | ||
}) | ||
|
||
it("should require http.async session on request", async () => { | ||
const req = createMockRequest() | ||
delete req.session | ||
expect(await addRequestSessionID(req)).toHaveProperty("statusCode", 500) | ||
expect(() => writeSessionID(req, testSessionID)).toThrowError( | ||
/missing session middleware/ | ||
) | ||
}) | ||
|
||
it("add a session-id if not exists", async () => { | ||
it("should add and read the same session id", async () => { | ||
const req = createMockRequest() | ||
await addRequestSessionID(req) | ||
writeSessionID(req, testSessionID) | ||
expect(req).toHaveProperty("session") | ||
expect(req.session).toHaveProperty(SESSION_ID_KEY) | ||
const id = req.session[SESSION_ID_KEY] | ||
expect(typeof id).toStrictEqual("string") | ||
expect(id.length).toBeGreaterThan(10) | ||
}) | ||
|
||
it("should reuse existing session-id if it exists", async () => { | ||
// create a session with SESSION_ID_HEADER_NAME: | ||
const req = createMockRequest() | ||
await addRequestSessionID(req) | ||
expect(req).toHaveProperty("session") | ||
const session1 = req.session[SESSION_ID_KEY] | ||
// now call it again and make sure it doesn't replace it: | ||
await addRequestSessionID(req) | ||
const session2 = req.session[SESSION_ID_KEY] | ||
expect(session1).toEqual(session2) | ||
const found = readSessionID(req) | ||
expect(found).toStrictEqual(testSessionID) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,39 +1,29 @@ | ||
import { | ||
ArchitectHttpRequestPayload, | ||
ArchitectHttpResponsePayload, | ||
} from "../../../types/http" | ||
import { v4 as uuidv4 } from "uuid" | ||
|
||
/** The name of the session key to get the session ID value */ | ||
export const SESSION_ID_KEY = "SESS-ID-KEY" | ||
const SESSION_ID_KEY = "SESS-ID-KEY" | ||
|
||
type HttpResponseLike = { session?: Record<string, string> } | ||
type HttpRequestLike = { session?: Record<string, string> } | ||
|
||
/** | ||
* If no request.session.SESSION_ID_TOKEN_HEADER_NAME exists in the session it adds it to request | ||
\ */ | ||
export async function addRequestSessionID( | ||
req: ArchitectHttpRequestPayload | ||
): Promise<ArchitectHttpResponsePayload | null> { | ||
if (!req.session) { | ||
* Writes the specified session ID to the specified response. | ||
* @param response This is generally a response, but for testing purposes we also use it to write to requests (and ultimately we just need something with a session so...) | ||
*/ | ||
export function writeSessionID( | ||
response: HttpResponseLike, | ||
sessionID: string | ||
): void { | ||
if (!response.session) { | ||
// The request probably didn't use arc.http.async middleware https://arc.codes/docs/en/reference/runtime/node#arc.http.async to automatically add the parse `session` field to req. | ||
return { | ||
statusCode: 500, | ||
json: { message: "missing session middleware" }, | ||
} | ||
throw new Error("missing session middleware") | ||
} | ||
|
||
// NOTE: arc.http.session is already *signed* so we don't have to worry about tampering of this session ID | ||
const sessionID = req.session[SESSION_ID_KEY] || newSessionID() | ||
|
||
// now ensure token and session ID are on the request | ||
req.session[SESSION_ID_KEY] = sessionID | ||
response.session[SESSION_ID_KEY] = sessionID | ||
} | ||
|
||
/** Returns the session id for the given request. Assumes the request already has a session id */ | ||
export function readSessionID(req: ArchitectHttpRequestPayload): string { | ||
export function readSessionID(req: HttpRequestLike): string { | ||
if (!req.session || !req.session[SESSION_ID_KEY]) { | ||
return null | ||
} | ||
return req.session[SESSION_ID_KEY] | ||
} | ||
|
||
const newSessionID = (): string => uuidv4() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.