Skip to content

Commit 4e268aa

Browse files
committed
Refactor and reuse getEventHeader
Improve Fetch Request detection
1 parent 5e0c1c2 commit 4e268aa

6 files changed

Lines changed: 64 additions & 48 deletions

File tree

packages/api/src/auth/index.ts

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { APIGatewayProxyEvent, Context as LambdaContext } from 'aws-lambda'
44
// @ts-expect-error Types are incorrect in 0.6, but will be fixed in the next version probably
55
import { parse as parseCookie } from 'cookie'
66

7-
import { isFetchApiRequest } from '../transforms'
7+
import { getEventHeader } from '../event'
88

99
import type { Decoded } from './parseJWT'
1010
export type { Decoded }
@@ -19,9 +19,7 @@ export const getAuthProviderHeader = (
1919
(key) => key.toLowerCase() === AUTH_PROVIDER_HEADER
2020
)
2121
if (authProviderKey) {
22-
return isFetchApiRequest(event)
23-
? event?.headers.get(authProviderKey)
24-
: event?.headers[authProviderKey]
22+
return getEventHeader(event, authProviderKey)
2523
}
2624
return undefined
2725
}
@@ -34,9 +32,7 @@ export interface AuthorizationHeader {
3432
export const parseAuthorizationCookie = (
3533
event: APIGatewayProxyEvent | Request
3634
) => {
37-
const cookie = isFetchApiRequest(event)
38-
? event.headers.get('Cookie')
39-
: event.headers?.Cookie || event.headers.cookie
35+
const cookie = getEventHeader(event, 'cookie')
4036

4137
// Unauthenticated request
4238
if (!cookie) {
@@ -56,11 +52,9 @@ export const parseAuthorizationCookie = (
5652
* Split the `Authorization` header into a schema and token part.
5753
*/
5854
export const parseAuthorizationHeader = (
59-
event: APIGatewayProxyEvent
55+
event: APIGatewayProxyEvent | Request
6056
): AuthorizationHeader => {
61-
const parts = (
62-
event.headers?.authorization || event.headers?.Authorization
63-
)?.split(' ')
57+
const parts = getEventHeader(event, 'authorization')?.split(' ')
6458
if (parts?.length !== 2) {
6559
throw new Error('The `Authorization` header is not valid.')
6660
}

packages/api/src/event.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { APIGatewayProxyEvent } from 'aws-lambda'
2+
3+
import { isFetchApiRequest } from './transforms'
4+
5+
// Extracts the header from an event, handling lower and upper case header names.
6+
export const getEventHeader = (
7+
event: APIGatewayProxyEvent | Request,
8+
headerName: string
9+
) => {
10+
if (isFetchApiRequest(event)) {
11+
return event.headers.get(headerName)
12+
}
13+
14+
return event.headers[headerName] || event.headers[headerName.toLowerCase()]
15+
}

packages/api/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export * from './types'
77

88
export * from './transforms'
99
export * from './cors'
10+
export * from './event'
1011

1112
// @NOTE: use require, to avoid messing around with tsconfig and nested output dirs
1213
const packageJson = require('../package.json')

packages/api/src/transforms.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Headers } from '@whatwg-node/fetch'
1+
import { Headers, Request as PonyfillRequest } from '@whatwg-node/fetch'
22
import type { APIGatewayProxyEvent } from 'aws-lambda'
33

44
// This is part of the request, dreived either from a LambdaEvent or FetchAPI Request
@@ -50,13 +50,19 @@ export const parseFetchEventBody = async (event: Request) => {
5050
export const isFetchApiRequest = (
5151
event: Request | APIGatewayProxyEvent
5252
): event is Request => {
53-
// Arda has suggested it's better to check for a lambda event than a fetch event
54-
// as there are some edgecases with constructor name in PonyfillRequest
55-
if ('httpMethod' in event || 'resource' in event) {
56-
return false
53+
if (
54+
event.constructor.name === 'Request' ||
55+
event.constructor.name === PonyfillRequest.name
56+
) {
57+
return true
5758
}
5859

59-
return true
60+
// Also do an extra check on type of headers
61+
if (Symbol.iterator in Object(event.headers)) {
62+
return true
63+
}
64+
65+
return false
6066
}
6167

6268
function getQueryStringParams(reqUrl: string) {

packages/auth-providers/dbAuth/api/src/__tests__/DbAuthHandler.fetch.test.js

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2801,11 +2801,15 @@ describe('dbAuth', () => {
28012801

28022802
it('throw an error if user is not found', async () => {
28032803
const data = { id: 999999999999 }
2804-
req = {
2805-
headers: {
2806-
cookie: encryptToCookie(JSON.stringify(data) + ';' + 'token'),
2807-
},
2804+
const headers = {
2805+
cookie: encryptToCookie(JSON.stringify(data) + ';' + 'token'),
28082806
}
2807+
2808+
const req = new Request('http://localhost:8910/_rw_mw', {
2809+
method: 'POST',
2810+
headers,
2811+
})
2812+
28092813
const dbAuth = new DbAuthHandler(req, context, options)
28102814

28112815
try {
@@ -2819,13 +2823,17 @@ describe('dbAuth', () => {
28192823

28202824
it('throws a generic error for an invalid client', async () => {
28212825
const dbUser = await createDbUser()
2822-
req = {
2823-
headers: {
2824-
cookie: encryptToCookie(
2825-
JSON.stringify({ id: dbUser.id }) + ';' + 'token'
2826-
),
2827-
},
2826+
const headers = {
2827+
cookie: encryptToCookie(
2828+
JSON.stringify({ id: dbUser.id }) + ';' + 'token'
2829+
),
28282830
}
2831+
2832+
const req = new Request('http://localhost:8910/_rw_mw', {
2833+
method: 'POST',
2834+
headers,
2835+
})
2836+
28292837
// invalid db client
28302838
const dbAuth = new DbAuthHandler(req, context, options)
28312839
dbAuth.dbAccessor = undefined
@@ -2841,13 +2849,17 @@ describe('dbAuth', () => {
28412849

28422850
it('returns the user whos id is in session', async () => {
28432851
const dbUser = await createDbUser()
2844-
req = {
2845-
headers: {
2846-
cookie: encryptToCookie(
2847-
JSON.stringify({ id: dbUser.id }) + ';' + 'token'
2848-
),
2849-
},
2852+
const headers = {
2853+
cookie: encryptToCookie(
2854+
JSON.stringify({ id: dbUser.id }) + ';' + 'token'
2855+
),
28502856
}
2857+
2858+
const req = new Request('http://localhost:8910/_rw_mw', {
2859+
method: 'POST',
2860+
headers,
2861+
})
2862+
28512863
const dbAuth = new DbAuthHandler(req, context, options)
28522864
const user = await dbAuth._getCurrentUser()
28532865

packages/auth-providers/dbAuth/api/src/shared.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import crypto from 'node:crypto'
22

33
import type { APIGatewayProxyEvent } from 'aws-lambda'
44

5-
import { isFetchApiRequest } from '@redwoodjs/api'
5+
import { getEventHeader } from '@redwoodjs/api'
66
import { getConfig, getConfigPath } from '@redwoodjs/project-config'
77

88
import * as DbAuthError from './errors'
@@ -23,18 +23,6 @@ const DEFAULT_SCRYPT_OPTIONS: ScryptOptions = {
2323
parallelization: 1,
2424
}
2525

26-
// Extracts the header from an event, handling lower and upper case header names.
27-
const eventGetHeader = (
28-
event: APIGatewayProxyEvent | Request,
29-
headerName: string
30-
) => {
31-
if (isFetchApiRequest(event)) {
32-
return event.headers.get(headerName)
33-
}
34-
35-
return event.headers[headerName] || event.headers[headerName.toLowerCase()]
36-
}
37-
3826
const getPort = () => {
3927
let configPath
4028

@@ -81,13 +69,13 @@ export const extractCookie = (event: APIGatewayProxyEvent | Request) => {
8169
// this feels a bit off, but also requires the parsing to become async
8270

8371
// return eventGraphiQLHeadersCookie(event) || eventHeadersCookie(event)
84-
return eventGetHeader(event, 'Cookie')
72+
return getEventHeader(event, 'Cookie')
8573
}
8674

8775
function extractEncryptedSessionFromHeader(
8876
event: APIGatewayProxyEvent | Request
8977
) {
90-
return eventGetHeader(event, 'Authorization')?.split(' ')[1]
78+
return getEventHeader(event, 'Authorization')?.split(' ')[1]
9179
}
9280

9381
// whether this encrypted session was made with the old CryptoJS algorithm

0 commit comments

Comments
 (0)