@kumologica/sdk 3.2.0-beta13 → 3.2.0-beta15

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.
@@ -329,6 +329,7 @@ RED.sidebar.awsDeploy = (function () {
329
329
  <!--option value="lex">Amazon Lex</option-->
330
330
  <!--option value="alexa">Amazon Alexa</option-->
331
331
  <option selected value="api">Amazon API Gateway</option>
332
+ <option selected value="websocket">Amazon WebSocket API</option>
332
333
  <!--option value="cf">Amazon CloudFront (Lambda@Edge)</option-->
333
334
  <!--option value="firehose">Amazon Kinesis Data Firehose</option-->
334
335
  <option disabled>────────────────────</option>
@@ -1385,6 +1386,16 @@ RED.sidebar.awsDeploy = (function () {
1385
1386
  { label: 'Resource', key: 'resource', value: '', required: false },
1386
1387
  { label: 'Authorizer Id', key: 'authorizerId', value: '', required: false }
1387
1388
  ];
1389
+ parameterSets['websocket'] = [
1390
+ {
1391
+ label: 'ApiId',
1392
+ key: 'apiId',
1393
+ value: '',
1394
+ required: true,
1395
+ function: 'attachDataList',
1396
+ },
1397
+ { label: 'Deployment Stage', key: 'stage', value: '', required: true }
1398
+ ];
1388
1399
  parameterSets['alb'] = [
1389
1400
  {
1390
1401
  label: 'App Load Balancer',
@@ -1434,7 +1445,15 @@ RED.sidebar.awsDeploy = (function () {
1434
1445
  parameterSets['cwevents'] = [
1435
1446
  { label: 'Expression', key: 'expression', value: 'cron()', required: true },
1436
1447
  { label: 'Reference', key: 'reference', value: '' },
1437
- { label: 'Name', key: 'name', value: ''}
1448
+ { label: 'Name', key: 'name', value: ''},
1449
+ { label: 'State',
1450
+ key: 'state',
1451
+ value: '',
1452
+ list: [
1453
+ { k: 'ENABLED', v: 'ENABLED' },
1454
+ { k: 'DISABLED', v: 'DISABLED' }
1455
+ ],
1456
+ },
1438
1457
  ];
1439
1458
  //parameterSets['cwlogs'] = [
1440
1459
  // {
@@ -1,29 +0,0 @@
1
- const AWS = require('aws-sdk');
2
-
3
- /*
4
- * AWS JS API:
5
- * https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html
6
- */
7
- class CAAlexa {
8
-
9
- constructor(log) {
10
- this.log = log;
11
- this.alexa = new AWS.AlexaForBusiness({region: 'us-east-1'});
12
- }
13
-
14
- /**
15
- * https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/AlexaForBusiness.html#listSkills-property
16
- */
17
- async listSkills() {
18
-
19
- const response = await this.alexa.listSkills({}).promise();
20
-
21
- // {"SkillSummaries":[{"SkillId":"amzn1.ask.skill.8ac93c7f-22ec-48c7-a19d-de22baffc503","SkillName":"Writing Tips","SupportsLinking":false,"EnablementType":"ENABLED","SkillType":"PUBLIC"}]}
22
-
23
- return response.SkillSummaries.map(function(v) {
24
- return {id: v.SkillId, name: v.SkillName, arn: v.SkillName};
25
- });
26
- }
27
- }
28
-
29
- module.exports = CAAlexa;
@@ -1,449 +0,0 @@
1
- const AWS = require('aws-sdk');
2
- const jp = require('jsonpath');
3
- const KLRekognition = require('./kl-rekognition-api');
4
-
5
- class AWSCFTemplate {
6
- constructor() {
7
- this.rekognition = new KLRekognition();
8
- }
9
-
10
- /*
11
- * Creates cloud formation template file for current lambda:
12
- * It is composed of:
13
- * - lambda definition
14
- * - lambda's role
15
- * - lambda's policy
16
- * - if event subriptions confirmed then event source mappings for:
17
- * - dynamodb stream
18
- * - sns
19
- * - kinesis
20
- * - if flow nodes are provided then
21
- * - role added for each downstream aws node
22
- */
23
- createCfTemplate(params, settings, nodes, region) {
24
- let ts = new Date();
25
-
26
- let template = {
27
- AWSTemplateFormatVersion: '2010-09-09',
28
- Resources: {},
29
- Outputs: {
30
- LambdaArn: {
31
- Description: 'The Arn of the cloud action flow lambda.',
32
- Value: { 'Fn::GetAtt': ['Lambda', 'Arn'] }
33
- }
34
- }
35
- };
36
-
37
- let lambda = {
38
- Type: "AWS::Lambda::Function",
39
- Properties: {
40
- FunctionName: settings.functionName,
41
- Handler: "lambda.handler",
42
- Role: { "Fn::GetAtt": [ "LambdaRole", "Arn" ] },
43
- Code: {
44
- S3Bucket: settings.deploymentBucketName,
45
- S3Key: settings.zipFileName
46
- },
47
- Runtime: "nodejs12.x",
48
- Timeout: 300,
49
- Environment: {
50
- Variables: {}
51
- },
52
- Tags: [
53
- {
54
- Key : "Kumologica-ts",
55
- Value : `${ts.toISOString()}`
56
- }
57
- ]
58
- }
59
- };
60
- template.Resources['Lambda'] = lambda;
61
-
62
- let lambdaRole = {
63
- Type: 'AWS::IAM::Role',
64
- Properties: {
65
- RoleName: settings.roleName,
66
- AssumeRolePolicyDocument: {
67
- Version: '2012-10-17',
68
- Statement: [
69
- {
70
- Effect: 'Allow',
71
- Principal: {
72
- Service: ['lambda.amazonaws.com']
73
- },
74
- Action: ['sts:AssumeRole']
75
- }
76
- ]
77
- },
78
- Path: '/',
79
- Policies: [
80
- {
81
- PolicyName: 'AWSLambdaBasicExecutionPolicy',
82
- PolicyDocument: {
83
- Version: '2012-10-17',
84
- Statement: [
85
- {
86
- Effect: 'Allow',
87
- Action: [
88
- 'logs:CreateLogGroup',
89
- 'logs:CreateLogStream',
90
- 'logs:PutLogEvents'
91
- ],
92
- Resource: '*'
93
- }
94
- ]
95
- }
96
- }
97
- ]
98
- }
99
- };
100
-
101
- const xRayPolicy = {
102
- PolicyName: 'AWSLambdaXRayPolicy',
103
- PolicyDocument: {
104
- Version: '2012-10-17',
105
- Statement: [
106
- {
107
- Effect: 'Allow',
108
- Action: [
109
- 'xray:PutTraceSegments',
110
- 'xray:PutTelemetryRecords'
111
- ],
112
- Resource: '*'
113
- }
114
- ]
115
- }
116
- };
117
-
118
- if (params.description) {
119
- lambda.Properties.Description = params.description;
120
- }
121
- if (params.memory) {
122
- lambda.Properties.MemorySize = params.memory;
123
- }
124
- if (params.timeout) {
125
- lambda.Properties.Timeout = params.timeout;
126
- }
127
-
128
- if (params.reservedConcurrency) {
129
- lambda.Properties.ReservedConcurrentExecutions = params.reservedConcurrency;
130
- }
131
-
132
- if (params.xRay) {
133
- lambdaRole.Properties.Policies.push(xRayPolicy);
134
- lambda.Properties.TracingConfig = {'Mode': 'Active'};
135
- }
136
-
137
- if (params.role) {
138
- lambda.Properties.Role = params.role;
139
- }
140
- if (params.environment) {
141
- params.environment.forEach(function(env, index) {
142
- lambda.Properties.Environment.Variables[env.key] = env.value;
143
- });
144
- }
145
-
146
- if (params.tags) {
147
- params.tags.forEach(function(tag, index) {
148
- lambda.Properties.Tags.push({'Key': tag.key, 'Value': tag.value});
149
- });
150
- }
151
-
152
- // adding inbound services permissions, only for dynamodb stream, sqs and kinesis
153
- if (params.events) {
154
- for (var i = 0; i < params.events.length; i++) {
155
- if (['dynamodb', 'sqs', 'kinesis'].includes(params.events[i].source)) {
156
- var mappingName = `${params.events[i].source}Mapping${i}`;
157
-
158
- template.Resources[mappingName] = this.eventSourceMapping(params.events[i], settings);
159
-
160
- if (params.events[i].source === 'dynamodb') {
161
- lambdaRole.Properties.Policies.push(
162
- this.dynamoDbStreamPolicy(params.events[i])
163
- );
164
- }
165
- if (params.events[i].source === 'sqs') {
166
- lambdaRole.Properties.Policies.push(
167
- this.sqsPolicy(params.events[i])
168
- );
169
- }
170
- if (params.events[i].source === 'kinesis') {
171
- lambdaRole.Properties.Policies.push(
172
- this.kinesisPolicy(params.events[i])
173
- );
174
- }
175
- }
176
- }
177
- }
178
-
179
- // adding all outbound services operations to iam role
180
- if (nodes) {
181
- for (var i=0; i<nodes.length; i++) {
182
- // exluding lambda for time being
183
- if (this.validNodeType(nodes[i])) {
184
- // if (nodes[i] && nodes[i].type && ['Rekognition', 'S3', 'SQS', 'Cloudwatch', 'Dynamo DB', 'SNS', 'SES', 'SSM'].includes(nodes[i].type)) {
185
-
186
- if (nodes[i].type === 'Dynamo DB') {
187
- //arn:aws:dynamodb:ap-southeast-2:174842903734:table/contact_us
188
- let tableArn = this.handleValue(lambda, nodes[i].tableArn);
189
- let tableParts = tableArn.split(":");
190
- let tableName = '*';
191
- if (tableParts && tableParts[5]) {
192
- tableName = tableParts[5].replace('table/', '');
193
- }
194
-
195
- this.handlePolicy(lambdaRole, `KLDDB${tableName}`, `dynamodb:${nodes[i].operation}`, tableArn);
196
-
197
- } else if (nodes[i].type === 'Lambda') {
198
- //arn:aws:lambda:ap-southeast-2:174450237637:function:kumologica-deployments-flow-lambda
199
- let lambdaArn = this.handleValue(lambda, nodes[i].LambdaArn);
200
- let lambdaParts = lambdaArn.split(":");
201
- let lambdaName = '*';
202
-
203
- if (lambdaParts && lambdaParts[6]) {
204
- lambdaName = lambdaParts[6];
205
- }
206
-
207
- this.handlePolicy(lambdaRole, `KLLBD${lambdaName}`, `lambda:InvokeFunction`, lambdaArn);
208
-
209
- } else if (nodes[i].type === 'SQS') {
210
- let queueArn = this.handleValue(lambda, nodes[i].QueueArn);
211
- let queueName = queueArn.split(":")[5];
212
- this.handlePolicy(lambdaRole, `KLSQS${queueName}`, `sqs:${nodes[i].operation}`, queueArn);
213
-
214
- } else if (nodes[i].type === 'SNS') {
215
- const topic = this.handleValue(lambda, nodes[i].publishTopic);
216
- this.handlePolicy(lambdaRole, `KLSNS${topic}`, `sns:${nodes[i].operation}`, topic);
217
-
218
- } else if (nodes[i].type === 'SES') {
219
- this.handlePolicy(lambdaRole, `KLSES`, `ses:${nodes[i].operation}`, '*');
220
-
221
- } else if (nodes[i].type === 'SSM') {
222
- let key;
223
- if (nodes[i].operation === "GetParametersByPath") {
224
- key = this.handleValue(lambda, nodes[i].Path);
225
- } else {
226
- key = this.handleValue(lambda, nodes[i].Key);
227
- }
228
-
229
- if (key.startsWith('/')) {
230
- key = key.substring(1);
231
- }
232
- const ssmArn = {'Fn::Sub': 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/' + key};
233
- this.handlePolicy(lambdaRole, `KLSSM${new Date().valueOf()}`, `ssm:${nodes[i].operation}`, ssmArn);
234
-
235
- if (nodes[i].operation === "GetParameter" && nodes[i].Key.startsWith("/aws/reference/secretsmanager/")) {
236
- const smArn = {'Fn::Sub': 'arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:*'};
237
- this.handlePolicy(lambdaRole, `KLSM${new Date().valueOf()}`, "secretsmanager:GetSecretValue", smArn);
238
- }
239
- } else if (nodes[i].type === 'S3') {
240
- let bucketName = this.handleValue(lambda, nodes[i].Bucket);
241
- const bucketArn = `arn:aws:s3:::${bucketName}/*`;
242
- this.handlePolicy(lambdaRole, `KLS3${bucketName}`, `s3:${nodes[i].operation}`, bucketArn);
243
-
244
- } else if (nodes[i].type === 'Cloudwatch') {
245
- let source = this.handleValue(lambda, nodes[i].Source);
246
- this.handlePolicy(lambdaRole, `KLCWE${source}`, `event:${nodes[i].operation}`, source);
247
-
248
- } else if (nodes[i].type === 'Rekognition') {
249
- const resource = this.rekognition.mapResource(nodes[i].operation, region, '*', nodes[i]);
250
- this.handlePolicy(lambdaRole, `KLR${nodes[i].operation}`, `rekognition:${nodes[i].operation}`, resource);
251
-
252
- if (['DetectModerationLabels',
253
- 'DetectText',
254
- 'DetectLabels',
255
- 'DetectFaces',
256
- 'IndexFaces',
257
- 'RecognizeCelebrities',
258
- 'SearchFacesByImage',
259
- 'StartStreamProcessor',
260
- 'StopStreamProcessor'].includes(nodes[i].operation)) {
261
-
262
- const bucketName = nodes[i].Image;
263
- const bucketArn = `arn:aws:s3:::${bucketName}/*`;
264
- this.handlePolicy(lambdaRole, `KLS3${bucketName}`, `s3:Get*`, bucketArn);
265
- this.handlePolicy(lambdaRole, `KLS3${bucketName}`, `s3:List*`, bucketArn);
266
- }
267
- }
268
- }
269
- }
270
- }
271
-
272
- if (!params.role) {
273
- template.Resources['LambdaRole'] = lambdaRole;
274
- }
275
-
276
- return template;
277
- }
278
-
279
- validNodeType(node) {
280
- return node
281
- && node.type
282
- && ['Rekognition', 'S3', 'SQS', 'Cloudwatch', 'Dynamo DB', 'SNS', 'SES', 'SSM', 'Lambda'].includes(node.type);
283
- }
284
-
285
- //
286
- // Function allows the storage of aws resource identifier (arn or other)
287
- // in either:
288
- // - string property - value returned as is (key input)
289
- // - env property - key input is a key to reference environment variable.
290
- // if env variables got key missing then error is returned
291
- // if var or msg used then error is returned, in these cases its impossible
292
- // to determine the value
293
- handleValue(lambda, key) {
294
- let value;
295
-
296
- if (!key) {
297
- return key;
298
- }
299
- let keyValue = key.replace(/\s+/g, '');
300
-
301
- if (keyValue.startsWith("env.")) {
302
- keyValue = keyValue.replace("env.", "");
303
- value = lambda.Properties.Environment.Variables[keyValue];
304
- if (!value) {
305
- throw new Error(`Missing Environment variable: ${keyValue}`);
306
- }
307
- } else if (key.startsWith("msg.") || key.startsWith("vars.")) {
308
- throw new Error('Only literal string and Environment variable references env. are supported sources of values. To use other types you must specify explicit role arn in function properties.');
309
- } else {
310
- value = key;
311
- }
312
- return this.sanitizeValue(value);
313
- }
314
-
315
- // Removes strings in quotes, they will cause cloudformation script to be invalid
316
- sanitizeValue(value) {
317
- let v = value.trim();
318
- if (v.charAt(0) === '"' && v.charAt(v.length -1) === '"') {
319
- return v.substr(1,v.length -2);
320
- }
321
- return value;
322
- }
323
-
324
- //
325
- // Function handles policy changes for specific resource:
326
- // - creates new policy for resource if not found
327
- // - updates existing resource policy (if found) with new permissions
328
- //
329
- handlePolicy(lambdaRole, policyName, operation, id) {
330
- policyName = policyName.replace('/', '-').replace('*', 'all');
331
- let policy = jp.query(lambdaRole.Properties, `Policies[?(@.PolicyName=='${policyName}')]`);
332
-
333
- if (policy.length == 1) {
334
- policy[0].PolicyDocument.Statement[0].Action.push(operation);
335
- } else {
336
- lambdaRole.Properties.Policies.push(
337
- this.outputPolicy(policyName, operation, id));
338
- }
339
- }
340
-
341
- dynamoDbStreamPolicy(event) {
342
- if (!event.stream) {
343
- throw new Error(`Missing Trigger Parameter: DynamoDB Stream's ARN`);
344
- }
345
-
346
- return {
347
- PolicyName: 'KumologicaLambdaDynamoDbStreamPolicy',
348
- PolicyDocument: {
349
- Version: '2012-10-17',
350
- Statement: [
351
- {
352
- Action: [
353
- 'dynamodb:DescribeStream',
354
- 'dynamodb:GetRecords',
355
- 'dynamodb:GetShardIterator'
356
- ],
357
- Resource: event.stream,
358
- Effect: 'Allow'
359
- }
360
- ]
361
- }
362
- };
363
- }
364
-
365
- outputPolicy(name, action, resource) {
366
- return {
367
- PolicyName: name,
368
- PolicyDocument: {
369
- Version: '2012-10-17',
370
- Statement: [
371
- {
372
- Action: [action],
373
- Resource: resource,
374
- Effect: 'Allow'
375
- }
376
- ]
377
- }
378
- };
379
- }
380
-
381
- sqsPolicy(event) {
382
- if (!event.stream) {
383
- throw new Error(`Missing Trigger Parameter: SQS url`);
384
- }
385
- return {
386
- PolicyName: 'KLSQSPolicy'+process.hrtime(),
387
- PolicyDocument: {
388
- Version: '2012-10-17',
389
- Statement: [
390
- {
391
- Action: [
392
- 'sqs:ReceiveMessage',
393
- 'sqs:DeleteMessage',
394
- 'sqs:GetQueueAttributes'
395
- ],
396
- Resource: event.stream,
397
- Effect: 'Allow'
398
- }
399
- ]
400
- }
401
- };
402
- }
403
-
404
- kinesisPolicy(event) {
405
- return {
406
- PolicyName: 'KumologicaLambdaKinesisPolicy',
407
- PolicyDocument: {
408
- Version: '2012-10-17',
409
- Statement: [
410
- {
411
- Action: [
412
- 'kinesis:DescribeStream',
413
- 'kinesis:DescribeStreamSummary',
414
- 'kinesis:GetRecords',
415
- 'kinesis:GetShardIterator',
416
- 'kinesis:ListShards',
417
- 'kinesis:ListStreams',
418
- 'kinesis:SubscribeToShard'
419
- ],
420
- Resource: event.stream,
421
- Effect: 'Allow'
422
- }
423
- ]
424
- }
425
- };
426
- }
427
-
428
- eventSourceMapping(event, settings) {
429
-
430
- let mapping = {
431
- Type: 'AWS::Lambda::EventSourceMapping',
432
- DependsOn: 'Lambda',
433
- Properties: {
434
- EventSourceArn: event.stream,
435
- FunctionName: { 'Fn::GetAtt': ['Lambda', 'Arn'] },
436
- BatchSize: event.batchSize,
437
- MaximumBatchingWindowInSeconds: event.batchWindow,
438
- Enabled: true
439
- }
440
- };
441
-
442
- if (event.startingPosition) {
443
- mapping.Properties.StartingPosition = event.startingPosition;
444
- }
445
- return mapping;
446
- }
447
- }
448
-
449
- module.exports = AWSCFTemplate;