serverless-offline 8.3.1 → 8.6.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 +83 -10
- package/dist/ServerlessOffline.js +19 -2
- package/dist/config/commandOptions.js +4 -0
- package/dist/config/defaultOptions.js +1 -0
- package/dist/events/{http/authCanExecuteResource.js → authCanExecuteResource.js} +0 -0
- package/dist/events/{http/authFunctionNameExtractor.js → authFunctionNameExtractor.js} +1 -1
- package/dist/events/{http/authMatchPolicyResource.js → authMatchPolicyResource.js} +0 -0
- package/dist/events/http/HttpServer.js +48 -10
- package/dist/events/http/createAuthScheme.js +3 -2
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEvent.js +21 -1
- package/dist/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +28 -2
- package/dist/events/websocket/WebSocketClients.js +259 -26
- package/dist/events/websocket/WebSocketServer.js +50 -4
- package/dist/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +99 -0
- package/dist/events/websocket/lambda-events/index.js +8 -0
- package/dist/lambda/LambdaFunction.js +3 -2
- package/dist/lambda/handler-runner/HandlerRunner.js +9 -1
- package/dist/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +9 -1
- package/dist/lambda/handler-runner/docker-runner/DockerContainer.js +4 -1
- package/dist/lambda/handler-runner/go-runner/GoRunner.js +211 -0
- package/dist/lambda/handler-runner/go-runner/index.js +15 -0
- package/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js +28 -7
- package/dist/lambda/handler-runner/java-runner/JavaRunner.js +1 -2
- package/dist/lambda/handler-runner/ruby-runner/RubyRunner.js +0 -2
- package/dist/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +2 -0
- package/dist/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +3 -2
- package/dist/lambda/routes/invocations/invocationsRoute.js +2 -1
- package/dist/utils/checkGoVersion.js +27 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/splitHandlerPathAndName.js +13 -9
- package/package.json +48 -19
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ To do so, it starts an HTTP server that handles the request's lifecycle like API
|
|
|
31
31
|
|
|
32
32
|
**Features:**
|
|
33
33
|
|
|
34
|
-
- [Node.js](https://nodejs.org), [Python](https://www.python.org), [Ruby](https://www.ruby-lang.org)
|
|
34
|
+
- [Node.js](https://nodejs.org), [Python](https://www.python.org), [Ruby](https://www.ruby-lang.org) and [Go](https://golang.org) λ runtimes.
|
|
35
35
|
- Velocity templates support.
|
|
36
36
|
- Lazy loading of your handler files.
|
|
37
37
|
- And more: integrations, authorizers, proxies, timeouts, responseParameters, HTTPS, CORS, etc...
|
|
@@ -49,6 +49,7 @@ This plugin is updated by its users, I just do maintenance and ensure that PRs a
|
|
|
49
49
|
- [Custom authorizers](#custom-authorizers)
|
|
50
50
|
- [Remote authorizers](#remote-authorizers)
|
|
51
51
|
- [JWT authorizers](#jwt-authorizers)
|
|
52
|
+
- [Serverless plugin authorizers](#serverless-plugin-authorizers)
|
|
52
53
|
- [Custom headers](#custom-headers)
|
|
53
54
|
- [Environment variables](#environment-variables)
|
|
54
55
|
- [AWS API Gateway Features](#aws-api-gateway-features)
|
|
@@ -115,6 +116,7 @@ All CLI options are optional:
|
|
|
115
116
|
--corsDisallowCredentials When provided, the default Access-Control-Allow-Credentials header value will be passed as 'false'. Default: true
|
|
116
117
|
--corsExposedHeaders Used as additional Access-Control-Exposed-Headers header value for responses. Delimit multiple values with commas. Default: 'WWW-Authenticate,Server-Authorization'
|
|
117
118
|
--disableCookieValidation Used to disable cookie-validation on hapi.js-server
|
|
119
|
+
--disableScheduledEvents Disables all scheduled events. Overrides configurations in serverless.yml.
|
|
118
120
|
--dockerHost The host name of Docker. Default: localhost
|
|
119
121
|
--dockerHostServicePath Defines service path which is used by SLS running inside Docker container
|
|
120
122
|
--dockerNetwork The network that the Docker container will connect to
|
|
@@ -242,7 +244,7 @@ to calling it via `aws-sdk`.
|
|
|
242
244
|
|
|
243
245
|
## The `process.env.IS_OFFLINE` variable
|
|
244
246
|
|
|
245
|
-
Will be `"true"` in your handlers and
|
|
247
|
+
Will be `"true"` in your handlers and throughout the plugin.
|
|
246
248
|
|
|
247
249
|
## Docker and Layers
|
|
248
250
|
|
|
@@ -359,14 +361,36 @@ defined in the `serverless.yml` can be used to validate the token and scopes in
|
|
|
359
361
|
the signature of the JWT is not validated with the defined issuer. Since this is a security risk, this feature is
|
|
360
362
|
only enabled with the `--ignoreJWTSignature` flag. Make sure to only set this flag for local development work.
|
|
361
363
|
|
|
364
|
+
## Serverless plugin authorizers
|
|
365
|
+
|
|
366
|
+
If your authentication needs are custom and not satisfied by the existing capabilities of the Serverless offline project, you can inject your own authentication strategy. To inject a custom strategy for Lambda invocation, you define a custom variable under `serverless-offline` called `authenticationProvider` in the serverless.yml file. The value of the custom variable will be used to `require(your authenticationProvider value)` where the location is expected to return a function with the following signature.
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
module.exports = function (endpoint, functionKey, method, path) {
|
|
370
|
+
return {
|
|
371
|
+
name: 'your strategy name',
|
|
372
|
+
scheme: 'your scheme name',
|
|
373
|
+
|
|
374
|
+
getAuthenticateFunction: () => ({
|
|
375
|
+
async authenticate(request, h) {
|
|
376
|
+
// your implementation
|
|
377
|
+
},
|
|
378
|
+
}),
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
A working example of injecting a custom authorization provider can be found in the projects integration tests under the folder `custom-authentication`.
|
|
384
|
+
|
|
362
385
|
## Custom headers
|
|
363
386
|
|
|
364
387
|
You are able to use some custom headers in your request to gain more control over the requestContext object.
|
|
365
388
|
|
|
366
|
-
| Header | Event key |
|
|
367
|
-
| ------------------------------- | ----------------------------------------------------------- |
|
|
368
|
-
| cognito-identity-id | event.requestContext.identity.cognitoIdentityId |
|
|
369
|
-
| cognito-authentication-provider | event.requestContext.identity.cognitoAuthenticationProvider |
|
|
389
|
+
| Header | Event key | Example |
|
|
390
|
+
| ------------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
|
|
391
|
+
| cognito-identity-id | event.requestContext.identity.cognitoIdentityId | |
|
|
392
|
+
| cognito-authentication-provider | event.requestContext.identity.cognitoAuthenticationProvider | |
|
|
393
|
+
| sls-offline-authorizer-override | event.requestContext.authorizer | { "iam": {"cognitoUser": { "amr": ["unauthenticated"], "identityId": "abc123" }}} |
|
|
370
394
|
|
|
371
395
|
By doing this you are now able to change those values using a custom header. This can help you with easier authentication or retrieving the userId from a `cognitoAuthenticationProvider` value.
|
|
372
396
|
|
|
@@ -507,8 +531,6 @@ Where the `event` is received in the lambda handler function.
|
|
|
507
531
|
|
|
508
532
|
There's support for [websocketsApiRouteSelectionExpression](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-selection-expressions.html) in it's basic form: `$request.body.x.y.z`, where the default value is `$request.body.action`.
|
|
509
533
|
|
|
510
|
-
Authorizers and wss:// are currently not supported.
|
|
511
|
-
|
|
512
534
|
## Usage with Webpack
|
|
513
535
|
|
|
514
536
|
Use [serverless-webpack](https://github.com/serverless-heaven/serverless-webpack) to compile and bundle your ES-next code
|
|
@@ -572,7 +594,54 @@ For each debug run:
|
|
|
572
594
|
|
|
573
595
|
The system will start in wait status. This will also automatically start the chrome browser and wait for you to set breakpoints for inspection. Set the breakpoints as needed and, then, click the play button for the debugging to continue.
|
|
574
596
|
|
|
575
|
-
Depending on the breakpoint, you may need to call the URL path for your function in
|
|
597
|
+
Depending on the breakpoint, you may need to call the URL path for your function in separate browser window for your serverless function to be run and made available for debugging.
|
|
598
|
+
|
|
599
|
+
### Interactive Debugging with Visual Studio Code (VSC)
|
|
600
|
+
|
|
601
|
+
With newer versions of node (6.3+) the node inspector is already part of your node environment and you can take advantage of debugging inside your IDE with source-map support. Here is the example configuration to debug interactively with VSC. It has two steps.
|
|
602
|
+
|
|
603
|
+
#### Step 1 : Adding a launch configuration in IDE
|
|
604
|
+
|
|
605
|
+
Add a new [launch configuration](https://code.visualstudio.com/docs/editor/debugging) to VSC like this:
|
|
606
|
+
|
|
607
|
+
```json
|
|
608
|
+
{
|
|
609
|
+
|
|
610
|
+
"type": "node",
|
|
611
|
+
"request": "launch",
|
|
612
|
+
"name": "Debug Serverless Offline",
|
|
613
|
+
"cwd": "${workspaceFolder}",
|
|
614
|
+
"runtimeExecutable": "npm",
|
|
615
|
+
"runtimeArgs": [
|
|
616
|
+
"run",
|
|
617
|
+
"debug"
|
|
618
|
+
],
|
|
619
|
+
"sourceMaps": true
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
#### Step2 : Adding a debug script
|
|
625
|
+
|
|
626
|
+
You will also need to add a `debug` script reference in your `package.json file`
|
|
627
|
+
|
|
628
|
+
Add this to the `scripts` section:
|
|
629
|
+
|
|
630
|
+
> Unix/Mac: `"debug" : "export SLS_DEBUG=* && node --inspect /usr/local/bin/serverless offline"`
|
|
631
|
+
|
|
632
|
+
> Windows: `"debug": "SET SLS_DEBUG=* && node --inspect node_modules\\serverless\\bin\\serverless offline"`
|
|
633
|
+
|
|
634
|
+
Example:
|
|
635
|
+
|
|
636
|
+
```json
|
|
637
|
+
....
|
|
638
|
+
"scripts": {
|
|
639
|
+
"debug" : "SET SLS_DEBUG=* && node --inspect node_modules\\serverless\\bin\\serverless offline"
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
In VSC, you can, then, add breakpoints to your code. To start a debug sessions you can either start your script in `package.json` by clicking the hovering debug intellisense icon or by going to your debug pane and selecting the Debug Serverless Offline configuration.
|
|
644
|
+
|
|
576
645
|
|
|
577
646
|
## Resource permissions and AWS profile
|
|
578
647
|
|
|
@@ -743,6 +812,10 @@ We try to follow [Airbnb's JavaScript Style Guide](https://github.com/airbnb/jav
|
|
|
743
812
|
| :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: |
|
|
744
813
|
| [lteacher](https://github.com/lteacher) | [martinmicunda](https://github.com/martinmicunda) | [nori3tsu](https://github.com/nori3tsu) | [ppasmanik](https://github.com/ppasmanik) | [ryanzyy](https://github.com/ryanzyy) |
|
|
745
814
|
|
|
746
|
-
| [<img alt="m0ppers" src="https://avatars3.githubusercontent.com/u/819421?v=4&s=117" width="117">](https://github.com/m0ppers) | [<img alt="footballencarta" src="https://avatars0.githubusercontent.com/u/1312258?v=4&s=117" width="117">](https://github.com/footballencarta) | [<img alt="bryanvaz" src="https://avatars0.githubusercontent.com/u/9157498?v=4&s=117" width="117">](https://github.com/bryanvaz) | [<img alt="njyjn" src="https://avatars.githubusercontent.com/u/10694375?v=4&s=117" width="117">](https://github.com/njyjn) |
|
|
815
|
+
| [<img alt="m0ppers" src="https://avatars3.githubusercontent.com/u/819421?v=4&s=117" width="117">](https://github.com/m0ppers) | [<img alt="footballencarta" src="https://avatars0.githubusercontent.com/u/1312258?v=4&s=117" width="117">](https://github.com/footballencarta) | [<img alt="bryanvaz" src="https://avatars0.githubusercontent.com/u/9157498?v=4&s=117" width="117">](https://github.com/bryanvaz) | [<img alt="njyjn" src="https://avatars.githubusercontent.com/u/10694375?v=4&s=117" width="117">](https://github.com/njyjn) | |
|
|
747
816
|
| :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: | ------------------------------------- |
|
|
748
817
|
| [m0ppers](https://github.com/m0ppers) | [footballencarta](https://github.com/footballencarta) | [bryanvaz](https://github.com/bryanvaz) | [njyjn](https://github.com/njyjn) | [kdybicz](https://github.com/kdybicz) |
|
|
818
|
+
|
|
819
|
+
| [<img alt="ericctsf" src="https://avatars.githubusercontent.com/u/42775388?s=400&v=4" width="117">](https://github.com/ericctsf) | | | | |
|
|
820
|
+
| :------------------------------------------------------------------------------------------------------------------------------: | :-: | :-: | :-: | :-: |
|
|
821
|
+
| [ericctsf](https://github.com/erictsf) | | | | |
|
|
@@ -96,6 +96,10 @@ class ServerlessOffline {
|
|
|
96
96
|
lifecycleEvents: ['init', 'ready', 'end'],
|
|
97
97
|
options: _index2.commandOptions,
|
|
98
98
|
usage: 'Simulates API Gateway to call your lambda functions offline using backward compatible initialization.'
|
|
99
|
+
},
|
|
100
|
+
functionsUpdated: {
|
|
101
|
+
type: 'entrypoint',
|
|
102
|
+
lifecycleEvents: ['cleanup']
|
|
99
103
|
}
|
|
100
104
|
},
|
|
101
105
|
lifecycleEvents: ['start'],
|
|
@@ -106,6 +110,7 @@ class ServerlessOffline {
|
|
|
106
110
|
this.hooks = {
|
|
107
111
|
'offline:start:init': this.start.bind(this),
|
|
108
112
|
'offline:start:ready': this.ready.bind(this),
|
|
113
|
+
'offline:functionsUpdated:cleanup': this.cleanupFunctions.bind(this),
|
|
109
114
|
'offline:start': this._startWithExplicitEnd.bind(this),
|
|
110
115
|
'offline:start:end': this.end.bind(this)
|
|
111
116
|
};
|
|
@@ -150,7 +155,7 @@ class ServerlessOffline {
|
|
|
150
155
|
eventModules.push(this._createHttp(httpEvents));
|
|
151
156
|
}
|
|
152
157
|
|
|
153
|
-
if (scheduleEvents.length > 0) {
|
|
158
|
+
if (!_classPrivateFieldLooseBase(this, _options)[_options].disableScheduledEvents && scheduleEvents.length > 0) {
|
|
154
159
|
eventModules.push(this._createSchedule(scheduleEvents));
|
|
155
160
|
}
|
|
156
161
|
|
|
@@ -203,6 +208,13 @@ class ServerlessOffline {
|
|
|
203
208
|
process.exit(0);
|
|
204
209
|
}
|
|
205
210
|
}
|
|
211
|
+
|
|
212
|
+
async cleanupFunctions() {
|
|
213
|
+
if (_classPrivateFieldLooseBase(this, _lambda)[_lambda]) {
|
|
214
|
+
(0, _serverlessLog.default)('Forcing cleanup of Lambda functions');
|
|
215
|
+
await _classPrivateFieldLooseBase(this, _lambda)[_lambda].cleanup();
|
|
216
|
+
}
|
|
217
|
+
}
|
|
206
218
|
/**
|
|
207
219
|
* Entry point for the plugin (sls offline) when running 'sls offline'
|
|
208
220
|
* The call to this.end() would terminate the process before 'offline:start:end' could be consumed
|
|
@@ -398,7 +410,12 @@ class ServerlessOffline {
|
|
|
398
410
|
}
|
|
399
411
|
|
|
400
412
|
httpEvent.http.isHttpApi = true;
|
|
401
|
-
|
|
413
|
+
|
|
414
|
+
if (functionDefinition.httpApi && functionDefinition.httpApi.payload) {
|
|
415
|
+
httpEvent.http.payload = functionDefinition.httpApi.payload;
|
|
416
|
+
} else {
|
|
417
|
+
httpEvent.http.payload = service.provider.httpApi && service.provider.httpApi.payload ? service.provider.httpApi.payload : '2.0';
|
|
418
|
+
}
|
|
402
419
|
}
|
|
403
420
|
|
|
404
421
|
if (http && http.private) {
|
|
@@ -29,6 +29,10 @@ var _default = {
|
|
|
29
29
|
usage: 'Used to disable cookie-validation on hapi.js-server',
|
|
30
30
|
type: 'boolean'
|
|
31
31
|
},
|
|
32
|
+
disableScheduledEvents: {
|
|
33
|
+
usage: 'Disables all scheduled events. Overrides configurations in serverless.yml. Default: false',
|
|
34
|
+
type: 'boolean'
|
|
35
|
+
},
|
|
32
36
|
enforceSecureCookies: {
|
|
33
37
|
usage: 'Enforce secure cookies',
|
|
34
38
|
type: 'boolean'
|
|
File without changes
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.default = authFunctionNameExtractor;
|
|
7
7
|
|
|
8
|
-
var _serverlessLog2 = _interopRequireDefault(require("
|
|
8
|
+
var _serverlessLog2 = _interopRequireDefault(require("../serverlessLog.js"));
|
|
9
9
|
|
|
10
10
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
11
|
|
|
File without changes
|
|
@@ -9,13 +9,15 @@ var _buffer = require("buffer");
|
|
|
9
9
|
|
|
10
10
|
var _fs = require("fs");
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var pathUtils = _interopRequireWildcard(require("path"));
|
|
13
13
|
|
|
14
14
|
var _h2o = _interopRequireDefault(require("@hapi/h2o2"));
|
|
15
15
|
|
|
16
16
|
var _hapi = require("@hapi/hapi");
|
|
17
17
|
|
|
18
|
-
var
|
|
18
|
+
var _module = require("module");
|
|
19
|
+
|
|
20
|
+
var _authFunctionNameExtractor = _interopRequireDefault(require("../authFunctionNameExtractor.js"));
|
|
19
21
|
|
|
20
22
|
var _authJWTSettingsExtractor = _interopRequireDefault(require("./authJWTSettingsExtractor.js"));
|
|
21
23
|
|
|
@@ -39,12 +41,12 @@ var _index2 = require("../../utils/index.js");
|
|
|
39
41
|
|
|
40
42
|
var _LambdaProxyIntegrationEventV = _interopRequireDefault(require("./lambda-events/LambdaProxyIntegrationEventV2.js"));
|
|
41
43
|
|
|
44
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
45
|
+
|
|
42
46
|
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
43
47
|
|
|
44
48
|
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
45
49
|
|
|
46
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
47
|
-
|
|
48
50
|
function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; }
|
|
49
51
|
|
|
50
52
|
var id = 0;
|
|
@@ -134,8 +136,8 @@ class HttpServer {
|
|
|
134
136
|
|
|
135
137
|
if (typeof httpsProtocol === 'string' && httpsProtocol.length > 0) {
|
|
136
138
|
serverOptions.tls = {
|
|
137
|
-
cert: (0, _fs.readFileSync)((0,
|
|
138
|
-
key: (0, _fs.readFileSync)((0,
|
|
139
|
+
cert: (0, _fs.readFileSync)((0, pathUtils.resolve)(httpsProtocol, 'cert.pem'), 'ascii'),
|
|
140
|
+
key: (0, _fs.readFileSync)((0, pathUtils.resolve)(httpsProtocol, 'key.pem'), 'ascii')
|
|
139
141
|
};
|
|
140
142
|
} // Hapijs server creation
|
|
141
143
|
|
|
@@ -428,6 +430,36 @@ class HttpServer {
|
|
|
428
430
|
return authStrategyName;
|
|
429
431
|
}
|
|
430
432
|
|
|
433
|
+
_setAuthorizationStrategy(endpoint, functionKey, method, path) {
|
|
434
|
+
var _customizations$offli;
|
|
435
|
+
|
|
436
|
+
/*
|
|
437
|
+
* The authentication strategy can be provided outside of this project
|
|
438
|
+
* by injecting the provider through a custom variable in the serverless.yml.
|
|
439
|
+
*
|
|
440
|
+
* see the example in the tests for more details
|
|
441
|
+
* /tests/integration/custom-authentication
|
|
442
|
+
*/
|
|
443
|
+
const customizations = _classPrivateFieldLooseBase(this, _serverless)[_serverless].service.custom;
|
|
444
|
+
|
|
445
|
+
if (customizations && (_customizations$offli = customizations.offline) !== null && _customizations$offli !== void 0 && _customizations$offli.customAuthenticationProvider) {
|
|
446
|
+
const root = pathUtils.resolve(_classPrivateFieldLooseBase(this, _serverless)[_serverless].serviceDir, 'require-resolver');
|
|
447
|
+
const customRequire = (0, _module.createRequire)(root);
|
|
448
|
+
const provider = customRequire(customizations.offline.customAuthenticationProvider);
|
|
449
|
+
const strategy = provider(endpoint, functionKey, method, path);
|
|
450
|
+
|
|
451
|
+
_classPrivateFieldLooseBase(this, _server)[_server].auth.scheme(strategy.scheme, strategy.getAuthenticateFunction);
|
|
452
|
+
|
|
453
|
+
_classPrivateFieldLooseBase(this, _server)[_server].auth.strategy(strategy.name, strategy.scheme);
|
|
454
|
+
|
|
455
|
+
return strategy.name;
|
|
456
|
+
} // If the endpoint has an authorization function, create an authStrategy for the route
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
const authStrategyName = _classPrivateFieldLooseBase(this, _options)[_options].noAuth ? null : this._configureJWTAuthorization(endpoint, functionKey, method, path) || this._configureAuthorization(endpoint, functionKey, method, path);
|
|
460
|
+
return authStrategyName;
|
|
461
|
+
}
|
|
462
|
+
|
|
431
463
|
createRoutes(functionKey, httpEvent, handler) {
|
|
432
464
|
const [handlerPath] = (0, _index2.splitHandlerPathAndName)(handler);
|
|
433
465
|
let method;
|
|
@@ -455,7 +487,7 @@ class HttpServer {
|
|
|
455
487
|
hapiPath = (0, _index2.generateHapiPath)(path, _classPrivateFieldLooseBase(this, _options)[_options], _classPrivateFieldLooseBase(this, _serverless)[_serverless]);
|
|
456
488
|
}
|
|
457
489
|
|
|
458
|
-
const endpoint = new _Endpoint.default((0,
|
|
490
|
+
const endpoint = new _Endpoint.default((0, pathUtils.join)(_classPrivateFieldLooseBase(this, _serverless)[_serverless].config.servicePath, handlerPath), httpEvent, this.v3Utils);
|
|
459
491
|
const stage = endpoint.isHttpApi ? '$default' : _classPrivateFieldLooseBase(this, _options)[_options].stage || _classPrivateFieldLooseBase(this, _serverless)[_serverless].service.provider.stage;
|
|
460
492
|
const protectedRoutes = [];
|
|
461
493
|
|
|
@@ -477,10 +509,10 @@ class HttpServer {
|
|
|
477
509
|
server,
|
|
478
510
|
stage: endpoint.isHttpApi || _classPrivateFieldLooseBase(this, _options)[_options].noPrependStageInUrl ? null : stage,
|
|
479
511
|
invokePath: `/2015-03-31/functions/${functionKey}/invocations`
|
|
480
|
-
});
|
|
512
|
+
});
|
|
481
513
|
|
|
514
|
+
const authStrategyName = this._setAuthorizationStrategy(endpoint, functionKey, method, path);
|
|
482
515
|
|
|
483
|
-
const authStrategyName = _classPrivateFieldLooseBase(this, _options)[_options].noAuth ? null : this._configureJWTAuthorization(endpoint, functionKey, method, path) || this._configureAuthorization(endpoint, functionKey, method, path);
|
|
484
516
|
let cors = null;
|
|
485
517
|
|
|
486
518
|
if (endpoint.cors) {
|
|
@@ -538,6 +570,12 @@ class HttpServer {
|
|
|
538
570
|
};
|
|
539
571
|
}
|
|
540
572
|
|
|
573
|
+
const additionalRequestContext = {};
|
|
574
|
+
|
|
575
|
+
if (httpEvent.operationId) {
|
|
576
|
+
additionalRequestContext.operationName = httpEvent.operationId;
|
|
577
|
+
}
|
|
578
|
+
|
|
541
579
|
hapiOptions.tags = ['api'];
|
|
542
580
|
|
|
543
581
|
const hapiHandler = async (request, h) => {
|
|
@@ -682,7 +720,7 @@ class HttpServer {
|
|
|
682
720
|
}
|
|
683
721
|
} else if (integration === 'AWS_PROXY') {
|
|
684
722
|
const stageVariables = _classPrivateFieldLooseBase(this, _serverless)[_serverless].service.custom ? _classPrivateFieldLooseBase(this, _serverless)[_serverless].service.custom.stageVariables : null;
|
|
685
|
-
const lambdaProxyIntegrationEvent = endpoint.isHttpApi && endpoint.payload === '2.0' ? new _LambdaProxyIntegrationEventV.default(request, stage, endpoint.routeKey, stageVariables, this.v3Utils) : new _index.LambdaProxyIntegrationEvent(request, stage, requestPath, stageVariables, endpoint.isHttpApi ? endpoint.routeKey : null, this.v3Utils);
|
|
723
|
+
const lambdaProxyIntegrationEvent = endpoint.isHttpApi && endpoint.payload === '2.0' ? new _LambdaProxyIntegrationEventV.default(request, stage, endpoint.routeKey, stageVariables, additionalRequestContext, this.v3Utils) : new _index.LambdaProxyIntegrationEvent(request, stage, requestPath, stageVariables, endpoint.isHttpApi ? endpoint.routeKey : null, additionalRequestContext, this.v3Utils);
|
|
686
724
|
event = lambdaProxyIntegrationEvent.create();
|
|
687
725
|
}
|
|
688
726
|
|
|
@@ -7,7 +7,7 @@ exports.default = createAuthScheme;
|
|
|
7
7
|
|
|
8
8
|
var _boom = _interopRequireDefault(require("@hapi/boom"));
|
|
9
9
|
|
|
10
|
-
var _authCanExecuteResource = _interopRequireDefault(require("
|
|
10
|
+
var _authCanExecuteResource = _interopRequireDefault(require("../authCanExecuteResource.js"));
|
|
11
11
|
|
|
12
12
|
var _debugLog = _interopRequireDefault(require("../../debugLog.js"));
|
|
13
13
|
|
|
@@ -112,7 +112,8 @@ function createAuthScheme(authorizerOptions, provider, lambda, {
|
|
|
112
112
|
lambdaFunction.setEvent(event);
|
|
113
113
|
|
|
114
114
|
try {
|
|
115
|
-
const result = await lambdaFunction.runHandler();
|
|
115
|
+
const result = await lambdaFunction.runHandler();
|
|
116
|
+
if (result === 'Unauthorized') return _boom.default.unauthorized('Unauthorized'); // return processResponse(null, result)
|
|
116
117
|
|
|
117
118
|
const policy = result; // Validate that the policy document has the principalId set
|
|
118
119
|
|
|
@@ -39,8 +39,10 @@ var _stage = /*#__PURE__*/_classPrivateFieldLooseKey("stage");
|
|
|
39
39
|
|
|
40
40
|
var _stageVariables = /*#__PURE__*/_classPrivateFieldLooseKey("stageVariables");
|
|
41
41
|
|
|
42
|
+
var _additionalRequestContext = /*#__PURE__*/_classPrivateFieldLooseKey("additionalRequestContext");
|
|
43
|
+
|
|
42
44
|
class LambdaProxyIntegrationEvent {
|
|
43
|
-
constructor(request, stage, path, stageVariables, routeKey = null, v3Utils) {
|
|
45
|
+
constructor(request, stage, path, stageVariables, routeKey = null, additionalRequestContext = null, v3Utils) {
|
|
44
46
|
Object.defineProperty(this, _path, {
|
|
45
47
|
writable: true,
|
|
46
48
|
value: null
|
|
@@ -61,11 +63,16 @@ class LambdaProxyIntegrationEvent {
|
|
|
61
63
|
writable: true,
|
|
62
64
|
value: null
|
|
63
65
|
});
|
|
66
|
+
Object.defineProperty(this, _additionalRequestContext, {
|
|
67
|
+
writable: true,
|
|
68
|
+
value: null
|
|
69
|
+
});
|
|
64
70
|
_classPrivateFieldLooseBase(this, _path)[_path] = path;
|
|
65
71
|
_classPrivateFieldLooseBase(this, _routeKey)[_routeKey] = routeKey;
|
|
66
72
|
_classPrivateFieldLooseBase(this, _request)[_request] = request;
|
|
67
73
|
_classPrivateFieldLooseBase(this, _stage)[_stage] = stage;
|
|
68
74
|
_classPrivateFieldLooseBase(this, _stageVariables)[_stageVariables] = stageVariables;
|
|
75
|
+
_classPrivateFieldLooseBase(this, _additionalRequestContext)[_additionalRequestContext] = additionalRequestContext || {};
|
|
69
76
|
|
|
70
77
|
if (v3Utils) {
|
|
71
78
|
this.log = v3Utils.log;
|
|
@@ -103,6 +110,18 @@ class LambdaProxyIntegrationEvent {
|
|
|
103
110
|
|
|
104
111
|
const headers = (0, _index.parseHeaders)(rawHeaders || []) || {};
|
|
105
112
|
|
|
113
|
+
if (headers['sls-offline-authorizer-override']) {
|
|
114
|
+
try {
|
|
115
|
+
authAuthorizer = parse(headers['sls-offline-authorizer-override']);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
if (this.log) {
|
|
118
|
+
this.log.error('Could not parse header sls-offline-authorizer-override, make sure it is correct JSON');
|
|
119
|
+
} else {
|
|
120
|
+
console.error('Serverless-offline: Could not parse header sls-offline-authorizer-override make sure it is correct JSON.');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
106
125
|
if (body) {
|
|
107
126
|
if (typeof body !== 'string') {
|
|
108
127
|
// this.#request.payload is NOT the same as the rawPayload
|
|
@@ -205,6 +224,7 @@ class LambdaProxyIntegrationEvent {
|
|
|
205
224
|
userAgent: _headers['user-agent'] || '',
|
|
206
225
|
userArn: 'offlineContext_userArn'
|
|
207
226
|
},
|
|
227
|
+
operationName: _classPrivateFieldLooseBase(this, _additionalRequestContext)[_additionalRequestContext].operationName,
|
|
208
228
|
path: _classPrivateFieldLooseBase(this, _path)[_path],
|
|
209
229
|
protocol: 'HTTP/1.1',
|
|
210
230
|
requestId: (0, _index.createUniqueId)(),
|
|
@@ -36,8 +36,10 @@ var _stage = /*#__PURE__*/_classPrivateFieldLooseKey("stage");
|
|
|
36
36
|
|
|
37
37
|
var _stageVariables = /*#__PURE__*/_classPrivateFieldLooseKey("stageVariables");
|
|
38
38
|
|
|
39
|
+
var _additionalRequestContext = /*#__PURE__*/_classPrivateFieldLooseKey("additionalRequestContext");
|
|
40
|
+
|
|
39
41
|
class LambdaProxyIntegrationEventV2 {
|
|
40
|
-
constructor(request, stage, routeKey, stageVariables, v3Utils) {
|
|
42
|
+
constructor(request, stage, routeKey, stageVariables, additionalRequestContext, v3Utils) {
|
|
41
43
|
Object.defineProperty(this, _routeKey, {
|
|
42
44
|
writable: true,
|
|
43
45
|
value: null
|
|
@@ -54,10 +56,15 @@ class LambdaProxyIntegrationEventV2 {
|
|
|
54
56
|
writable: true,
|
|
55
57
|
value: null
|
|
56
58
|
});
|
|
59
|
+
Object.defineProperty(this, _additionalRequestContext, {
|
|
60
|
+
writable: true,
|
|
61
|
+
value: null
|
|
62
|
+
});
|
|
57
63
|
_classPrivateFieldLooseBase(this, _routeKey)[_routeKey] = routeKey;
|
|
58
64
|
_classPrivateFieldLooseBase(this, _request)[_request] = request;
|
|
59
65
|
_classPrivateFieldLooseBase(this, _stage)[_stage] = stage;
|
|
60
66
|
_classPrivateFieldLooseBase(this, _stageVariables)[_stageVariables] = stageVariables;
|
|
67
|
+
_classPrivateFieldLooseBase(this, _additionalRequestContext)[_additionalRequestContext] = additionalRequestContext || {};
|
|
61
68
|
|
|
62
69
|
if (v3Utils) {
|
|
63
70
|
this.log = v3Utils.log;
|
|
@@ -92,6 +99,18 @@ class LambdaProxyIntegrationEventV2 {
|
|
|
92
99
|
|
|
93
100
|
const headers = (0, _index.parseHeaders)(rawHeaders || []) || {};
|
|
94
101
|
|
|
102
|
+
if (headers['sls-offline-authorizer-override']) {
|
|
103
|
+
try {
|
|
104
|
+
authAuthorizer = parse(headers['sls-offline-authorizer-override']);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (this.log) {
|
|
107
|
+
this.log.error('Could not parse header sls-offline-authorizer-override, make sure it is correct JSON');
|
|
108
|
+
} else {
|
|
109
|
+
console.error('Serverless-offline: Could not parse header sls-offline-authorizer-override make sure it is correct JSON.');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
95
114
|
if (body) {
|
|
96
115
|
if (typeof body !== 'string') {
|
|
97
116
|
// this.#request.payload is NOT the same as the rawPayload
|
|
@@ -150,7 +169,13 @@ class LambdaProxyIntegrationEventV2 {
|
|
|
150
169
|
const httpMethod = method.toUpperCase();
|
|
151
170
|
const requestTime = (0, _index.formatToClfTime)(received);
|
|
152
171
|
const requestTimeEpoch = received;
|
|
153
|
-
const cookies = Object.entries(_classPrivateFieldLooseBase(this, _request)[_request].state).
|
|
172
|
+
const cookies = Object.entries(_classPrivateFieldLooseBase(this, _request)[_request].state).flatMap(([key, value]) => {
|
|
173
|
+
if (Array.isArray(value)) {
|
|
174
|
+
return value.map(v => `${key}=${v}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return `${key}=${value}`;
|
|
178
|
+
});
|
|
154
179
|
return {
|
|
155
180
|
version: '2.0',
|
|
156
181
|
routeKey: _classPrivateFieldLooseBase(this, _routeKey)[_routeKey],
|
|
@@ -177,6 +202,7 @@ class LambdaProxyIntegrationEventV2 {
|
|
|
177
202
|
sourceIp: remoteAddress,
|
|
178
203
|
userAgent: _headers['user-agent'] || ''
|
|
179
204
|
},
|
|
205
|
+
operationName: _classPrivateFieldLooseBase(this, _additionalRequestContext)[_additionalRequestContext].operationName,
|
|
180
206
|
requestId: 'offlineContext_resourceId',
|
|
181
207
|
routeKey: _classPrivateFieldLooseBase(this, _routeKey)[_routeKey],
|
|
182
208
|
stage: _classPrivateFieldLooseBase(this, _stage)[_stage],
|