-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
145 lines (123 loc) · 4.75 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { GatsbyFunctionRequest, GatsbyFunctionResponse } from 'gatsby'
import flowRight from 'lodash/flowRight'
type GatsbyFunction = (req: GatsbyFunctionRequest, res: GatsbyFunctionResponse) => any;
type GatsbyFunctionMiddleware = (next: GatsbyFunction) => GatsbyFunction;
/**
* Decorate your functions handler with middleware.
*
* This function takes a list of middleware and
* returns a functions handler with these middleware
* applied to it.
*
* In other words it combines all middleware into one.
*/
export const combineMiddleware = (...middleware: GatsbyFunctionMiddleware[]): GatsbyFunctionMiddleware => {
return flowRight(...middleware)
}
type HttpMethod =
| 'GET'
| 'HEAD'
| 'POST'
| 'PUT'
| 'DELETE'
| 'CONNECT'
| 'OPTIONS'
| 'TRACE'
| 'PATCH'
/**
* Limits a function so that it can only be called with the specified HTTP methods.
*/
export const withHttpMethods = (methods: HttpMethod[]): GatsbyFunctionMiddleware => {
return (next) => (req, res) => {
if (!methods.includes(req.method as HttpMethod)) {
return res.status(405).send('Method Not Allowed')
}
return next(req, res)
}
}
/**
* Limits a function so that it can only be called with specific content-types.
*/
export const withContentTypes = (contentTypes: string[]): GatsbyFunctionMiddleware => {
return (next) => (req, res) => {
if (!contentTypes.includes(req.headers?.['content-type']?.toLowerCase() ?? '')) {
return res.status(415).send('Unsupported Media Type')
}
return next(req, res)
}
}
type AuthorizerFunction = (authorizationHeaderValue: string) => Promise<boolean>;
/**
* Accepts an authorizer function which will
* attempt to parse the Authorization header value
* and return an authorization result (true or false).
*
* If parsing fails, the authorizer function may throw
* an error to indicate that the parsing was unsuccessful.
*/
export const withAuthorization = (authorizer: AuthorizerFunction): GatsbyFunctionMiddleware => {
return (next) => (req, res) => {
const header = req.headers?.authorization
if (!header) {
return res.status(401).send('Unauthorized')
}
try {
if (!authorizer(header)) {
return res.status(403).send('Forbidden')
}
} catch (err) {
return res.status(401).send('Unauthorized')
}
return next(req, res)
}
}
type CorsConfig = {
/**
* The Access-Control-Allow-Origin response header indicates whether the response can be shared with requesting code from the given origin.
*
* See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
*/
allowOrigin: string;
/**
* The Access-Control-Allow-Headers response header is used in response to a preflight request which includes the Access-Control-Request-Headers to indicate which HTTP headers can be used during the actual request. This header is required if the request has an Access-Control-Request-Headers header.
*
* See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
*/
allowHeaders: string;
/**
* The Access-Control-Allow-Methods response header specifies one or more methods allowed when accessing a resource in response to a preflight request.
*
* See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
*/
allowMethods: string;
/**
* The Access-Control-Allow-Credentials response header tells browsers whether to expose the response to the frontend JavaScript code when the request's credentials mode (Request.credentials) is include.
*
* See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
*/
allowCredentials: boolean;
/**
* The Access-Control-Max-Age response header indicates how long the results of a preflight request (that is the information contained in the Access-Control-Allow-Methods and Access-Control-Allow-Headers headers) can be cached.
*
* See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
*/
maxAge: number;
}
export const withCors = (corsConfig: CorsConfig): GatsbyFunctionMiddleware => {
return (next) => (req, res) => {
if (req.method?.toLowerCase() === 'options') {
res
.setHeader('Allow', corsConfig.allowMethods)
.setHeader('Access-Control-Allow-Origin', corsConfig.allowOrigin)
.setHeader('Access-Control-Allow-Headers', corsConfig.allowHeaders)
.setHeader('Access-Control-Allow-Methods', corsConfig.allowMethods)
.status(204)
if (corsConfig.allowCredentials) {
res.setHeader('Access-Control-Allow-Credentials', 'true')
}
res.setHeader('Access-Control-Max-Age', corsConfig.maxAge ?? 5)
return res.send('')
}
return next(req, res)
}
}