serverless-offline 10.0.2 → 10.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -34
- package/package.json +13 -111
- package/src/ServerlessOffline.js +21 -5
- package/src/config/commandOptions.js +1 -1
- package/src/config/defaultOptions.js +1 -3
- package/src/events/http/HttpServer.js +19 -6
- package/src/events/websocket/HttpServer.js +21 -1
- package/src/events/websocket/WebSocket.js +23 -3
- package/src/events/websocket/WebSocketServer.js +6 -1
- package/src/utils/getApiKeysValues.js +7 -0
- package/src/utils/index.js +1 -0
package/README.md
CHANGED
|
@@ -108,40 +108,151 @@ to list all the options for the plugin run:
|
|
|
108
108
|
|
|
109
109
|
All CLI options are optional:
|
|
110
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
|
-
|
|
111
|
+
#### apiKey
|
|
112
|
+
|
|
113
|
+
_This option is deprecated and will be removed in the next major version. If you want to specify the apiKey value yourself, please define it under 'provider.apiGateway.apiKeys' in the serverless config._
|
|
114
|
+
|
|
115
|
+
Defines the API key value to be used for endpoints marked as private.<br />
|
|
116
|
+
Defaults to a random value.
|
|
117
|
+
|
|
118
|
+
#### corsAllowHeaders
|
|
119
|
+
|
|
120
|
+
Used as default Access-Control-Allow-Headers header value for responses. Delimit multiple values with commas.<br />
|
|
121
|
+
Default: 'accept,content-type,x-api-key'
|
|
122
|
+
|
|
123
|
+
#### corsAllowOrigin
|
|
124
|
+
|
|
125
|
+
Used as default Access-Control-Allow-Origin header value for responses. Delimit multiple values with commas.<br />
|
|
126
|
+
Default: '\*'
|
|
127
|
+
|
|
128
|
+
#### corsDisallowCredentials
|
|
129
|
+
|
|
130
|
+
When provided, the default Access-Control-Allow-Credentials header value will be passed as 'false'.\
|
|
131
|
+
Default: true
|
|
132
|
+
|
|
133
|
+
#### corsExposedHeaders
|
|
134
|
+
|
|
135
|
+
Used as additional Access-Control-Exposed-Headers header value for responses. Delimit multiple values with commas.<br />
|
|
136
|
+
Default: 'WWW-Authenticate,Server-Authorization'
|
|
137
|
+
|
|
138
|
+
#### disableCookieValidation
|
|
139
|
+
|
|
140
|
+
Used to disable cookie-validation on hapi.js-server.
|
|
141
|
+
|
|
142
|
+
#### disableScheduledEvents
|
|
143
|
+
|
|
144
|
+
Disables all scheduled events. Overrides configurations in serverless.yml.
|
|
145
|
+
|
|
146
|
+
#### dockerHost
|
|
147
|
+
|
|
148
|
+
The host name of Docker.<br />
|
|
149
|
+
Default: localhost
|
|
150
|
+
|
|
151
|
+
#### dockerHostServicePath
|
|
152
|
+
|
|
153
|
+
Defines service path which is used by SLS running inside Docker container.
|
|
154
|
+
|
|
155
|
+
#### dockerNetwork
|
|
156
|
+
|
|
157
|
+
The network that the Docker container will connect to.
|
|
158
|
+
|
|
159
|
+
#### dockerReadOnly
|
|
160
|
+
|
|
161
|
+
Marks if the docker code layer should be read only.<br />
|
|
162
|
+
Default: true
|
|
163
|
+
|
|
164
|
+
#### enforceSecureCookies
|
|
165
|
+
|
|
166
|
+
Enforce secure cookies
|
|
167
|
+
|
|
168
|
+
#### host
|
|
169
|
+
|
|
170
|
+
-o Host name to listen on.<br />
|
|
171
|
+
Default: localhost
|
|
172
|
+
|
|
173
|
+
#### httpPort
|
|
174
|
+
|
|
175
|
+
Http port to listen on.<br />
|
|
176
|
+
Default: 3000
|
|
177
|
+
|
|
178
|
+
#### httpsProtocol
|
|
179
|
+
|
|
180
|
+
-H To enable HTTPS, specify directory (relative to your cwd, typically your project dir) for both cert.pem and key.pem files.
|
|
181
|
+
|
|
182
|
+
#### ignoreJWTSignature
|
|
183
|
+
|
|
184
|
+
When using HttpApi with a JWT authorizer, don't check the signature of the JWT token. This should only be used for local development.
|
|
185
|
+
|
|
186
|
+
#### lambdaPort
|
|
187
|
+
|
|
188
|
+
Lambda http port to listen on.<br />
|
|
189
|
+
Default: 3002
|
|
190
|
+
|
|
191
|
+
#### layersDir
|
|
192
|
+
|
|
193
|
+
The directory layers should be stored in.<br />
|
|
194
|
+
Default: ${codeDir}/.serverless-offline/layers'
|
|
195
|
+
|
|
196
|
+
#### localEnvironment
|
|
197
|
+
|
|
198
|
+
Copy local environment variables.<br />
|
|
199
|
+
Default: false
|
|
200
|
+
|
|
201
|
+
#### noAuth
|
|
202
|
+
|
|
203
|
+
Turns off all authorizers.
|
|
204
|
+
|
|
205
|
+
#### noPrependStageInUrl
|
|
206
|
+
|
|
207
|
+
Don't prepend http routes with the stage.
|
|
208
|
+
|
|
209
|
+
#### noStripTrailingSlashInUrl
|
|
210
|
+
|
|
211
|
+
Don't strip trailing slash from http routes.
|
|
212
|
+
|
|
213
|
+
#### noTimeout
|
|
214
|
+
|
|
215
|
+
-t Disables the timeout feature.
|
|
216
|
+
|
|
217
|
+
#### prefix
|
|
218
|
+
|
|
219
|
+
-p Adds a prefix to every path, to send your requests to http://localhost:3000/[prefix]/[your_path] instead.<br />
|
|
220
|
+
Default: ''
|
|
221
|
+
|
|
222
|
+
#### reloadHandler
|
|
223
|
+
|
|
224
|
+
Reloads handler with each request.
|
|
225
|
+
|
|
226
|
+
#### resourceRoutes
|
|
227
|
+
|
|
228
|
+
Turns on loading of your HTTP proxy settings from serverless.yml.
|
|
229
|
+
|
|
230
|
+
#### terminateIdleLambdaTime
|
|
231
|
+
|
|
232
|
+
Number of seconds until an idle function is eligible for termination.
|
|
233
|
+
|
|
234
|
+
#### useDocker
|
|
235
|
+
|
|
236
|
+
Run handlers in a docker container.
|
|
237
|
+
|
|
238
|
+
#### useInProcess
|
|
239
|
+
|
|
240
|
+
Run handlers in the same process as 'serverless-offline'.
|
|
241
|
+
|
|
242
|
+
#### webSocketHardTimeout
|
|
243
|
+
|
|
244
|
+
Set WebSocket hard timeout in seconds to reproduce AWS limits (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#apigateway-execution-service-websocket-limits-table).<br />
|
|
245
|
+
Default: 7200 (2 hours)
|
|
246
|
+
|
|
247
|
+
#### webSocketIdleTimeout
|
|
248
|
+
|
|
249
|
+
Set WebSocket idle timeout in seconds to reproduce AWS limits (https://docs.aws.amazon.com/apigateway/latest/developerguide/limits.html#apigateway-execution-service-websocket-limits-table).<br />
|
|
250
|
+
Default: 600 (10 minutes)
|
|
251
|
+
|
|
252
|
+
#### websocketPort
|
|
253
|
+
|
|
254
|
+
WebSocket port to listen on.<br />
|
|
255
|
+
Default: 3001
|
|
145
256
|
|
|
146
257
|
Any of the CLI options can be added to your `serverless.yml`. For example:
|
|
147
258
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dedicatedTo": "Blue, a great migrating bird.",
|
|
3
3
|
"name": "serverless-offline",
|
|
4
|
-
"version": "10.0
|
|
4
|
+
"version": "10.2.0",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
@@ -23,12 +23,13 @@
|
|
|
23
23
|
"prettify": "prettier --write --ignore-path .gitignore \"**/*.{css,html,js,json,md,yaml,yml}\"",
|
|
24
24
|
"prettify:updated": "pipe-git-updated --ext=css --ext=html --ext=js --ext=json --ext=md --ext=yaml --ext=yml -- prettier --write",
|
|
25
25
|
"test": "mocha --require ./tests/mochaHooks.cjs",
|
|
26
|
-
"test:
|
|
27
|
-
"test:
|
|
28
|
-
"test:
|
|
29
|
-
"test:
|
|
30
|
-
"test:
|
|
31
|
-
"test:
|
|
26
|
+
"test:cov": "NODE_OPTIONS='--experimental-loader @istanbuljs/esm-loader-hook' nyc --reporter=html npm test",
|
|
27
|
+
"old-test:jest": "npm run build && jest --verbose --silent --runInBand",
|
|
28
|
+
"old-test:cov": "npm run build && jest --coverage --silent --runInBand --collectCoverageFrom=src/**/*.js",
|
|
29
|
+
"old-test:log": "npm run build && jest --verbose",
|
|
30
|
+
"old-test:noBuild": "jest --verbose --runInBand --bail",
|
|
31
|
+
"old-test:unit": "jest --verbose --silent --runInBand --config jest.config.units.js",
|
|
32
|
+
"old-test:watch": "SKIP_SETUP=true jest --verbose --watch"
|
|
32
33
|
},
|
|
33
34
|
"repository": {
|
|
34
35
|
"type": "git",
|
|
@@ -53,107 +54,6 @@
|
|
|
53
54
|
"websocket"
|
|
54
55
|
],
|
|
55
56
|
"author": "David Hérault <dherault@gmail.com> (https://github.com/dherault)",
|
|
56
|
-
"contributors": [
|
|
57
|
-
"Adam Sweeting (https://github.com/adamelliottsweeting)",
|
|
58
|
-
"Adrien (https://github.com/AdrienGiboire)",
|
|
59
|
-
"Al Pal (https://github.com/againer)",
|
|
60
|
-
"Alessandro Palumbo (https://github.com/apalumbo)",
|
|
61
|
-
"Alex Blythe (https://github.com/ablythe)",
|
|
62
|
-
"allenhartwig (https://github.com/allenhartwig)",
|
|
63
|
-
"Andre Rabold (https://github.com/arabold)",
|
|
64
|
-
"Andrei Popovici (https://github.com/andreipopovici)",
|
|
65
|
-
"Anthony Liatsis (https://github.com/aliatsis)",
|
|
66
|
-
"Austen (https://github.com/ac360)",
|
|
67
|
-
"Austin Payne (https://github.com/austin-payne)",
|
|
68
|
-
"Ayush Gupta (https://github.com/AyushG3112)",
|
|
69
|
-
"Ben Cooling (https://github.com/bencooling)",
|
|
70
|
-
"Bob Thomas (https://github.com/bob-thomas)",
|
|
71
|
-
"Brandon Evans (https://github.com/BrandonE)",
|
|
72
|
-
"Cameron Cooper (https://github.com/cameroncooper)",
|
|
73
|
-
"Chris Trevino (https://github.com/darthtrevino)",
|
|
74
|
-
"Chris Watson (https://github.com/c24w)",
|
|
75
|
-
"Christoph Gysin (https://github.com/christophgysin)",
|
|
76
|
-
"Damon Williams (https://github.com/footballencarta)",
|
|
77
|
-
"Daniel Cottone <daniel.cottone@gmail.com> (https://github.com/daniel-cottone)",
|
|
78
|
-
"Daniel Parker (https://github.com/rlgod)",
|
|
79
|
-
"Dave Sole (https://github.com/dsole)",
|
|
80
|
-
"David Bunker (https://github.com/dbunker)",
|
|
81
|
-
"demetriusnunes (https://github.com/demetriusnunes)",
|
|
82
|
-
"DJCrabhat (https://github.com/djcrabhat)",
|
|
83
|
-
"Domas Lasauskas (https://github.com/domaslasauskas)",
|
|
84
|
-
"Dustin Belliston (https://github.com/dwbelliston)",
|
|
85
|
-
"Echo Nolan (https://github.com/enolan)",
|
|
86
|
-
"Egor Kislitsyn (https://github.com/minibikini)",
|
|
87
|
-
"Elliott Spira (https://github.com/em0ney)",
|
|
88
|
-
"Ethan Moistner (https://github.com/emmoistner)",
|
|
89
|
-
"Francis Upton IV (https://github.com/francisu)",
|
|
90
|
-
"Francisco Guimarães (https://github.com/franciscocpg)",
|
|
91
|
-
"G Roques (https://github.com/gbroques)",
|
|
92
|
-
"Gabriel Verdi (https://github.com/ansraliant)",
|
|
93
|
-
"Garun Vagidov (https://github.com/garunski)",
|
|
94
|
-
"Gert Jansen van Rensburg (https://github.com/gertjvr)",
|
|
95
|
-
"Guillaume Carbonneau (https://github.com/guillaume)",
|
|
96
|
-
"György Balássy (https://github.com/balassy)",
|
|
97
|
-
"James Relyea (https://github.com/james-relyea)",
|
|
98
|
-
"Jarda Snajdr (https://github.com/jsnajdr)",
|
|
99
|
-
"Jaryd Carolin (https://github.com/horyd)",
|
|
100
|
-
"Jeff Hall (https://github.com/electrikdevelopment)",
|
|
101
|
-
"jgilbert01 (https://github.com/jgilbert01)",
|
|
102
|
-
"Joaquin Ormaechea (https://github.com/jormaechea)",
|
|
103
|
-
"John McKim (https://github.com/johncmckim)",
|
|
104
|
-
"Jonas De Kegel (https://github.com/jlsjonas)",
|
|
105
|
-
"Joost Farla (https://github.com/joostfarla)",
|
|
106
|
-
"Joubert RedRat (https://github.com/joubertredrat)",
|
|
107
|
-
"Juanjo Diaz (https://github.com/juanjoDiaz)",
|
|
108
|
-
"Kaj Wiklund (https://github.com/kajwiklund)",
|
|
109
|
-
"Kiryl Yermakou (https://github.com/rma4ok)",
|
|
110
|
-
"kobanyan (https://github.com/kobanyan)",
|
|
111
|
-
"Leonardo Alifraco (https://github.com/lalifraco-devspark)",
|
|
112
|
-
"Leonardo Medici (https://github.com/doclm)",
|
|
113
|
-
"Luciano Jesus Lima (https://github.com/brazilianbytes)",
|
|
114
|
-
"Luke Chavers (https://github.com/vmadman)",
|
|
115
|
-
"Manuel Böhm (https://github.com/boehmers)",
|
|
116
|
-
"Marc Campbell (https://github.com/marccampbell)",
|
|
117
|
-
"Marco Lüthy (https://github.com/adieuadieu)",
|
|
118
|
-
"Mark Tse (https://github.com/neverendingqs)",
|
|
119
|
-
"Martin Micunda (https://github.com/martinmicunda)",
|
|
120
|
-
"Matt Hodgson (https://github.com/mhodgson)",
|
|
121
|
-
"Matt Jonker (https://github.com/msjonker)",
|
|
122
|
-
"Melvin Vermeer (https://github.com/melvinvermeer)",
|
|
123
|
-
"Michael MacDonald (https://github.com/mjmac)",
|
|
124
|
-
"Miso (Mike) Zmiric (https://github.com/mzmiric5)",
|
|
125
|
-
"Niall Riordan (https://github.com/njriordan)",
|
|
126
|
-
"Norimitsu Yamashita (https://github.com/nori3tsu)",
|
|
127
|
-
"Oliv (https://github.com/obearn)",
|
|
128
|
-
"Paul Esson (https://github.com/thepont)",
|
|
129
|
-
"Paul Pasmanik (https://github.com/ppasmanik)",
|
|
130
|
-
"Piotr Gasiorowski (https://github.com/WooDzu)",
|
|
131
|
-
"polaris340 (https://github.com/polaris340)",
|
|
132
|
-
"Quenby Mitchell (https://github.com/qswinson)",
|
|
133
|
-
"Ram Hardy (https://github.com/computerpunc)",
|
|
134
|
-
"Ramon Emilio Savinon (https://github.com/vaberay)",
|
|
135
|
-
"Rob Brazier (https://github.com/robbrazier)",
|
|
136
|
-
"Rowell Belen (https://github.com/bytekast)",
|
|
137
|
-
"Russell Schick (https://github.com/rschick)",
|
|
138
|
-
"Ryan Zhang (https://github.com/ryanzyy)",
|
|
139
|
-
"Selcuk Cihan (https://github.com/selcukcihan)",
|
|
140
|
-
"Shaun (https://github.com/starsprung)",
|
|
141
|
-
"Shine Li (https://github.com/shineli)",
|
|
142
|
-
"Stefan Siegl (https://github.com/stesie)",
|
|
143
|
-
"Stewart Gleadow (https://github.com/sgleadow)",
|
|
144
|
-
"Thales Minussi (https://github.com/tminussi)",
|
|
145
|
-
"Thang Minh Vu (https://github.com/ittus)",
|
|
146
|
-
"Tom St. Clair (https://github.com/tom-stclair)",
|
|
147
|
-
"Trevor Leach (https://github.com/trevor-leach)",
|
|
148
|
-
"Tuan Minh Huynh (https://github.com/tuanmh)",
|
|
149
|
-
"Utku Turunc (https://github.com/utkuturunc)",
|
|
150
|
-
"Vasiliy Solovey (https://github.com/miltador)",
|
|
151
|
-
"Dima Krutolianov (https://github.com/dimadk24)",
|
|
152
|
-
"Bryan Vaz (https://github.com/bryanvaz)",
|
|
153
|
-
"Justin Ng (https://github.com/njyjn)",
|
|
154
|
-
"Fernando Alvarez (https://github.com/jefer590)",
|
|
155
|
-
"Eric Carter (https://github.com/ericctsf)"
|
|
156
|
-
],
|
|
157
57
|
"engines": {
|
|
158
58
|
"node": ">=14.18.0"
|
|
159
59
|
},
|
|
@@ -186,7 +86,7 @@
|
|
|
186
86
|
"@hapi/h2o2": "^9.1.0",
|
|
187
87
|
"@hapi/hapi": "^20.2.2",
|
|
188
88
|
"@serverless/utils": "^6.7.0",
|
|
189
|
-
"aws-sdk": "^2.
|
|
89
|
+
"aws-sdk": "^2.1222.0",
|
|
190
90
|
"boxen": "^7.0.0",
|
|
191
91
|
"chalk": "^5.0.1",
|
|
192
92
|
"execa": "^6.1.0",
|
|
@@ -204,11 +104,12 @@
|
|
|
204
104
|
"p-memoize": "^7.1.0",
|
|
205
105
|
"p-retry": "^5.1.1",
|
|
206
106
|
"velocityjs": "^2.0.6",
|
|
207
|
-
"ws": "^8.
|
|
107
|
+
"ws": "^8.9.0"
|
|
208
108
|
},
|
|
209
109
|
"devDependencies": {
|
|
110
|
+
"@istanbuljs/esm-loader-hook": "^0.2.0",
|
|
210
111
|
"archiver": "^5.3.1",
|
|
211
|
-
"eslint": "^8.23.
|
|
112
|
+
"eslint": "^8.23.1",
|
|
212
113
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
213
114
|
"eslint-config-prettier": "^8.5.0",
|
|
214
115
|
"eslint-plugin-import": "^2.25.4",
|
|
@@ -217,6 +118,7 @@
|
|
|
217
118
|
"husky": "^8.0.1",
|
|
218
119
|
"lint-staged": "^13.0.3",
|
|
219
120
|
"mocha": "^10.0.0",
|
|
121
|
+
"nyc": "^15.1.0",
|
|
220
122
|
"prettier": "^2.7.1",
|
|
221
123
|
"serverless": "^3.22.0",
|
|
222
124
|
"standard-version": "^9.5.0"
|
package/src/ServerlessOffline.js
CHANGED
|
@@ -6,7 +6,8 @@ import {
|
|
|
6
6
|
defaultOptions,
|
|
7
7
|
SERVER_SHUTDOWN_TIMEOUT,
|
|
8
8
|
} from './config/index.js'
|
|
9
|
-
import { gray } from './config/colors.js'
|
|
9
|
+
import { gray, orange } from './config/colors.js'
|
|
10
|
+
import { createApiKey } from './utils/index.js'
|
|
10
11
|
|
|
11
12
|
export default class ServerlessOffline {
|
|
12
13
|
#cliOptions = null
|
|
@@ -205,9 +206,11 @@ export default class ServerlessOffline {
|
|
|
205
206
|
this.#lambda,
|
|
206
207
|
)
|
|
207
208
|
|
|
209
|
+
await this.#webSocket.createServer()
|
|
210
|
+
|
|
208
211
|
this.#webSocket.create(events)
|
|
209
212
|
|
|
210
|
-
|
|
213
|
+
await this.#webSocket.start()
|
|
211
214
|
}
|
|
212
215
|
|
|
213
216
|
#mergeOptions() {
|
|
@@ -320,6 +323,7 @@ export default class ServerlessOffline {
|
|
|
320
323
|
}
|
|
321
324
|
|
|
322
325
|
httpEvent.http.isHttpApi = true
|
|
326
|
+
|
|
323
327
|
if (
|
|
324
328
|
functionDefinition.httpApi &&
|
|
325
329
|
functionDefinition.httpApi.payload
|
|
@@ -333,7 +337,7 @@ export default class ServerlessOffline {
|
|
|
333
337
|
}
|
|
334
338
|
}
|
|
335
339
|
|
|
336
|
-
if (http
|
|
340
|
+
if (http?.private) {
|
|
337
341
|
hasPrivateHttpEvent = true
|
|
338
342
|
}
|
|
339
343
|
|
|
@@ -358,14 +362,26 @@ export default class ServerlessOffline {
|
|
|
358
362
|
|
|
359
363
|
// for simple API Key authentication model
|
|
360
364
|
if (hasPrivateHttpEvent) {
|
|
365
|
+
if (this.#options.apiKey) {
|
|
366
|
+
log.notice()
|
|
367
|
+
log.warning(
|
|
368
|
+
orange(`'--apiKey' is deprecated and will be removed in the next major version.
|
|
369
|
+
Please define the apiKey value in the 'provider.apiGateway.apiKeys' section of the serverless config.
|
|
370
|
+
If you are experiencing any issues please let us know: https://github.com/dherault/serverless-offline/issues`),
|
|
371
|
+
)
|
|
372
|
+
log.notice()
|
|
373
|
+
} else {
|
|
374
|
+
this.#options.apiKey = createApiKey()
|
|
375
|
+
}
|
|
376
|
+
|
|
361
377
|
log.notice(`Key with token: ${this.#options.apiKey}`)
|
|
362
378
|
|
|
363
379
|
if (this.#options.noAuth) {
|
|
364
380
|
log.notice(
|
|
365
|
-
|
|
381
|
+
`Authorizers are turned off. You do not need to use 'x-api-key' header.`,
|
|
366
382
|
)
|
|
367
383
|
} else {
|
|
368
|
-
log.notice(
|
|
384
|
+
log.notice(`Remember to use 'x-api-key' on the request headers.`)
|
|
369
385
|
}
|
|
370
386
|
}
|
|
371
387
|
|
|
@@ -2,7 +2,7 @@ export default {
|
|
|
2
2
|
apiKey: {
|
|
3
3
|
type: 'string',
|
|
4
4
|
usage:
|
|
5
|
-
'Defines the API key value to be used for endpoints marked as private. Defaults to a random hash.',
|
|
5
|
+
'[This option is deprecated] Defines the API key value to be used for endpoints marked as private. Defaults to a random hash.',
|
|
6
6
|
},
|
|
7
7
|
corsAllowHeaders: {
|
|
8
8
|
type: 'string',
|
|
@@ -24,6 +24,7 @@ import logRoutes from '../../utils/logRoutes.js'
|
|
|
24
24
|
import {
|
|
25
25
|
detectEncoding,
|
|
26
26
|
generateHapiPath,
|
|
27
|
+
getApiKeysValues,
|
|
27
28
|
getHttpApiCorsConfig,
|
|
28
29
|
jsonPath,
|
|
29
30
|
splitHandlerPathAndName,
|
|
@@ -33,6 +34,8 @@ const { parse, stringify } = JSON
|
|
|
33
34
|
const { assign, entries, keys } = Object
|
|
34
35
|
|
|
35
36
|
export default class HttpServer {
|
|
37
|
+
#apiKeysValues = null
|
|
38
|
+
|
|
36
39
|
#lambda = null
|
|
37
40
|
|
|
38
41
|
#options = null
|
|
@@ -44,6 +47,10 @@ export default class HttpServer {
|
|
|
44
47
|
#terminalInfo = []
|
|
45
48
|
|
|
46
49
|
constructor(serverless, options, lambda) {
|
|
50
|
+
this.#apiKeysValues = getApiKeysValues(
|
|
51
|
+
serverless.service.provider.apiGateway?.apiKeys ?? [],
|
|
52
|
+
)
|
|
53
|
+
|
|
47
54
|
this.#lambda = lambda
|
|
48
55
|
this.#options = options
|
|
49
56
|
this.#serverless = serverless
|
|
@@ -418,17 +425,22 @@ export default class HttpServer {
|
|
|
418
425
|
) {
|
|
419
426
|
const errorResponse = () =>
|
|
420
427
|
h
|
|
421
|
-
.response({
|
|
428
|
+
.response({
|
|
429
|
+
message: 'Forbidden',
|
|
430
|
+
})
|
|
422
431
|
.code(403)
|
|
423
|
-
.type('application/json')
|
|
424
432
|
.header('x-amzn-ErrorType', 'ForbiddenException')
|
|
433
|
+
.type('application/json')
|
|
425
434
|
|
|
426
|
-
const
|
|
435
|
+
const apiKey = request.headers['x-api-key']
|
|
427
436
|
|
|
428
|
-
if (
|
|
429
|
-
if (
|
|
437
|
+
if (apiKey) {
|
|
438
|
+
if (
|
|
439
|
+
apiKey !== this.#options.apiKey &&
|
|
440
|
+
!this.#apiKeysValues.has(apiKey)
|
|
441
|
+
) {
|
|
430
442
|
log.debug(
|
|
431
|
-
`Method ${method} of function ${functionKey} token ${
|
|
443
|
+
`Method ${method} of function ${functionKey} token ${apiKey} not valid`,
|
|
432
444
|
)
|
|
433
445
|
|
|
434
446
|
return errorResponse()
|
|
@@ -823,6 +835,7 @@ export default class HttpServer {
|
|
|
823
835
|
const parseCookies = (headerValue) => {
|
|
824
836
|
const cookieName = headerValue.slice(0, headerValue.indexOf('='))
|
|
825
837
|
const cookieValue = headerValue.slice(headerValue.indexOf('=') + 1)
|
|
838
|
+
|
|
826
839
|
h.state(cookieName, cookieValue, {
|
|
827
840
|
encoding: 'none',
|
|
828
841
|
strictHeader: false,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
1
3
|
import { exit } from 'node:process'
|
|
2
4
|
import { Server } from '@hapi/hapi'
|
|
3
5
|
import { log } from '@serverless/utils/log.js'
|
|
@@ -13,8 +15,22 @@ export default class HttpServer {
|
|
|
13
15
|
constructor(options, webSocketClients) {
|
|
14
16
|
this.#options = options
|
|
15
17
|
this.#webSocketClients = webSocketClients
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async #loadCerts(httpsProtocol) {
|
|
21
|
+
const [cert, key] = await Promise.all([
|
|
22
|
+
readFile(resolve(httpsProtocol, 'cert.pem'), 'utf-8'),
|
|
23
|
+
readFile(resolve(httpsProtocol, 'key.pem'), 'utf-8'),
|
|
24
|
+
])
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
cert,
|
|
28
|
+
key,
|
|
29
|
+
}
|
|
30
|
+
}
|
|
16
31
|
|
|
17
|
-
|
|
32
|
+
async createServer() {
|
|
33
|
+
const { host, websocketPort, httpsProtocol } = this.#options
|
|
18
34
|
|
|
19
35
|
const serverOptions = {
|
|
20
36
|
host,
|
|
@@ -24,6 +40,10 @@ export default class HttpServer {
|
|
|
24
40
|
// e.g. : /my-path is the same as /my-path/
|
|
25
41
|
stripTrailingSlash: true,
|
|
26
42
|
},
|
|
43
|
+
// https support
|
|
44
|
+
...(httpsProtocol != null && {
|
|
45
|
+
tls: await this.#loadCerts(httpsProtocol),
|
|
46
|
+
}),
|
|
27
47
|
}
|
|
28
48
|
|
|
29
49
|
this.#server = new Server(serverOptions)
|
|
@@ -6,19 +6,39 @@ import WebSocketServer from './WebSocketServer.js'
|
|
|
6
6
|
export default class WebSocket {
|
|
7
7
|
#httpServer = null
|
|
8
8
|
|
|
9
|
+
#lambda = null
|
|
10
|
+
|
|
11
|
+
#options = null
|
|
12
|
+
|
|
13
|
+
#serverless = null
|
|
14
|
+
|
|
9
15
|
#webSocketServer = null
|
|
10
16
|
|
|
11
17
|
constructor(serverless, options, lambda) {
|
|
12
|
-
|
|
18
|
+
this.#lambda = lambda
|
|
19
|
+
this.#options = options
|
|
20
|
+
this.#serverless = serverless
|
|
21
|
+
}
|
|
13
22
|
|
|
14
|
-
|
|
23
|
+
async createServer() {
|
|
24
|
+
const webSocketClients = new WebSocketClients(
|
|
25
|
+
this.#serverless,
|
|
26
|
+
this.#options,
|
|
27
|
+
this.#lambda,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
this.#httpServer = new HttpServer(this.#options, webSocketClients)
|
|
31
|
+
|
|
32
|
+
await this.#httpServer.createServer()
|
|
15
33
|
|
|
16
34
|
// share server
|
|
17
35
|
this.#webSocketServer = new WebSocketServer(
|
|
18
|
-
options,
|
|
36
|
+
this.#options,
|
|
19
37
|
webSocketClients,
|
|
20
38
|
this.#httpServer.server,
|
|
21
39
|
)
|
|
40
|
+
|
|
41
|
+
await this.#webSocketServer.createServer()
|
|
22
42
|
}
|
|
23
43
|
|
|
24
44
|
start() {
|
|
@@ -7,14 +7,19 @@ export default class WebSocketServer {
|
|
|
7
7
|
|
|
8
8
|
#options = null
|
|
9
9
|
|
|
10
|
+
#sharedServer = null
|
|
11
|
+
|
|
10
12
|
#webSocketClients = null
|
|
11
13
|
|
|
12
14
|
constructor(options, webSocketClients, sharedServer) {
|
|
13
15
|
this.#options = options
|
|
16
|
+
this.#sharedServer = sharedServer
|
|
14
17
|
this.#webSocketClients = webSocketClients
|
|
18
|
+
}
|
|
15
19
|
|
|
20
|
+
async createServer() {
|
|
16
21
|
const server = new WsWebSocketServer({
|
|
17
|
-
server: sharedServer,
|
|
22
|
+
server: this.#sharedServer,
|
|
18
23
|
verifyClient: async ({ req }, cb) => {
|
|
19
24
|
const connectionId = createUniqueId()
|
|
20
25
|
const key = req.headers['sec-websocket-key']
|
package/src/utils/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { default as createUniqueId } from './createUniqueId.js'
|
|
|
5
5
|
export { default as detectExecutable } from './detectExecutable.js'
|
|
6
6
|
export { default as formatToClfTime } from './formatToClfTime.js'
|
|
7
7
|
export { default as generateHapiPath } from './generateHapiPath.js'
|
|
8
|
+
export { default as getApiKeysValues } from './getApiKeysValues.js'
|
|
8
9
|
export { default as getHttpApiCorsConfig } from './getHttpApiCorsConfig.js'
|
|
9
10
|
export { default as jsonPath } from './jsonPath.js'
|
|
10
11
|
export { default as lowerCaseKeys } from './lowerCaseKeys.js'
|