@mapbox/cloudfriend 7.0.0 → 7.0.1-1

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 (21) hide show
  1. package/.nyc_output/5173def1-e652-48eb-b821-68e4c28e98bf.json +1 -0
  2. package/.nyc_output/da9b250c-7fe3-4849-a7b9-5dcb7ad608aa.json +1 -0
  3. package/.nyc_output/processinfo/{2c9b3698-f822-47f6-a941-eea13e638ffc.json → 5173def1-e652-48eb-b821-68e4c28e98bf.json} +1 -1
  4. package/.nyc_output/processinfo/{1983e39b-fcbb-4618-a9dd-36f2ec3b1532.json → da9b250c-7fe3-4849-a7b9-5dcb7ad608aa.json} +1 -1
  5. package/.nyc_output/processinfo/index.json +1 -1
  6. package/lib/shortcuts/hookshot.js +23 -12
  7. package/package.json +1 -1
  8. package/test/fixtures/shortcuts/hookshot-github-compatible-legacy-node-runtimes.json +423 -0
  9. package/test/fixtures/shortcuts/hookshot-github-secret-ref.json +3 -3
  10. package/test/fixtures/shortcuts/hookshot-github-secret-string.json +3 -3
  11. package/test/fixtures/shortcuts/hookshot-github.json +3 -3
  12. package/test/fixtures/shortcuts/hookshot-passthrough-access-log-format.json +3 -3
  13. package/test/fixtures/shortcuts/hookshot-passthrough-alarms.json +3 -3
  14. package/test/fixtures/shortcuts/hookshot-passthrough-compatible-legacy-node-runtimes.json +411 -0
  15. package/test/fixtures/shortcuts/hookshot-passthrough-enhanced-logging.json +3 -3
  16. package/test/fixtures/shortcuts/hookshot-passthrough-full-blown-logging.json +3 -3
  17. package/test/fixtures/shortcuts/hookshot-passthrough-logging.json +3 -3
  18. package/test/fixtures/shortcuts/hookshot-passthrough.json +3 -3
  19. package/test/shortcuts.test.js +46 -0
  20. package/.nyc_output/1983e39b-fcbb-4618-a9dd-36f2ec3b1532.json +0 -1
  21. package/.nyc_output/2c9b3698-f822-47f6-a941-eea13e638ffc.json +0 -1
@@ -7,6 +7,16 @@ const merge = require('../merge');
7
7
 
8
8
  const random = crypto.randomBytes(4).toString('hex');
9
9
 
10
+ function assertNodeVersion(runtime) {
11
+ if (runtime.match(/^nodejs[\d+]+.x$/)) {
12
+ const version = runtime.match(/\d+/)[0];
13
+ if (Number(version) < 18)
14
+ throw new Error(`Only nodejs runtimes >= 18 are supported for hookshot lambdas, received: '${runtime}'`);
15
+ } else {
16
+ throw new Error(`Only valid nodejs runtimes are supported for hookshot lambdas, received: '${runtime}'`);
17
+ }
18
+ }
19
+
10
20
  /**
11
21
  * The hookshot.Passthrough class defines resources that set up a single API Gateway
12
22
  * endpoint that responds to `POST` and `OPTIONS` requests. You are expected to
@@ -86,6 +96,8 @@ class Passthrough {
86
96
  WebhookSecret
87
97
  } = options;
88
98
 
99
+ if (options.Runtime) assertNodeVersion(options.Runtime);
100
+
89
101
  let {
90
102
  LoggingLevel = 'OFF'
91
103
  } = options;
@@ -260,10 +272,9 @@ class Passthrough {
260
272
  code() {
261
273
  return {
262
274
  'Fn::Sub': redent(`
263
- 'use strict';
264
275
 
265
- const AWS = require('aws-sdk');
266
- const lambda = new AWS.Lambda();
276
+ const { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');
277
+ const client = new LambdaClient();
267
278
 
268
279
  module.exports.lambda = (event, context, callback) => {
269
280
  if (event.httpMethod === 'OPTIONS') {
@@ -280,17 +291,17 @@ class Passthrough {
280
291
  return callback(null, response);
281
292
  }
282
293
 
283
- const lambdaParams = {
294
+ const command = new InvokeCommand({
284
295
  FunctionName: '\${${this.PassthroughTo}}',
285
296
  Payload: JSON.stringify(event)
286
- };
297
+ });
287
298
 
288
- lambda.invoke(lambdaParams).promise()
299
+ client.send(command)
289
300
  .then((response) => {
290
301
  if (!response || !response.Payload)
291
302
  return callback(new Error('Your Lambda function ${this.PassthroughTo} did not provide a payload'));
292
303
 
293
- var payload = JSON.parse(response.Payload);
304
+ var payload = JSON.parse(Buffer.from(response.Payload).toString());
294
305
  payload.headers = payload.headers || {};
295
306
  payload.headers['Access-Control-Allow-Origin'] = '*';
296
307
  callback(null, payload);
@@ -420,8 +431,8 @@ class Github extends Passthrough {
420
431
  'use strict';
421
432
 
422
433
  const crypto = require('crypto');
423
- const AWS = require('aws-sdk');
424
- const lambda = new AWS.Lambda();
434
+ const { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');
435
+ const client = new LambdaClient();
425
436
  const secret = '\${WebhookSecret}';
426
437
 
427
438
  module.exports.lambda = (event, context, callback) => {
@@ -436,13 +447,13 @@ class Github extends Passthrough {
436
447
 
437
448
  if (body.zen) return callback(null, 'ignored ping request');
438
449
 
439
- const lambdaParams = {
450
+ const command = new InvokeCommand({
440
451
  FunctionName: '\${${this.PassthroughTo}}',
441
452
  Payload: JSON.stringify(event.body),
442
453
  InvocationType: 'Event'
443
- };
454
+ });
444
455
 
445
- lambda.invoke(lambdaParams).promise()
456
+ client.send(command)
446
457
  .then(() => callback(null, 'success'))
447
458
  .catch((err) => callback(err));
448
459
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mapbox/cloudfriend",
3
- "version": "7.0.0",
3
+ "version": "7.0.1-1",
4
4
  "description": "Helper functions for assembling CloudFormation templates in JavaScript",
5
5
  "main": "index.js",
6
6
  "engines": {
@@ -0,0 +1,423 @@
1
+ {
2
+ "AWSTemplateFormatVersion": "2010-09-09",
3
+ "Metadata": {},
4
+ "Parameters": {},
5
+ "Rules": {},
6
+ "Mappings": {},
7
+ "Conditions": {},
8
+ "Resources": {
9
+ "PassApi": {
10
+ "Type": "AWS::ApiGateway::RestApi",
11
+ "Properties": {
12
+ "Name": {
13
+ "Fn::Sub": "${AWS::StackName}-webhook"
14
+ },
15
+ "FailOnWarnings": true,
16
+ "EndpointConfiguration": {
17
+ "Types": [
18
+ "REGIONAL"
19
+ ]
20
+ }
21
+ }
22
+ },
23
+ "PassStage": {
24
+ "Type": "AWS::ApiGateway::Stage",
25
+ "Properties": {
26
+ "DeploymentId": {
27
+ "Ref": "PassDeployment5dcf4ca7"
28
+ },
29
+ "StageName": "hookshot",
30
+ "RestApiId": {
31
+ "Ref": "PassApi"
32
+ },
33
+ "MethodSettings": [
34
+ {
35
+ "HttpMethod": "*",
36
+ "ResourcePath": "/*",
37
+ "ThrottlingBurstLimit": 20,
38
+ "ThrottlingRateLimit": 5,
39
+ "LoggingLevel": "OFF",
40
+ "DataTraceEnabled": false,
41
+ "MetricsEnabled": false
42
+ }
43
+ ]
44
+ }
45
+ },
46
+ "PassDeployment5dcf4ca7": {
47
+ "Type": "AWS::ApiGateway::Deployment",
48
+ "DependsOn": "PassMethod",
49
+ "Properties": {
50
+ "RestApiId": {
51
+ "Ref": "PassApi"
52
+ },
53
+ "StageName": "unused"
54
+ }
55
+ },
56
+ "PassResource": {
57
+ "Type": "AWS::ApiGateway::Resource",
58
+ "Properties": {
59
+ "ParentId": {
60
+ "Fn::GetAtt": [
61
+ "PassApi",
62
+ "RootResourceId"
63
+ ]
64
+ },
65
+ "RestApiId": {
66
+ "Ref": "PassApi"
67
+ },
68
+ "PathPart": "webhook"
69
+ }
70
+ },
71
+ "PassMethod": {
72
+ "Type": "AWS::ApiGateway::Method",
73
+ "Properties": {
74
+ "RestApiId": {
75
+ "Ref": "PassApi"
76
+ },
77
+ "ResourceId": {
78
+ "Ref": "PassResource"
79
+ },
80
+ "ApiKeyRequired": false,
81
+ "AuthorizationType": "NONE",
82
+ "HttpMethod": "POST",
83
+ "Integration": {
84
+ "Type": "AWS",
85
+ "IntegrationHttpMethod": "POST",
86
+ "IntegrationResponses": [
87
+ {
88
+ "StatusCode": "200"
89
+ },
90
+ {
91
+ "StatusCode": "500",
92
+ "SelectionPattern": "^error.*"
93
+ },
94
+ {
95
+ "StatusCode": "403",
96
+ "SelectionPattern": "^invalid.*"
97
+ }
98
+ ],
99
+ "Uri": {
100
+ "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${PassFunction.Arn}/invocations"
101
+ },
102
+ "RequestTemplates": {
103
+ "application/json": "{\"signature\":\"$input.params('X-Hub-Signature')\",\"body\":$input.json('$')}"
104
+ }
105
+ },
106
+ "MethodResponses": [
107
+ {
108
+ "StatusCode": "200",
109
+ "ResponseModels": {
110
+ "application/json": "Empty"
111
+ }
112
+ },
113
+ {
114
+ "StatusCode": "500",
115
+ "ResponseModels": {
116
+ "application/json": "Empty"
117
+ }
118
+ },
119
+ {
120
+ "StatusCode": "403",
121
+ "ResponseModels": {
122
+ "application/json": "Empty"
123
+ }
124
+ }
125
+ ]
126
+ }
127
+ },
128
+ "PassPermission": {
129
+ "Type": "AWS::Lambda::Permission",
130
+ "Properties": {
131
+ "FunctionName": {
132
+ "Ref": "PassFunction"
133
+ },
134
+ "Action": "lambda:InvokeFunction",
135
+ "Principal": "apigateway.amazonaws.com",
136
+ "SourceArn": {
137
+ "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${PassApi}/*"
138
+ }
139
+ }
140
+ },
141
+ "PassFunctionLogs": {
142
+ "Type": "AWS::Logs::LogGroup",
143
+ "Properties": {
144
+ "LogGroupName": {
145
+ "Fn::Sub": [
146
+ "/aws/lambda/${name}",
147
+ {
148
+ "name": {
149
+ "Fn::Sub": "${AWS::StackName}-Pass"
150
+ }
151
+ }
152
+ ]
153
+ },
154
+ "RetentionInDays": 14
155
+ }
156
+ },
157
+ "PassFunction": {
158
+ "Type": "AWS::Lambda::Function",
159
+ "Properties": {
160
+ "Code": {
161
+ "ZipFile": {
162
+ "Fn::Sub": [
163
+ "'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
164
+ {
165
+ "WebhookSecret": "abc123"
166
+ }
167
+ ]
168
+ }
169
+ },
170
+ "Description": {
171
+ "Fn::Sub": "Passthrough function for ${AWS::StackName}"
172
+ },
173
+ "FunctionName": {
174
+ "Fn::Sub": "${AWS::StackName}-Pass"
175
+ },
176
+ "Handler": "index.lambda",
177
+ "MemorySize": 128,
178
+ "Runtime": "nodejs16.x",
179
+ "Timeout": 30,
180
+ "Role": {
181
+ "Fn::GetAtt": [
182
+ "PassFunctionRole",
183
+ "Arn"
184
+ ]
185
+ }
186
+ }
187
+ },
188
+ "PassFunctionErrorAlarm": {
189
+ "Type": "AWS::CloudWatch::Alarm",
190
+ "Properties": {
191
+ "AlarmName": {
192
+ "Fn::Sub": "${AWS::StackName}-PassFunction-Errors-${AWS::Region}"
193
+ },
194
+ "AlarmDescription": {
195
+ "Fn::Sub": [
196
+ "Error alarm for ${name} lambda function in ${AWS::StackName} stack",
197
+ {
198
+ "name": {
199
+ "Fn::Sub": "${AWS::StackName}-Pass"
200
+ }
201
+ }
202
+ ]
203
+ },
204
+ "AlarmActions": [],
205
+ "Period": 60,
206
+ "EvaluationPeriods": 1,
207
+ "DatapointsToAlarm": 1,
208
+ "Statistic": "Sum",
209
+ "Threshold": 0,
210
+ "ComparisonOperator": "GreaterThanThreshold",
211
+ "TreatMissingData": "notBreaching",
212
+ "Namespace": "AWS/Lambda",
213
+ "Dimensions": [
214
+ {
215
+ "Name": "FunctionName",
216
+ "Value": {
217
+ "Ref": "PassFunction"
218
+ }
219
+ }
220
+ ],
221
+ "MetricName": "Errors"
222
+ }
223
+ },
224
+ "PassFunctionLogPolicy": {
225
+ "Type": "AWS::IAM::Policy",
226
+ "DependsOn": "PassFunctionRole",
227
+ "Properties": {
228
+ "PolicyName": "lambda-log-access",
229
+ "Roles": [
230
+ {
231
+ "Ref": "PassFunctionRole"
232
+ }
233
+ ],
234
+ "PolicyDocument": {
235
+ "Version": "2012-10-17",
236
+ "Statement": [
237
+ {
238
+ "Effect": "Allow",
239
+ "Action": "logs:*",
240
+ "Resource": {
241
+ "Fn::GetAtt": [
242
+ "PassFunctionLogs",
243
+ "Arn"
244
+ ]
245
+ }
246
+ }
247
+ ]
248
+ }
249
+ }
250
+ },
251
+ "PassFunctionRole": {
252
+ "Type": "AWS::IAM::Role",
253
+ "Properties": {
254
+ "AssumeRolePolicyDocument": {
255
+ "Statement": [
256
+ {
257
+ "Effect": "Allow",
258
+ "Action": "sts:AssumeRole",
259
+ "Principal": {
260
+ "Service": {
261
+ "Fn::Sub": "lambda.amazonaws.com"
262
+ }
263
+ }
264
+ }
265
+ ]
266
+ },
267
+ "Policies": [
268
+ {
269
+ "PolicyName": "main",
270
+ "PolicyDocument": {
271
+ "Version": "2012-10-17",
272
+ "Statement": [
273
+ {
274
+ "Effect": "Allow",
275
+ "Action": "lambda:InvokeFunction",
276
+ "Resource": {
277
+ "Fn::GetAtt": [
278
+ "Destination",
279
+ "Arn"
280
+ ]
281
+ }
282
+ }
283
+ ]
284
+ }
285
+ }
286
+ ]
287
+ }
288
+ },
289
+ "DestinationLogs": {
290
+ "Type": "AWS::Logs::LogGroup",
291
+ "Properties": {
292
+ "LogGroupName": {
293
+ "Fn::Sub": [
294
+ "/aws/lambda/${name}",
295
+ {
296
+ "name": {
297
+ "Fn::Sub": "${AWS::StackName}-Destination"
298
+ }
299
+ }
300
+ ]
301
+ },
302
+ "RetentionInDays": 14
303
+ }
304
+ },
305
+ "Destination": {
306
+ "Type": "AWS::Lambda::Function",
307
+ "Properties": {
308
+ "Code": {
309
+ "ZipFile": "module.exports.handler = (e, c, cb) => cb();"
310
+ },
311
+ "Description": {
312
+ "Fn::Sub": "Destination in the ${AWS::StackName} stack"
313
+ },
314
+ "FunctionName": {
315
+ "Fn::Sub": "${AWS::StackName}-Destination"
316
+ },
317
+ "Handler": "index.handler",
318
+ "MemorySize": 128,
319
+ "Runtime": "nodejs18.x",
320
+ "Timeout": 300,
321
+ "Role": {
322
+ "Fn::GetAtt": [
323
+ "DestinationRole",
324
+ "Arn"
325
+ ]
326
+ }
327
+ }
328
+ },
329
+ "DestinationErrorAlarm": {
330
+ "Type": "AWS::CloudWatch::Alarm",
331
+ "Properties": {
332
+ "AlarmName": {
333
+ "Fn::Sub": "${AWS::StackName}-Destination-Errors-${AWS::Region}"
334
+ },
335
+ "AlarmDescription": {
336
+ "Fn::Sub": [
337
+ "Error alarm for ${name} lambda function in ${AWS::StackName} stack",
338
+ {
339
+ "name": {
340
+ "Fn::Sub": "${AWS::StackName}-Destination"
341
+ }
342
+ }
343
+ ]
344
+ },
345
+ "AlarmActions": [],
346
+ "Period": 60,
347
+ "EvaluationPeriods": 5,
348
+ "DatapointsToAlarm": 1,
349
+ "Statistic": "Sum",
350
+ "Threshold": 0,
351
+ "ComparisonOperator": "GreaterThanThreshold",
352
+ "TreatMissingData": "notBreaching",
353
+ "Namespace": "AWS/Lambda",
354
+ "Dimensions": [
355
+ {
356
+ "Name": "FunctionName",
357
+ "Value": {
358
+ "Ref": "Destination"
359
+ }
360
+ }
361
+ ],
362
+ "MetricName": "Errors"
363
+ }
364
+ },
365
+ "DestinationLogPolicy": {
366
+ "Type": "AWS::IAM::Policy",
367
+ "DependsOn": "DestinationRole",
368
+ "Properties": {
369
+ "PolicyName": "lambda-log-access",
370
+ "Roles": [
371
+ {
372
+ "Ref": "DestinationRole"
373
+ }
374
+ ],
375
+ "PolicyDocument": {
376
+ "Version": "2012-10-17",
377
+ "Statement": [
378
+ {
379
+ "Effect": "Allow",
380
+ "Action": "logs:*",
381
+ "Resource": {
382
+ "Fn::GetAtt": [
383
+ "DestinationLogs",
384
+ "Arn"
385
+ ]
386
+ }
387
+ }
388
+ ]
389
+ }
390
+ }
391
+ },
392
+ "DestinationRole": {
393
+ "Type": "AWS::IAM::Role",
394
+ "Properties": {
395
+ "AssumeRolePolicyDocument": {
396
+ "Statement": [
397
+ {
398
+ "Effect": "Allow",
399
+ "Action": "sts:AssumeRole",
400
+ "Principal": {
401
+ "Service": {
402
+ "Fn::Sub": "lambda.amazonaws.com"
403
+ }
404
+ }
405
+ }
406
+ ]
407
+ }
408
+ }
409
+ }
410
+ },
411
+ "Outputs": {
412
+ "PassEndpointOutput": {
413
+ "Description": "The HTTPS endpoint used to send github webhooks",
414
+ "Value": {
415
+ "Fn::Sub": "https://${PassApi}.execute-api.${AWS::Region}.amazonaws.com/hookshot/webhook"
416
+ }
417
+ },
418
+ "PassSecretOutput": {
419
+ "Description": "A secret key to give Github to use when signing webhook requests",
420
+ "Value": "abc123"
421
+ }
422
+ }
423
+ }
@@ -28,7 +28,7 @@
28
28
  "Type": "AWS::ApiGateway::Stage",
29
29
  "Properties": {
30
30
  "DeploymentId": {
31
- "Ref": "PassDeployment0e352c83"
31
+ "Ref": "PassDeployment467809dc"
32
32
  },
33
33
  "StageName": "hookshot",
34
34
  "RestApiId": {
@@ -47,7 +47,7 @@
47
47
  ]
48
48
  }
49
49
  },
50
- "PassDeployment0e352c83": {
50
+ "PassDeployment467809dc": {
51
51
  "Type": "AWS::ApiGateway::Deployment",
52
52
  "DependsOn": "PassMethod",
53
53
  "Properties": {
@@ -164,7 +164,7 @@
164
164
  "Code": {
165
165
  "ZipFile": {
166
166
  "Fn::Sub": [
167
- "'use strict';\n\nconst crypto = require('crypto');\nconst AWS = require('aws-sdk');\nconst lambda = new AWS.Lambda();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const lambdaParams = {\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n };\n\n lambda.invoke(lambdaParams).promise()\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
167
+ "'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
168
168
  {
169
169
  "WebhookSecret": {
170
170
  "Ref": "SomeParameter"
@@ -24,7 +24,7 @@
24
24
  "Type": "AWS::ApiGateway::Stage",
25
25
  "Properties": {
26
26
  "DeploymentId": {
27
- "Ref": "PassDeployment0e352c83"
27
+ "Ref": "PassDeployment467809dc"
28
28
  },
29
29
  "StageName": "hookshot",
30
30
  "RestApiId": {
@@ -43,7 +43,7 @@
43
43
  ]
44
44
  }
45
45
  },
46
- "PassDeployment0e352c83": {
46
+ "PassDeployment467809dc": {
47
47
  "Type": "AWS::ApiGateway::Deployment",
48
48
  "DependsOn": "PassMethod",
49
49
  "Properties": {
@@ -160,7 +160,7 @@
160
160
  "Code": {
161
161
  "ZipFile": {
162
162
  "Fn::Sub": [
163
- "'use strict';\n\nconst crypto = require('crypto');\nconst AWS = require('aws-sdk');\nconst lambda = new AWS.Lambda();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const lambdaParams = {\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n };\n\n lambda.invoke(lambdaParams).promise()\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
163
+ "'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
164
164
  {
165
165
  "WebhookSecret": "abc123"
166
166
  }
@@ -24,7 +24,7 @@
24
24
  "Type": "AWS::ApiGateway::Stage",
25
25
  "Properties": {
26
26
  "DeploymentId": {
27
- "Ref": "PassDeployment0e352c83"
27
+ "Ref": "PassDeployment467809dc"
28
28
  },
29
29
  "StageName": "hookshot",
30
30
  "RestApiId": {
@@ -43,7 +43,7 @@
43
43
  ]
44
44
  }
45
45
  },
46
- "PassDeployment0e352c83": {
46
+ "PassDeployment467809dc": {
47
47
  "Type": "AWS::ApiGateway::Deployment",
48
48
  "DependsOn": "PassMethod",
49
49
  "Properties": {
@@ -166,7 +166,7 @@
166
166
  "Code": {
167
167
  "ZipFile": {
168
168
  "Fn::Sub": [
169
- "'use strict';\n\nconst crypto = require('crypto');\nconst AWS = require('aws-sdk');\nconst lambda = new AWS.Lambda();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const lambdaParams = {\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n };\n\n lambda.invoke(lambdaParams).promise()\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
169
+ "'use strict';\n\nconst crypto = require('crypto');\nconst { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\nconst secret = '${WebhookSecret}';\n\nmodule.exports.lambda = (event, context, callback) => {\n const body = event.body;\n const hash = 'sha1=' + crypto\n .createHmac('sha1', secret)\n .update(new Buffer(JSON.stringify(body)))\n .digest('hex');\n\n if (event.signature !== hash)\n return callback('invalid: signature does not match');\n\n if (body.zen) return callback(null, 'ignored ping request');\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event.body),\n InvocationType: 'Event'\n });\n\n client.send(command)\n .then(() => callback(null, 'success'))\n .catch((err) => callback(err));\n};",
170
170
  {
171
171
  "WebhookSecret": {
172
172
  "Ref": "PassSecret"
@@ -24,7 +24,7 @@
24
24
  "Type": "AWS::ApiGateway::Stage",
25
25
  "Properties": {
26
26
  "DeploymentId": {
27
- "Ref": "PassDeployment0e352c83"
27
+ "Ref": "PassDeployment467809dc"
28
28
  },
29
29
  "StageName": "hookshot",
30
30
  "RestApiId": {
@@ -52,7 +52,7 @@
52
52
  }
53
53
  }
54
54
  },
55
- "PassDeployment0e352c83": {
55
+ "PassDeployment467809dc": {
56
56
  "Type": "AWS::ApiGateway::Deployment",
57
57
  "DependsOn": "PassMethod",
58
58
  "Properties": {
@@ -168,7 +168,7 @@
168
168
  "Properties": {
169
169
  "Code": {
170
170
  "ZipFile": {
171
- "Fn::Sub": "'use strict';\n\nconst AWS = require('aws-sdk');\nconst lambda = new AWS.Lambda();\n\nmodule.exports.lambda = (event, context, callback) => {\n if (event.httpMethod === 'OPTIONS') {\n const requestHeaders = event.headers['Access-Control-Request-Headers'] || event.headers['access-control-request-headers'];\n const response = {\n statusCode: 200,\n body: '',\n headers: {\n 'Access-Control-Allow-Headers': requestHeaders,\n 'Access-Control-Allow-Methods': 'POST, OPTIONS',\n 'Access-Control-Allow-Origin': '*'\n }\n };\n return callback(null, response);\n }\n\n const lambdaParams = {\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event)\n };\n\n lambda.invoke(lambdaParams).promise()\n .then((response) => {\n if (!response || !response.Payload)\n return callback(new Error('Your Lambda function Destination did not provide a payload'));\n\n var payload = JSON.parse(response.Payload);\n payload.headers = payload.headers || {};\n payload.headers['Access-Control-Allow-Origin'] = '*';\n callback(null, payload);\n })\n .catch((err) => callback(err));\n};"
171
+ "Fn::Sub": "const { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\n\nmodule.exports.lambda = (event, context, callback) => {\n if (event.httpMethod === 'OPTIONS') {\n const requestHeaders = event.headers['Access-Control-Request-Headers'] || event.headers['access-control-request-headers'];\n const response = {\n statusCode: 200,\n body: '',\n headers: {\n 'Access-Control-Allow-Headers': requestHeaders,\n 'Access-Control-Allow-Methods': 'POST, OPTIONS',\n 'Access-Control-Allow-Origin': '*'\n }\n };\n return callback(null, response);\n }\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event)\n });\n\n client.send(command)\n .then((response) => {\n if (!response || !response.Payload)\n return callback(new Error('Your Lambda function Destination did not provide a payload'));\n\n var payload = JSON.parse(Buffer.from(response.Payload).toString());\n payload.headers = payload.headers || {};\n payload.headers['Access-Control-Allow-Origin'] = '*';\n callback(null, payload);\n })\n .catch((err) => callback(err));\n};"
172
172
  }
173
173
  },
174
174
  "Description": {
@@ -24,7 +24,7 @@
24
24
  "Type": "AWS::ApiGateway::Stage",
25
25
  "Properties": {
26
26
  "DeploymentId": {
27
- "Ref": "PassDeployment0e352c83"
27
+ "Ref": "PassDeployment467809dc"
28
28
  },
29
29
  "StageName": "hookshot",
30
30
  "RestApiId": {
@@ -43,7 +43,7 @@
43
43
  ]
44
44
  }
45
45
  },
46
- "PassDeployment0e352c83": {
46
+ "PassDeployment467809dc": {
47
47
  "Type": "AWS::ApiGateway::Deployment",
48
48
  "DependsOn": "PassMethod",
49
49
  "Properties": {
@@ -150,7 +150,7 @@
150
150
  "Properties": {
151
151
  "Code": {
152
152
  "ZipFile": {
153
- "Fn::Sub": "'use strict';\n\nconst AWS = require('aws-sdk');\nconst lambda = new AWS.Lambda();\n\nmodule.exports.lambda = (event, context, callback) => {\n if (event.httpMethod === 'OPTIONS') {\n const requestHeaders = event.headers['Access-Control-Request-Headers'] || event.headers['access-control-request-headers'];\n const response = {\n statusCode: 200,\n body: '',\n headers: {\n 'Access-Control-Allow-Headers': requestHeaders,\n 'Access-Control-Allow-Methods': 'POST, OPTIONS',\n 'Access-Control-Allow-Origin': '*'\n }\n };\n return callback(null, response);\n }\n\n const lambdaParams = {\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event)\n };\n\n lambda.invoke(lambdaParams).promise()\n .then((response) => {\n if (!response || !response.Payload)\n return callback(new Error('Your Lambda function Destination did not provide a payload'));\n\n var payload = JSON.parse(response.Payload);\n payload.headers = payload.headers || {};\n payload.headers['Access-Control-Allow-Origin'] = '*';\n callback(null, payload);\n })\n .catch((err) => callback(err));\n};"
153
+ "Fn::Sub": "const { InvokeCommand, LambdaClient } = require('@aws-sdk/client-lambda');\nconst client = new LambdaClient();\n\nmodule.exports.lambda = (event, context, callback) => {\n if (event.httpMethod === 'OPTIONS') {\n const requestHeaders = event.headers['Access-Control-Request-Headers'] || event.headers['access-control-request-headers'];\n const response = {\n statusCode: 200,\n body: '',\n headers: {\n 'Access-Control-Allow-Headers': requestHeaders,\n 'Access-Control-Allow-Methods': 'POST, OPTIONS',\n 'Access-Control-Allow-Origin': '*'\n }\n };\n return callback(null, response);\n }\n\n const command = new InvokeCommand({\n FunctionName: '${Destination}',\n Payload: JSON.stringify(event)\n });\n\n client.send(command)\n .then((response) => {\n if (!response || !response.Payload)\n return callback(new Error('Your Lambda function Destination did not provide a payload'));\n\n var payload = JSON.parse(Buffer.from(response.Payload).toString());\n payload.headers = payload.headers || {};\n payload.headers['Access-Control-Allow-Origin'] = '*';\n callback(null, payload);\n })\n .catch((err) => callback(err));\n};"
154
154
  }
155
155
  },
156
156
  "Description": {