serverless-offline 8.7.0 → 9.0.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.
Files changed (234) hide show
  1. package/README.md +91 -95
  2. package/package.json +41 -69
  3. package/src/ServerlessOffline.js +412 -0
  4. package/src/config/commandOptions.js +155 -0
  5. package/src/config/constants.js +22 -0
  6. package/{dist → src}/config/defaultOptions.js +8 -17
  7. package/src/config/index.js +4 -0
  8. package/src/config/supportedRuntimes.js +47 -0
  9. package/src/events/authCanExecuteResource.js +35 -0
  10. package/src/events/authFunctionNameExtractor.js +75 -0
  11. package/src/events/authMatchPolicyResource.js +71 -0
  12. package/src/events/authValidateContext.js +51 -0
  13. package/src/events/http/Endpoint.js +135 -0
  14. package/src/events/http/Http.js +50 -0
  15. package/src/events/http/HttpEventDefinition.js +20 -0
  16. package/src/events/http/HttpServer.js +1277 -0
  17. package/src/events/http/OfflineEndpoint.js +33 -0
  18. package/src/events/http/authJWTSettingsExtractor.js +70 -0
  19. package/src/events/http/createAuthScheme.js +176 -0
  20. package/src/events/http/createJWTAuthScheme.js +106 -0
  21. package/src/events/http/index.js +1 -0
  22. package/src/events/http/javaHelpers.js +102 -0
  23. package/src/events/http/lambda-events/LambdaIntegrationEvent.js +57 -0
  24. package/src/events/http/lambda-events/LambdaProxyIntegrationEvent.js +233 -0
  25. package/src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +190 -0
  26. package/src/events/http/lambda-events/VelocityContext.js +147 -0
  27. package/src/events/http/lambda-events/index.js +4 -0
  28. package/src/events/http/lambda-events/renderVelocityTemplateObject.js +93 -0
  29. package/{dist → src}/events/http/parseResources.js +73 -78
  30. package/src/events/http/payloadSchemaValidator.js +13 -0
  31. package/{dist → src}/events/http/templates/offline-default.req.vm +0 -0
  32. package/{dist → src}/events/http/templates/offline-default.res.vm +0 -0
  33. package/src/events/schedule/Schedule.js +131 -0
  34. package/src/events/schedule/ScheduleEvent.js +18 -0
  35. package/src/events/schedule/ScheduleEventDefinition.js +21 -0
  36. package/src/events/schedule/index.js +1 -0
  37. package/src/events/websocket/HttpServer.js +69 -0
  38. package/src/events/websocket/WebSocket.js +52 -0
  39. package/src/events/websocket/WebSocketClients.js +462 -0
  40. package/src/events/websocket/WebSocketEventDefinition.js +18 -0
  41. package/src/events/websocket/WebSocketServer.js +73 -0
  42. package/src/events/websocket/http-routes/_catchAll/catchAllRoute.js +16 -0
  43. package/src/events/websocket/http-routes/_catchAll/index.js +1 -0
  44. package/src/events/websocket/http-routes/connections/ConnectionsController.js +28 -0
  45. package/src/events/websocket/http-routes/connections/connectionsRoutes.js +70 -0
  46. package/src/events/websocket/http-routes/connections/index.js +1 -0
  47. package/src/events/websocket/http-routes/index.js +2 -0
  48. package/src/events/websocket/index.js +1 -0
  49. package/src/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +65 -0
  50. package/src/events/websocket/lambda-events/WebSocketConnectEvent.js +68 -0
  51. package/src/events/websocket/lambda-events/WebSocketDisconnectEvent.js +31 -0
  52. package/src/events/websocket/lambda-events/WebSocketEvent.js +29 -0
  53. package/src/events/websocket/lambda-events/WebSocketRequestContext.js +67 -0
  54. package/src/events/websocket/lambda-events/index.js +4 -0
  55. package/src/index.js +12 -0
  56. package/src/lambda/HttpServer.js +108 -0
  57. package/src/lambda/Lambda.js +68 -0
  58. package/src/lambda/LambdaContext.js +33 -0
  59. package/src/lambda/LambdaFunction.js +308 -0
  60. package/src/lambda/LambdaFunctionPool.js +109 -0
  61. package/src/lambda/__tests__/LambdaContext.test.js +30 -0
  62. package/src/lambda/__tests__/LambdaFunction.test.js +196 -0
  63. package/src/lambda/__tests__/fixtures/Lambda/LambdaFunctionThatReturnsJSONObject.fixture.js +47 -0
  64. package/src/lambda/__tests__/fixtures/Lambda/LambdaFunctionThatReturnsNativeString.fixture.js +46 -0
  65. package/src/lambda/__tests__/fixtures/Lambda/package.json +3 -0
  66. package/src/lambda/__tests__/fixtures/lambdaFunction.fixture.js +145 -0
  67. package/src/lambda/__tests__/fixtures/package.json +3 -0
  68. package/src/lambda/__tests__/routes/invocations/InvocationsController.test.js +42 -0
  69. package/src/lambda/handler-runner/HandlerRunner.js +136 -0
  70. package/src/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +72 -0
  71. package/src/lambda/handler-runner/child-process-runner/childProcessHelper.js +42 -0
  72. package/src/lambda/handler-runner/child-process-runner/index.js +1 -0
  73. package/src/lambda/handler-runner/docker-runner/DockerContainer.js +417 -0
  74. package/src/lambda/handler-runner/docker-runner/DockerImage.js +35 -0
  75. package/src/lambda/handler-runner/docker-runner/DockerRunner.js +63 -0
  76. package/src/lambda/handler-runner/docker-runner/index.js +1 -0
  77. package/src/lambda/handler-runner/go-runner/GoRunner.js +166 -0
  78. package/src/lambda/handler-runner/go-runner/index.js +1 -0
  79. package/src/lambda/handler-runner/in-process-runner/InProcessRunner.js +125 -0
  80. package/src/lambda/handler-runner/in-process-runner/index.js +1 -0
  81. package/src/lambda/handler-runner/index.js +1 -0
  82. package/src/lambda/handler-runner/java-runner/JavaRunner.js +114 -0
  83. package/src/lambda/handler-runner/java-runner/index.js +1 -0
  84. package/src/lambda/handler-runner/python-runner/PythonRunner.js +138 -0
  85. package/src/lambda/handler-runner/python-runner/index.js +1 -0
  86. package/{dist → src}/lambda/handler-runner/python-runner/invoke.py +0 -0
  87. package/src/lambda/handler-runner/ruby-runner/RubyRunner.js +107 -0
  88. package/src/lambda/handler-runner/ruby-runner/index.js +1 -0
  89. package/{dist → src}/lambda/handler-runner/ruby-runner/invoke.rb +0 -0
  90. package/src/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +70 -0
  91. package/src/lambda/handler-runner/worker-thread-runner/index.js +1 -0
  92. package/src/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +29 -0
  93. package/src/lambda/index.js +1 -0
  94. package/src/lambda/routes/index.js +2 -0
  95. package/src/lambda/routes/invocations/InvocationsController.js +102 -0
  96. package/src/lambda/routes/invocations/index.js +1 -0
  97. package/src/lambda/routes/invocations/invocationsRoute.js +77 -0
  98. package/src/lambda/routes/invoke-async/InvokeAsyncController.js +20 -0
  99. package/src/lambda/routes/invoke-async/index.js +1 -0
  100. package/src/lambda/routes/invoke-async/invokeAsyncRoute.js +33 -0
  101. package/src/utils/__tests__/createUniqueId.test.js +18 -0
  102. package/src/utils/__tests__/formatToClfTime.test.js +14 -0
  103. package/src/utils/__tests__/generateHapiPath.test.js +46 -0
  104. package/src/utils/__tests__/lowerCaseKeys.test.js +30 -0
  105. package/src/utils/__tests__/parseHeaders.test.js +13 -0
  106. package/src/utils/__tests__/parseMultiValueHeaders.test.js +24 -0
  107. package/src/utils/__tests__/parseMultiValueQueryStringParameters.test.js +159 -0
  108. package/src/utils/__tests__/parseQueryStringParameters.test.js +15 -0
  109. package/src/utils/__tests__/splitHandlerPathAndName.test.js +54 -0
  110. package/src/utils/__tests__/unflatten.test.js +32 -0
  111. package/src/utils/checkDockerDaemon.js +19 -0
  112. package/src/utils/checkGoVersion.js +16 -0
  113. package/src/utils/createApiKey.js +5 -0
  114. package/src/utils/createUniqueId.js +5 -0
  115. package/src/utils/detectExecutable.js +11 -0
  116. package/{dist → src}/utils/formatToClfTime.js +6 -14
  117. package/src/utils/generateHapiPath.js +26 -0
  118. package/src/utils/getHttpApiCorsConfig.js +28 -0
  119. package/src/utils/index.js +42 -0
  120. package/src/utils/jsonPath.js +13 -0
  121. package/src/utils/logRoutes.js +64 -0
  122. package/src/utils/lowerCaseKeys.js +6 -0
  123. package/src/utils/parseHeaders.js +14 -0
  124. package/src/utils/parseMultiValueHeaders.js +27 -0
  125. package/src/utils/parseMultiValueQueryStringParameters.js +31 -0
  126. package/src/utils/parseQueryStringParameters.js +15 -0
  127. package/src/utils/resolveJoins.js +29 -0
  128. package/src/utils/splitHandlerPathAndName.js +31 -0
  129. package/src/utils/unflatten.js +11 -0
  130. package/dist/ServerlessOffline.js +0 -507
  131. package/dist/checkEngine.js +0 -21
  132. package/dist/config/commandOptions.js +0 -149
  133. package/dist/config/constants.js +0 -30
  134. package/dist/config/index.js +0 -55
  135. package/dist/config/supportedRuntimes.js +0 -40
  136. package/dist/debugLog.js +0 -10
  137. package/dist/events/authCanExecuteResource.js +0 -35
  138. package/dist/events/authFunctionNameExtractor.js +0 -87
  139. package/dist/events/authMatchPolicyResource.js +0 -62
  140. package/dist/events/http/Endpoint.js +0 -171
  141. package/dist/events/http/Http.js +0 -77
  142. package/dist/events/http/HttpEventDefinition.js +0 -36
  143. package/dist/events/http/HttpServer.js +0 -1363
  144. package/dist/events/http/OfflineEndpoint.js +0 -40
  145. package/dist/events/http/authJWTSettingsExtractor.js +0 -76
  146. package/dist/events/http/authValidateContext.js +0 -48
  147. package/dist/events/http/createAuthScheme.js +0 -184
  148. package/dist/events/http/createJWTAuthScheme.js +0 -155
  149. package/dist/events/http/index.js +0 -15
  150. package/dist/events/http/javaHelpers.js +0 -99
  151. package/dist/events/http/lambda-events/LambdaIntegrationEvent.js +0 -85
  152. package/dist/events/http/lambda-events/LambdaProxyIntegrationEvent.js +0 -244
  153. package/dist/events/http/lambda-events/LambdaProxyIntegrationEventV2.js +0 -221
  154. package/dist/events/http/lambda-events/VelocityContext.js +0 -168
  155. package/dist/events/http/lambda-events/index.js +0 -39
  156. package/dist/events/http/lambda-events/renderVelocityTemplateObject.js +0 -108
  157. package/dist/events/http/payloadSchemaValidator.js +0 -13
  158. package/dist/events/schedule/Schedule.js +0 -182
  159. package/dist/events/schedule/ScheduleEvent.js +0 -27
  160. package/dist/events/schedule/ScheduleEventDefinition.js +0 -36
  161. package/dist/events/schedule/index.js +0 -15
  162. package/dist/events/websocket/HttpServer.js +0 -112
  163. package/dist/events/websocket/WebSocket.js +0 -78
  164. package/dist/events/websocket/WebSocketClients.js +0 -550
  165. package/dist/events/websocket/WebSocketEventDefinition.js +0 -32
  166. package/dist/events/websocket/WebSocketServer.js +0 -140
  167. package/dist/events/websocket/http-routes/_catchAll/catchAllRoute.js +0 -33
  168. package/dist/events/websocket/http-routes/_catchAll/index.js +0 -15
  169. package/dist/events/websocket/http-routes/connections/ConnectionsController.js +0 -45
  170. package/dist/events/websocket/http-routes/connections/connectionsRoutes.js +0 -95
  171. package/dist/events/websocket/http-routes/connections/index.js +0 -15
  172. package/dist/events/websocket/http-routes/index.js +0 -23
  173. package/dist/events/websocket/index.js +0 -15
  174. package/dist/events/websocket/lambda-events/WebSocketAuthorizerEvent.js +0 -99
  175. package/dist/events/websocket/lambda-events/WebSocketConnectEvent.js +0 -101
  176. package/dist/events/websocket/lambda-events/WebSocketDisconnectEvent.js +0 -47
  177. package/dist/events/websocket/lambda-events/WebSocketEvent.js +0 -54
  178. package/dist/events/websocket/lambda-events/WebSocketRequestContext.js +0 -98
  179. package/dist/events/websocket/lambda-events/index.js +0 -39
  180. package/dist/index.js +0 -19
  181. package/dist/lambda/HttpServer.js +0 -122
  182. package/dist/lambda/Lambda.js +0 -113
  183. package/dist/lambda/LambdaContext.js +0 -53
  184. package/dist/lambda/LambdaFunction.js +0 -391
  185. package/dist/lambda/LambdaFunctionPool.js +0 -127
  186. package/dist/lambda/handler-runner/HandlerRunner.js +0 -223
  187. package/dist/lambda/handler-runner/child-process-runner/ChildProcessRunner.js +0 -132
  188. package/dist/lambda/handler-runner/child-process-runner/childProcessHelper.js +0 -40
  189. package/dist/lambda/handler-runner/child-process-runner/index.js +0 -15
  190. package/dist/lambda/handler-runner/docker-runner/DockerContainer.js +0 -517
  191. package/dist/lambda/handler-runner/docker-runner/DockerImage.js +0 -67
  192. package/dist/lambda/handler-runner/docker-runner/DockerRunner.js +0 -74
  193. package/dist/lambda/handler-runner/docker-runner/index.js +0 -15
  194. package/dist/lambda/handler-runner/go-runner/GoRunner.js +0 -211
  195. package/dist/lambda/handler-runner/go-runner/index.js +0 -15
  196. package/dist/lambda/handler-runner/in-process-runner/InProcessRunner.js +0 -234
  197. package/dist/lambda/handler-runner/in-process-runner/index.js +0 -15
  198. package/dist/lambda/handler-runner/index.js +0 -15
  199. package/dist/lambda/handler-runner/java-runner/JavaRunner.js +0 -151
  200. package/dist/lambda/handler-runner/java-runner/index.js +0 -15
  201. package/dist/lambda/handler-runner/python-runner/PythonRunner.js +0 -180
  202. package/dist/lambda/handler-runner/python-runner/index.js +0 -15
  203. package/dist/lambda/handler-runner/ruby-runner/RubyRunner.js +0 -148
  204. package/dist/lambda/handler-runner/ruby-runner/index.js +0 -15
  205. package/dist/lambda/handler-runner/worker-thread-runner/WorkerThreadRunner.js +0 -94
  206. package/dist/lambda/handler-runner/worker-thread-runner/index.js +0 -15
  207. package/dist/lambda/handler-runner/worker-thread-runner/workerThreadHelper.js +0 -30
  208. package/dist/lambda/index.js +0 -15
  209. package/dist/lambda/routes/index.js +0 -23
  210. package/dist/lambda/routes/invocations/InvocationsController.js +0 -142
  211. package/dist/lambda/routes/invocations/index.js +0 -15
  212. package/dist/lambda/routes/invocations/invocationsRoute.js +0 -90
  213. package/dist/lambda/routes/invoke-async/InvokeAsyncController.js +0 -38
  214. package/dist/lambda/routes/invoke-async/index.js +0 -15
  215. package/dist/lambda/routes/invoke-async/invokeAsyncRoute.js +0 -43
  216. package/dist/main.js +0 -11
  217. package/dist/serverlessLog.js +0 -91
  218. package/dist/utils/checkDockerDaemon.js +0 -27
  219. package/dist/utils/checkGoVersion.js +0 -27
  220. package/dist/utils/createApiKey.js +0 -12
  221. package/dist/utils/createUniqueId.js +0 -14
  222. package/dist/utils/detectExecutable.js +0 -21
  223. package/dist/utils/generateHapiPath.js +0 -28
  224. package/dist/utils/getHttpApiCorsConfig.js +0 -44
  225. package/dist/utils/index.js +0 -158
  226. package/dist/utils/jsonPath.js +0 -21
  227. package/dist/utils/parseHeaders.js +0 -23
  228. package/dist/utils/parseMultiValueHeaders.js +0 -36
  229. package/dist/utils/parseMultiValueQueryStringParameters.js +0 -40
  230. package/dist/utils/parseQueryStringParameters.js +0 -26
  231. package/dist/utils/resolveJoins.js +0 -34
  232. package/dist/utils/satisfiesVersionRange.js +0 -20
  233. package/dist/utils/splitHandlerPathAndName.js +0 -41
  234. package/dist/utils/unflatten.js +0 -18
@@ -0,0 +1,33 @@
1
+ export default class OfflineEndpoint {
2
+ apiKeyRequired = false
3
+
4
+ authorizationType = 'none'
5
+
6
+ authorizerFunction = false
7
+
8
+ path = ''
9
+
10
+ requestParameters = {}
11
+
12
+ requestTemplates = {
13
+ 'application/json': '',
14
+ }
15
+
16
+ responses = {
17
+ default: {
18
+ 400: {
19
+ statusCode: '400',
20
+ },
21
+ responseModels: {
22
+ 'application/json;charset=UTF-8': 'Empty',
23
+ },
24
+ responseParameters: {},
25
+ responseTemplates: {
26
+ 'application/json;charset=UTF-8': '',
27
+ },
28
+ statusCode: 200,
29
+ },
30
+ }
31
+
32
+ type = 'AWS'
33
+ }
@@ -0,0 +1,70 @@
1
+ import { log } from '@serverless/utils/log.js'
2
+
3
+ export default function authJWTSettingsExtractor(
4
+ endpoint,
5
+ provider,
6
+ ignoreJWTSignature,
7
+ ) {
8
+ const buildFailureResult = (warningMessage) => {
9
+ log.warning(warningMessage)
10
+
11
+ return {
12
+ unsupportedAuth: true,
13
+ }
14
+ }
15
+
16
+ const buildSuccessResult = (authorizerName) => ({ authorizerName })
17
+
18
+ const { authorizer } = endpoint
19
+
20
+ if (!authorizer) {
21
+ return buildSuccessResult(null)
22
+ }
23
+
24
+ if (!provider.httpApi || !provider.httpApi.authorizers) {
25
+ return buildSuccessResult(null)
26
+ }
27
+
28
+ // TODO: add code that will actually validate a JWT.
29
+ if (!ignoreJWTSignature) {
30
+ return buildSuccessResult(null)
31
+ }
32
+
33
+ if (!authorizer.name) {
34
+ return buildFailureResult(
35
+ 'Serverless Offline supports only JWT authorizers referenced by name',
36
+ )
37
+ }
38
+
39
+ const httpApiAuthorizer = provider.httpApi.authorizers[authorizer.name]
40
+
41
+ if (!httpApiAuthorizer) {
42
+ return buildFailureResult(`JWT authorizer ${authorizer.name} not found`)
43
+ }
44
+
45
+ if (!httpApiAuthorizer.identitySource) {
46
+ return buildFailureResult(
47
+ `JWT authorizer ${authorizer.name} missing identity source`,
48
+ )
49
+ }
50
+
51
+ if (!httpApiAuthorizer.issuerUrl) {
52
+ return buildFailureResult(
53
+ `JWT authorizer ${authorizer.name} missing issuer url`,
54
+ )
55
+ }
56
+
57
+ if (!httpApiAuthorizer.audience || httpApiAuthorizer.audience.length === 0) {
58
+ return buildFailureResult(
59
+ `JWT authorizer ${authorizer.name} missing audience`,
60
+ )
61
+ }
62
+
63
+ const result = {
64
+ authorizerName: authorizer.name,
65
+ ...authorizer,
66
+ ...httpApiAuthorizer,
67
+ }
68
+
69
+ return result
70
+ }
@@ -0,0 +1,176 @@
1
+ import Boom from '@hapi/boom'
2
+ import { log } from '@serverless/utils/log.js'
3
+ import authCanExecuteResource from '../authCanExecuteResource.js'
4
+ import authValidateContext from '../authValidateContext.js'
5
+ import {
6
+ nullIfEmpty,
7
+ parseHeaders,
8
+ parseMultiValueHeaders,
9
+ parseMultiValueQueryStringParameters,
10
+ parseQueryStringParameters,
11
+ } from '../../utils/index.js'
12
+
13
+ export default function createAuthScheme(authorizerOptions, provider, lambda) {
14
+ const authFunName = authorizerOptions.name
15
+ let identityHeader = 'authorization'
16
+
17
+ if (authorizerOptions.type !== 'request') {
18
+ const identitySourceMatch = /^method.request.header.((?:\w+-?)+\w+)$/.exec(
19
+ authorizerOptions.identitySource,
20
+ )
21
+
22
+ if (!identitySourceMatch || identitySourceMatch.length !== 2) {
23
+ throw new Error(
24
+ `Serverless Offline only supports retrieving tokens from the headers (λ: ${authFunName})`,
25
+ )
26
+ }
27
+
28
+ identityHeader = identitySourceMatch[1].toLowerCase()
29
+ }
30
+
31
+ // Create Auth Scheme
32
+ return () => ({
33
+ async authenticate(request, h) {
34
+ log.notice()
35
+ log.notice(
36
+ `Running Authorization function for ${request.method} ${request.path} (λ: ${authFunName})`,
37
+ )
38
+
39
+ // Get Authorization header
40
+ const { req } = request.raw
41
+
42
+ // Get path params
43
+ // aws doesn't auto decode path params - hapi does
44
+ const pathParams = { ...request.params }
45
+
46
+ const accountId = 'random-account-id'
47
+ const apiId = 'random-api-id'
48
+ const httpMethod = request.method.toUpperCase()
49
+ const resourcePath = request.route.path.replace(
50
+ new RegExp(`^/${provider.stage}`),
51
+ '',
52
+ )
53
+
54
+ let event = {
55
+ enhancedAuthContext: {},
56
+ methodArn: `arn:aws:execute-api:${provider.region}:${accountId}:${apiId}/${provider.stage}/${httpMethod}${resourcePath}`,
57
+ requestContext: {
58
+ accountId,
59
+ apiId,
60
+ httpMethod,
61
+ path: request.path,
62
+ requestId: 'random-request-id',
63
+ resourceId: 'random-resource-id',
64
+ resourcePath,
65
+ stage: provider.stage,
66
+ },
67
+ resource: resourcePath,
68
+ }
69
+
70
+ // Create event Object for authFunction
71
+ // methodArn is the ARN of the function we are running we are authorizing access to (or not)
72
+ // Account ID and API ID are not simulated
73
+ if (authorizerOptions.type === 'request') {
74
+ const { rawHeaders, url } = req
75
+
76
+ event = {
77
+ ...event,
78
+ headers: parseHeaders(rawHeaders),
79
+ httpMethod: request.method.toUpperCase(),
80
+ multiValueHeaders: parseMultiValueHeaders(rawHeaders),
81
+ multiValueQueryStringParameters:
82
+ parseMultiValueQueryStringParameters(url),
83
+ path: request.path,
84
+ pathParameters: nullIfEmpty(pathParams),
85
+ queryStringParameters: parseQueryStringParameters(url),
86
+ type: 'REQUEST',
87
+ }
88
+ } else {
89
+ const authorization = req.headers[identityHeader]
90
+
91
+ const identityValidationExpression = new RegExp(
92
+ authorizerOptions.identityValidationExpression,
93
+ )
94
+ const matchedAuthorization =
95
+ identityValidationExpression.test(authorization)
96
+ const finalAuthorization = matchedAuthorization ? authorization : ''
97
+
98
+ log.debug(`Retrieved ${identityHeader} header "${finalAuthorization}"`)
99
+
100
+ event = {
101
+ ...event,
102
+ authorizationToken: finalAuthorization,
103
+ type: 'TOKEN',
104
+ }
105
+ }
106
+
107
+ const lambdaFunction = lambda.get(authFunName)
108
+ lambdaFunction.setEvent(event)
109
+
110
+ try {
111
+ const result = await lambdaFunction.runHandler()
112
+ if (result === 'Unauthorized') return Boom.unauthorized('Unauthorized')
113
+
114
+ // Validate that the policy document has the principalId set
115
+ if (!result.principalId) {
116
+ log.notice(
117
+ `Authorization response did not include a principalId: (λ: ${authFunName})`,
118
+ )
119
+
120
+ return Boom.forbidden('No principalId set on the Response')
121
+ }
122
+
123
+ if (!authCanExecuteResource(result.policyDocument, event.methodArn)) {
124
+ log.notice(
125
+ `Authorization response didn't authorize user to access resource: (λ: ${authFunName})`,
126
+ )
127
+
128
+ return Boom.forbidden(
129
+ 'User is not authorized to access this resource',
130
+ )
131
+ }
132
+
133
+ // validate the resulting context, ensuring that all
134
+ // values are either string, number, or boolean types
135
+ if (result.context) {
136
+ const validationResult = authValidateContext(
137
+ result.context,
138
+ authFunName,
139
+ )
140
+
141
+ if (validationResult instanceof Error) {
142
+ return validationResult
143
+ }
144
+
145
+ result.context = validationResult
146
+ }
147
+
148
+ log.notice(
149
+ `Authorization function returned a successful response: (λ: ${authFunName})`,
150
+ )
151
+
152
+ const authorizer = {
153
+ integrationLatency: '42',
154
+ principalId: result.principalId,
155
+ ...result.context,
156
+ }
157
+
158
+ // Set the credentials for the rest of the pipeline
159
+ return h.authenticated({
160
+ credentials: {
161
+ authorizer,
162
+ context: result.context,
163
+ principalId: result.principalId,
164
+ usageIdentifierKey: result.usageIdentifierKey,
165
+ },
166
+ })
167
+ } catch {
168
+ log.notice(
169
+ `Authorization function returned an error response: (λ: ${authFunName})`,
170
+ )
171
+
172
+ return Boom.unauthorized('Unauthorized')
173
+ }
174
+ },
175
+ })
176
+ }
@@ -0,0 +1,106 @@
1
+ import Boom from '@hapi/boom'
2
+ import { log } from '@serverless/utils/log.js'
3
+ import { decode } from 'jsonwebtoken'
4
+
5
+ const { isArray } = Array
6
+
7
+ export default function createAuthScheme(jwtOptions) {
8
+ const authorizerName = jwtOptions.name
9
+
10
+ const identitySourceMatch = /^\$request.header.((?:\w+-?)+\w+)$/.exec(
11
+ jwtOptions.identitySource,
12
+ )
13
+
14
+ if (!identitySourceMatch || identitySourceMatch.length !== 2) {
15
+ throw new Error(
16
+ `Serverless Offline only supports retrieving JWT from the headers (${authorizerName})`,
17
+ )
18
+ }
19
+
20
+ const identityHeader = identitySourceMatch[1].toLowerCase()
21
+
22
+ // Create Auth Scheme
23
+ return () => ({
24
+ async authenticate(request, h) {
25
+ log.notice()
26
+ log.notice(
27
+ `Running JWT Authorization function for ${request.method} ${request.path} (${authorizerName})`,
28
+ )
29
+
30
+ // Get Authorization header
31
+ const { req } = request.raw
32
+ let jwtToken = req.headers[identityHeader]
33
+ if (jwtToken && jwtToken.split(' ')[0] === 'Bearer') {
34
+ ;[, jwtToken] = jwtToken.split(' ')
35
+ }
36
+
37
+ try {
38
+ const decoded = decode(jwtToken, { complete: true })
39
+ if (!decoded) {
40
+ return Boom.unauthorized('JWT not decoded')
41
+ }
42
+
43
+ const expirationDate = new Date(decoded.payload.exp * 1000)
44
+ if (expirationDate.valueOf() < Date.now()) {
45
+ return Boom.unauthorized('JWT Token expired')
46
+ }
47
+
48
+ const { aud, iss, scope } = decoded.payload
49
+ const clientId = decoded.payload.client_id
50
+ if (iss !== jwtOptions.issuerUrl) {
51
+ log.notice(`JWT Token not from correct issuer url`)
52
+
53
+ return Boom.unauthorized('JWT Token not from correct issuer url')
54
+ }
55
+
56
+ const validAudiences = isArray(jwtOptions.audience)
57
+ ? jwtOptions.audience
58
+ : [jwtOptions.audience]
59
+ const providedAudiences = isArray(aud) ? aud : [aud]
60
+ const validAudienceProvided = providedAudiences.some((a) =>
61
+ validAudiences.includes(a),
62
+ )
63
+
64
+ if (!validAudienceProvided && !validAudiences.includes(clientId)) {
65
+ log.notice(`JWT Token does not contain correct audience`)
66
+
67
+ return Boom.unauthorized(
68
+ 'JWT Token does not contain correct audience',
69
+ )
70
+ }
71
+
72
+ let scopes = null
73
+ if (jwtOptions.scopes && jwtOptions.scopes.length) {
74
+ if (!scope) {
75
+ log.notice(`JWT Token missing valid scope`)
76
+
77
+ return Boom.forbidden('JWT Token missing valid scope')
78
+ }
79
+
80
+ scopes = scope.split(' ')
81
+ if (scopes.every((s) => !jwtOptions.scopes.includes(s))) {
82
+ log.notice(`JWT Token missing valid scope`)
83
+
84
+ return Boom.forbidden('JWT Token missing valid scope')
85
+ }
86
+ }
87
+
88
+ log.notice(`JWT Token validated`)
89
+
90
+ // Set the credentials for the rest of the pipeline
91
+ // return resolve(
92
+ return h.authenticated({
93
+ credentials: {
94
+ claims: decoded.payload,
95
+ scopes,
96
+ },
97
+ })
98
+ } catch (err) {
99
+ log.notice(`JWT could not be decoded`)
100
+ log.error(err)
101
+
102
+ return Boom.unauthorized('Unauthorized')
103
+ }
104
+ },
105
+ })
106
+ }
@@ -0,0 +1 @@
1
+ export { default } from './Http.js'
@@ -0,0 +1,102 @@
1
+ // String functions
2
+ // For velocity templates to access java functions, to mimick AWS
3
+
4
+ function javaContains(value) {
5
+ return this.includes(value)
6
+ }
7
+
8
+ function javaEquals(anObject) {
9
+ return this.toString() === anObject.toString()
10
+ }
11
+
12
+ function javaEqualsIgnoreCase(anotherString) {
13
+ return anotherString === null
14
+ ? false
15
+ : this === anotherString ||
16
+ this.toLowerCase() === anotherString.toLowerCase()
17
+ }
18
+
19
+ function javaMatches(value) {
20
+ return this.match(new RegExp(value, 'm'))
21
+ }
22
+
23
+ function javaReplaceAll(oldValue, newValue) {
24
+ return this.replace(new RegExp(oldValue, 'gm'), newValue)
25
+ }
26
+
27
+ function javaReplaceFirst(oldValue, newValue) {
28
+ return this.replace(new RegExp(oldValue, 'm'), newValue)
29
+ }
30
+
31
+ // method has 2 function signatures:
32
+ // regionMatches(toffset: number, other: string, ooffset: number, len: number): boolean
33
+ // regionMatches(ignoreCase: boolean, toffset: number, other: string, ooffset: number, len: number): boolean
34
+ function javaRegionMatches(...args) {
35
+ let ignoreCase
36
+ let toffset
37
+ let other
38
+ let ooffset
39
+ let len
40
+
41
+ if (args.length === 4) {
42
+ ;[toffset, other, ooffset, len] = args
43
+ ignoreCase = false
44
+ } else {
45
+ ;[ignoreCase, toffset, other, ooffset, len] = args
46
+ }
47
+
48
+ // Note: toffset, ooffset, or len might be near -1>>>1.
49
+ if (
50
+ ooffset < 0 ||
51
+ toffset < 0 ||
52
+ toffset > this.length - len ||
53
+ ooffset > other.length - len
54
+ ) {
55
+ return false
56
+ }
57
+
58
+ let s1 = this.substring(toffset, toffset + len)
59
+ let s2 = other.substring(ooffset, ooffset + len)
60
+
61
+ if (ignoreCase) {
62
+ s1 = s1.toLowerCase()
63
+ s2 = s2.toLowerCase()
64
+ }
65
+
66
+ return s1 === s2
67
+ }
68
+
69
+ const {
70
+ prototype,
71
+ prototype: {
72
+ contains,
73
+ equals,
74
+ equalsIgnoreCase,
75
+ matches,
76
+ regionMatches,
77
+ replaceAll,
78
+ replaceFirst,
79
+ },
80
+ } = String
81
+
82
+ export default function runInPollutedScope(runScope) {
83
+ prototype.contains = javaContains
84
+ prototype.equals = javaEquals
85
+ prototype.equalsIgnoreCase = javaEqualsIgnoreCase
86
+ prototype.matches = javaMatches
87
+ prototype.regionMatches = javaRegionMatches
88
+ prototype.replaceAll = javaReplaceAll
89
+ prototype.replaceFirst = javaReplaceFirst
90
+
91
+ const result = runScope()
92
+
93
+ prototype.contains = contains
94
+ prototype.equals = equals
95
+ prototype.equalsIgnoreCase = equalsIgnoreCase
96
+ prototype.matches = matches
97
+ prototype.regionMatches = regionMatches
98
+ prototype.replaceAll = replaceAll
99
+ prototype.replaceFirst = replaceFirst
100
+
101
+ return result
102
+ }
@@ -0,0 +1,57 @@
1
+ import { env } from 'node:process'
2
+ import { log } from '@serverless/utils/log.js'
3
+ import renderVelocityTemplateObject from './renderVelocityTemplateObject.js'
4
+ import VelocityContext from './VelocityContext.js'
5
+
6
+ const { parse } = JSON
7
+
8
+ export default class LambdaIntegrationEvent {
9
+ #path = null
10
+
11
+ #request = null
12
+
13
+ #requestTemplate = null
14
+
15
+ #stage = null
16
+
17
+ constructor(request, stage, requestTemplate, path) {
18
+ this.#path = path
19
+ this.#request = request
20
+ this.#requestTemplate = requestTemplate
21
+ this.#stage = stage
22
+ }
23
+
24
+ create() {
25
+ if (env.AUTHORIZER) {
26
+ try {
27
+ const authorizerContext = parse(env.AUTHORIZER)
28
+ if (authorizerContext) {
29
+ this.#request.auth = {
30
+ ...this.#request.auth,
31
+ credentials: {
32
+ authorizer: authorizerContext,
33
+ },
34
+ }
35
+ }
36
+ } catch {
37
+ log.error(
38
+ 'Could not parse process.env.AUTHORIZER, make sure it is correct JSON',
39
+ )
40
+ }
41
+ }
42
+
43
+ const velocityContext = new VelocityContext(
44
+ this.#request,
45
+ this.#stage,
46
+ this.#request.payload || {},
47
+ this.#path,
48
+ ).getContext()
49
+
50
+ const event = renderVelocityTemplateObject(
51
+ this.#requestTemplate,
52
+ velocityContext,
53
+ )
54
+
55
+ return event
56
+ }
57
+ }