serverless-spy 0.0.33 → 0.0.35
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/.jsii +9 -9
- package/common/publishSpyEvent.ts +269 -0
- package/dist/releasetag.txt +1 -1
- package/extension/interceptor.ts +27 -13
- package/functions/onConnect.ts +2 -1
- package/functions/onDisconnect.ts +2 -1
- package/functions/sendMessage.ts +3 -268
- package/lib/common/publishSpyEvent.d.ts +4 -0
- package/lib/common/publishSpyEvent.js +211 -0
- package/lib/common/publishSpyEvent.mjs +205 -0
- package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js +13888 -13
- package/lib/extension/dist/layer/nodejs/node_modules/interceptor.js.map +4 -4
- package/lib/listener/{SpyListener.d.ts → ServerlessSpyListener.d.ts} +12 -12
- package/lib/listener/ServerlessSpyListener.js +3 -0
- package/lib/listener/ServerlessSpyListener.mjs +2 -0
- package/lib/listener/ServerlessSpyListenerParams.d.ts +5 -0
- package/lib/listener/ServerlessSpyListenerParams.js +3 -0
- package/lib/listener/ServerlessSpyListenerParams.mjs +2 -0
- package/lib/listener/SpyHandlers.ts.d.ts +1 -1
- package/lib/listener/SpyHandlers.ts.js +1 -1
- package/lib/listener/SpyHandlers.ts.mjs +1 -1
- package/lib/listener/WaitForParams.d.ts +5 -0
- package/lib/listener/WaitForParams.js +3 -0
- package/lib/listener/WaitForParams.mjs +2 -0
- package/lib/listener/WsListener.d.ts +38 -0
- package/lib/listener/WsListener.js +185 -0
- package/lib/listener/WsListener.mjs +181 -0
- package/lib/listener/createServerlessSpyListener.d.ts +2 -13
- package/lib/listener/createServerlessSpyListener.js +5 -163
- package/lib/listener/createServerlessSpyListener.mjs +5 -163
- package/lib/listener/index.d.ts +1 -1
- package/lib/listener/index.js +2 -2
- package/lib/listener/index.mjs +2 -2
- package/lib/src/ServerlessSpy.d.ts +17 -8
- package/lib/src/ServerlessSpy.js +108 -67
- package/lib/src/ServerlessSpy.mjs +105 -64
- package/lib/src/common/envVariableNames.d.ts +19 -0
- package/lib/src/common/envVariableNames.js +26 -0
- package/lib/src/common/envVariableNames.mjs +23 -0
- package/listener/{SpyListener.ts → ServerlessSpyListener.ts} +12 -13
- package/listener/ServerlessSpyListenerParams.ts +6 -0
- package/listener/SpyHandlers.ts.ts +1 -1
- package/listener/WaitForParams.ts +6 -0
- package/listener/WsListener.ts +273 -0
- package/listener/createServerlessSpyListener.ts +5 -265
- package/listener/index.ts +1 -1
- package/package.json +1 -1
- package/lib/listener/SpyListener.js +0 -3
- package/lib/listener/SpyListener.mjs +0 -2
package/functions/sendMessage.ts
CHANGED
|
@@ -1,277 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ApiGatewayManagementApi,
|
|
3
|
-
PostToConnectionCommand,
|
|
4
|
-
} from '@aws-sdk/client-apigatewaymanagementapi';
|
|
5
|
-
import {
|
|
6
|
-
AttributeValue,
|
|
7
|
-
DeleteItemCommand,
|
|
8
|
-
DynamoDBClient,
|
|
9
|
-
ScanCommand,
|
|
10
|
-
} from '@aws-sdk/client-dynamodb';
|
|
11
|
-
import { unmarshall } from '@aws-sdk/util-dynamodb';
|
|
12
|
-
|
|
13
|
-
import {
|
|
14
|
-
DynamoDBStreamEvent,
|
|
15
|
-
S3Event,
|
|
16
|
-
SNSEvent,
|
|
17
|
-
EventBridgeEvent,
|
|
18
|
-
SQSEvent,
|
|
19
|
-
} from 'aws-lambda';
|
|
20
|
-
import { DynamoDBSpyEvent } from '../common/spyEvents/DynamoDBSpyEvent';
|
|
21
|
-
import { EventBridgeRuleSpyEvent } from '../common/spyEvents/EventBridgeRuleSpyEvent';
|
|
22
|
-
import { EventBridgeSpyEvent } from '../common/spyEvents/EventBridgeSpyEvent';
|
|
23
|
-
import { S3SpyEvent } from '../common/spyEvents/S3SpyEvent';
|
|
24
|
-
import { SnsSubscriptionSpyEvent } from '../common/spyEvents/SnsSubscriptionSpyEvent';
|
|
25
|
-
import { SnsTopicSpyEvent } from '../common/spyEvents/SnsTopicSpyEvent';
|
|
26
|
-
import { SpyMessage } from '../common/spyEvents/SpyMessage';
|
|
27
|
-
import { SqsSpyEvent } from '../common/spyEvents/SqsSpyEvent';
|
|
28
|
-
|
|
29
|
-
const ddb = new DynamoDBClient({
|
|
30
|
-
region: process.env.AWS_REGION,
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
const { TABLE_NAME } = process.env;
|
|
34
|
-
const endpoint = process.env.WS_ENDPOINT!;
|
|
35
|
-
|
|
36
|
-
const apigwManagementApi = new ApiGatewayManagementApi({
|
|
37
|
-
apiVersion: '2018-11-29',
|
|
38
|
-
endpoint,
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
let connections: Record<string, AttributeValue>[] | undefined;
|
|
42
|
-
|
|
43
|
-
export const handler = async (event: any, context: any) => {
|
|
44
|
-
console.log('EVENT', JSON.stringify(event));
|
|
45
|
-
// console.log("CONTEXT", JSON.stringify(context));
|
|
46
|
-
|
|
47
|
-
const mapping = JSON.parse(process.env.INFRA_MAPPING!);
|
|
48
|
-
console.log('mapping', JSON.stringify(mapping));
|
|
49
|
-
|
|
50
|
-
let connectionData;
|
|
51
|
-
|
|
52
|
-
const scanParams = new ScanCommand({
|
|
53
|
-
TableName: process.env.TABLE_NAME as string,
|
|
54
|
-
ProjectionExpression: 'connectionId',
|
|
55
|
-
});
|
|
1
|
+
import { publishSpyEvent } from '../common/publishSpyEvent';
|
|
56
2
|
|
|
3
|
+
export const handler = async (event: any) => {
|
|
57
4
|
try {
|
|
58
|
-
|
|
5
|
+
await publishSpyEvent(event);
|
|
59
6
|
} catch (e) {
|
|
60
7
|
console.error(e);
|
|
61
8
|
return { statusCode: 500, body: (e as Error)?.stack };
|
|
62
9
|
}
|
|
63
|
-
connections = connectionData.Items;
|
|
64
|
-
|
|
65
|
-
const postDataPromises: Promise<any>[] = [];
|
|
66
|
-
|
|
67
|
-
if (event?.Records && event.Records[0]?.Sns) {
|
|
68
|
-
console.log('*** SNS ***');
|
|
69
|
-
const eventSns = event as SNSEvent;
|
|
70
|
-
for (const record of eventSns.Records) {
|
|
71
|
-
const subscriptionArn = record.EventSubscriptionArn;
|
|
72
|
-
|
|
73
|
-
let serviceKey: string;
|
|
74
|
-
if (mapping[subscriptionArn]) {
|
|
75
|
-
// subscription event that could contain filter based on existing subscription
|
|
76
|
-
serviceKey = mapping[subscriptionArn];
|
|
77
|
-
} else {
|
|
78
|
-
// catch all subscription
|
|
79
|
-
const topicArn = record.Sns.TopicArn;
|
|
80
|
-
serviceKey = mapping[topicArn];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
let message: string;
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
message = JSON.parse(record.Sns.Message);
|
|
87
|
-
} catch {
|
|
88
|
-
message = record.Sns.Message;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const spyEventType = getSpyEventType(serviceKey) as
|
|
92
|
-
| 'FunctionSnsTopic'
|
|
93
|
-
| 'FunctionSnsSubscription';
|
|
94
|
-
|
|
95
|
-
const data: SnsTopicSpyEvent | SnsSubscriptionSpyEvent = {
|
|
96
|
-
spyEventType,
|
|
97
|
-
message,
|
|
98
|
-
subject: record.Sns.Subject,
|
|
99
|
-
timestamp: record.Sns.Timestamp,
|
|
100
|
-
topicArn: record.Sns.TopicArn,
|
|
101
|
-
messageId: record.Sns.MessageId,
|
|
102
|
-
messageAttributes: record.Sns.MessageAttributes,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
106
|
-
data,
|
|
107
|
-
serviceKey,
|
|
108
|
-
};
|
|
109
|
-
postDataPromises.push(postData(fluentEvent));
|
|
110
|
-
}
|
|
111
|
-
} else if (event?.Records && event.Records[0]?.eventSource === 'aws:sqs') {
|
|
112
|
-
console.log('*** SQS ***');
|
|
113
|
-
const eventSqs = event as SQSEvent;
|
|
114
|
-
for (const record of eventSqs.Records) {
|
|
115
|
-
const subscriptionArn = record.eventSourceARN;
|
|
116
|
-
|
|
117
|
-
const serviceKey = mapping[subscriptionArn];
|
|
118
|
-
let body: string;
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
body = JSON.parse(record.body);
|
|
122
|
-
} catch {
|
|
123
|
-
body = record.body;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
const data: SqsSpyEvent = {
|
|
127
|
-
spyEventType: 'Sqs',
|
|
128
|
-
body,
|
|
129
|
-
messageAttributes: record.messageAttributes,
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
133
|
-
data,
|
|
134
|
-
serviceKey,
|
|
135
|
-
};
|
|
136
|
-
postDataPromises.push(postData(fluentEvent));
|
|
137
|
-
}
|
|
138
|
-
} else if (event?.Records && event.Records[0]?.s3) {
|
|
139
|
-
console.log('*** S3 ***');
|
|
140
|
-
const eventS3 = event as S3Event;
|
|
141
|
-
for (const record of eventS3.Records) {
|
|
142
|
-
const bucketArn = record.s3.bucket.arn;
|
|
143
|
-
|
|
144
|
-
const data: S3SpyEvent = {
|
|
145
|
-
spyEventType: 'S3',
|
|
146
|
-
eventName: record.eventName,
|
|
147
|
-
eventTime: record.eventTime,
|
|
148
|
-
bucket: record.s3.bucket.name,
|
|
149
|
-
key: record.s3.object.key,
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
153
|
-
data,
|
|
154
|
-
serviceKey: mapping[bucketArn],
|
|
155
|
-
};
|
|
156
|
-
postDataPromises.push(postData(fluentEvent));
|
|
157
|
-
}
|
|
158
|
-
} else if (event.Records && event.Records[0]?.dynamodb) {
|
|
159
|
-
console.log('*** DYNAMODB ***');
|
|
160
|
-
const eventDynamoDB = event as DynamoDBStreamEvent;
|
|
161
|
-
for (const record of eventDynamoDB.Records) {
|
|
162
|
-
let arn = record.eventSourceARN!;
|
|
163
|
-
arn = arn.substring(0, arn.indexOf('/stream/'));
|
|
164
|
-
|
|
165
|
-
const data: DynamoDBSpyEvent = {
|
|
166
|
-
spyEventType: 'DynamoDB',
|
|
167
|
-
eventName: record.eventName,
|
|
168
|
-
newImage: unmarshall(record.dynamodb?.NewImage as any),
|
|
169
|
-
keys: unmarshall(record.dynamodb?.Keys as any),
|
|
170
|
-
oldImage: record.dynamodb?.OldImage
|
|
171
|
-
? unmarshall(record.dynamodb?.OldImage as any)
|
|
172
|
-
: undefined,
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
176
|
-
data,
|
|
177
|
-
serviceKey: mapping[arn],
|
|
178
|
-
};
|
|
179
|
-
postDataPromises.push(postData(fluentEvent));
|
|
180
|
-
}
|
|
181
|
-
} else if (
|
|
182
|
-
event.detail &&
|
|
183
|
-
event['detail-type'] &&
|
|
184
|
-
event.version &&
|
|
185
|
-
event.source
|
|
186
|
-
) {
|
|
187
|
-
console.log('*** EventBridge ***');
|
|
188
|
-
const eventEb = event as EventBridgeEvent<any, any>;
|
|
189
|
-
|
|
190
|
-
const serviceKey = mapping.eventBridge; // the is new lambda for each subscription
|
|
191
|
-
|
|
192
|
-
const spyEventType = getSpyEventType(serviceKey) as
|
|
193
|
-
| 'EventBridge'
|
|
194
|
-
| 'EventBridgeRule';
|
|
195
|
-
|
|
196
|
-
const message = eventEb.detail;
|
|
197
|
-
|
|
198
|
-
const data: EventBridgeSpyEvent | EventBridgeRuleSpyEvent = {
|
|
199
|
-
spyEventType,
|
|
200
|
-
detail: message,
|
|
201
|
-
detailType: eventEb['detail-type'],
|
|
202
|
-
source: eventEb.source,
|
|
203
|
-
time: eventEb.time,
|
|
204
|
-
account: eventEb.account,
|
|
205
|
-
};
|
|
206
|
-
|
|
207
|
-
const fluentEvent: Omit<SpyMessage, 'timestamp'> = {
|
|
208
|
-
data,
|
|
209
|
-
serviceKey,
|
|
210
|
-
};
|
|
211
|
-
postDataPromises.push(postData(fluentEvent));
|
|
212
|
-
} else {
|
|
213
|
-
console.log('*** OTHER ***');
|
|
214
|
-
const fluentEvent: Omit<SpyMessage, 'timestamp'> = event;
|
|
215
|
-
postDataPromises.push(postData(fluentEvent));
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
await Promise.all(postDataPromises);
|
|
219
10
|
|
|
220
11
|
return { statusCode: 200, body: 'Data sent.' };
|
|
221
12
|
};
|
|
222
|
-
|
|
223
|
-
async function postData(spyMessage: Omit<SpyMessage, 'timestamp'>) {
|
|
224
|
-
// const postData = JSON.parse(event.body!).data;
|
|
225
|
-
console.log('postData', JSON.stringify(spyMessage));
|
|
226
|
-
|
|
227
|
-
if (!connections) {
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const postCalls = connections.map(async ({ connectionId }) => {
|
|
232
|
-
console.log(`Sending message to: ${connectionId.S}`);
|
|
233
|
-
|
|
234
|
-
try {
|
|
235
|
-
const postToConnectionCommand = new PostToConnectionCommand({
|
|
236
|
-
ConnectionId: connectionId.S,
|
|
237
|
-
Data: JSON.stringify({
|
|
238
|
-
timestamp: new Date().toISOString(),
|
|
239
|
-
serviceKey: spyMessage.serviceKey,
|
|
240
|
-
data: spyMessage.data,
|
|
241
|
-
}) as any,
|
|
242
|
-
});
|
|
243
|
-
|
|
244
|
-
await apigwManagementApi.send(postToConnectionCommand);
|
|
245
|
-
} catch (e) {
|
|
246
|
-
console.error(`Fails sending message to: ${connectionId.S}`, e);
|
|
247
|
-
console.error(`Status code: ${(e as any).statusCode}`);
|
|
248
|
-
if ((e as any).$metadata.httpStatusCode === 410) {
|
|
249
|
-
console.log(`Found stale connection, deleting ${connectionId}`);
|
|
250
|
-
|
|
251
|
-
const deleteParams = new DeleteItemCommand({
|
|
252
|
-
TableName: TABLE_NAME,
|
|
253
|
-
Key: { connectionId },
|
|
254
|
-
});
|
|
255
|
-
|
|
256
|
-
await ddb.send(deleteParams);
|
|
257
|
-
} else {
|
|
258
|
-
throw e;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
try {
|
|
264
|
-
await Promise.all(postCalls);
|
|
265
|
-
console.log('Send message finish');
|
|
266
|
-
} catch (e) {
|
|
267
|
-
return { statusCode: 500, body: (e as Error)?.stack };
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function getSpyEventType(serviceKey: string) {
|
|
272
|
-
if (!serviceKey) {
|
|
273
|
-
throw new Error('Missing serviceKey');
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return serviceKey.substring(0, serviceKey.indexOf('#'));
|
|
277
|
-
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { SpyMessage } from './spyEvents/SpyMessage';
|
|
2
|
+
export declare function publishSpyEvent(event: any): Promise<void>;
|
|
3
|
+
export declare function postData(spyMessage: Omit<SpyMessage, 'timestamp'>): Promise<void>;
|
|
4
|
+
export declare function getSpyEventType(serviceKey: string): string;
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getSpyEventType = exports.postData = exports.publishSpyEvent = void 0;
|
|
4
|
+
const client_apigatewaymanagementapi_1 = require("@aws-sdk/client-apigatewaymanagementapi");
|
|
5
|
+
const client_dynamodb_1 = require("@aws-sdk/client-dynamodb");
|
|
6
|
+
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
|
|
7
|
+
const envVariableNames_1 = require("../src/common/envVariableNames");
|
|
8
|
+
const ddb = new client_dynamodb_1.DynamoDBClient({
|
|
9
|
+
region: process.env.AWS_REGION,
|
|
10
|
+
});
|
|
11
|
+
const apigwManagementApi = new client_apigatewaymanagementapi_1.ApiGatewayManagementApi({
|
|
12
|
+
apiVersion: '2018-11-29',
|
|
13
|
+
endpoint: process.env[envVariableNames_1.envVariableNames.SSPY_WS_ENDPOINT],
|
|
14
|
+
});
|
|
15
|
+
let connections;
|
|
16
|
+
async function publishSpyEvent(event) {
|
|
17
|
+
console.log('EVENT', JSON.stringify(event));
|
|
18
|
+
const mapping = JSON.parse(process.env[envVariableNames_1.envVariableNames.SSPY_INFRA_MAPPING]);
|
|
19
|
+
console.log('mapping', JSON.stringify(mapping));
|
|
20
|
+
let connectionData;
|
|
21
|
+
const scanParams = new client_dynamodb_1.ScanCommand({
|
|
22
|
+
TableName: process.env[envVariableNames_1.envVariableNames.SSPY_WS_TABLE_NAME],
|
|
23
|
+
ProjectionExpression: 'connectionId',
|
|
24
|
+
});
|
|
25
|
+
connectionData = await ddb.send(scanParams);
|
|
26
|
+
connections = connectionData.Items;
|
|
27
|
+
console.log(`connections at ${new Date().toISOString()}`, JSON.stringify(connections));
|
|
28
|
+
const postDataPromises = [];
|
|
29
|
+
if (event?.Records && event.Records[0]?.Sns) {
|
|
30
|
+
console.log('*** SNS ***');
|
|
31
|
+
const eventSns = event;
|
|
32
|
+
for (const record of eventSns.Records) {
|
|
33
|
+
const subscriptionArn = record.EventSubscriptionArn;
|
|
34
|
+
let serviceKey;
|
|
35
|
+
if (mapping[subscriptionArn]) {
|
|
36
|
+
// subscription event that could contain filter based on existing subscription
|
|
37
|
+
serviceKey = mapping[subscriptionArn];
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// catch all subscription
|
|
41
|
+
const topicArn = record.Sns.TopicArn;
|
|
42
|
+
serviceKey = mapping[topicArn];
|
|
43
|
+
}
|
|
44
|
+
let message;
|
|
45
|
+
try {
|
|
46
|
+
message = JSON.parse(record.Sns.Message);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
message = record.Sns.Message;
|
|
50
|
+
}
|
|
51
|
+
const spyEventType = getSpyEventType(serviceKey);
|
|
52
|
+
const data = {
|
|
53
|
+
spyEventType,
|
|
54
|
+
message,
|
|
55
|
+
subject: record.Sns.Subject,
|
|
56
|
+
timestamp: record.Sns.Timestamp,
|
|
57
|
+
topicArn: record.Sns.TopicArn,
|
|
58
|
+
messageId: record.Sns.MessageId,
|
|
59
|
+
messageAttributes: record.Sns.MessageAttributes,
|
|
60
|
+
};
|
|
61
|
+
const fluentEvent = {
|
|
62
|
+
data,
|
|
63
|
+
serviceKey,
|
|
64
|
+
};
|
|
65
|
+
postDataPromises.push(postData(fluentEvent));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (event?.Records && event.Records[0]?.eventSource === 'aws:sqs') {
|
|
69
|
+
console.log('*** SQS ***');
|
|
70
|
+
const eventSqs = event;
|
|
71
|
+
for (const record of eventSqs.Records) {
|
|
72
|
+
const subscriptionArn = record.eventSourceARN;
|
|
73
|
+
const serviceKey = mapping[subscriptionArn];
|
|
74
|
+
let body;
|
|
75
|
+
try {
|
|
76
|
+
body = JSON.parse(record.body);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
body = record.body;
|
|
80
|
+
}
|
|
81
|
+
const data = {
|
|
82
|
+
spyEventType: 'Sqs',
|
|
83
|
+
body,
|
|
84
|
+
messageAttributes: record.messageAttributes,
|
|
85
|
+
};
|
|
86
|
+
const fluentEvent = {
|
|
87
|
+
data,
|
|
88
|
+
serviceKey,
|
|
89
|
+
};
|
|
90
|
+
postDataPromises.push(postData(fluentEvent));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (event?.Records && event.Records[0]?.s3) {
|
|
94
|
+
console.log('*** S3 ***');
|
|
95
|
+
const eventS3 = event;
|
|
96
|
+
for (const record of eventS3.Records) {
|
|
97
|
+
const bucketArn = record.s3.bucket.arn;
|
|
98
|
+
const data = {
|
|
99
|
+
spyEventType: 'S3',
|
|
100
|
+
eventName: record.eventName,
|
|
101
|
+
eventTime: record.eventTime,
|
|
102
|
+
bucket: record.s3.bucket.name,
|
|
103
|
+
key: record.s3.object.key,
|
|
104
|
+
};
|
|
105
|
+
const fluentEvent = {
|
|
106
|
+
data,
|
|
107
|
+
serviceKey: mapping[bucketArn],
|
|
108
|
+
};
|
|
109
|
+
postDataPromises.push(postData(fluentEvent));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (event.Records && event.Records[0]?.dynamodb) {
|
|
113
|
+
console.log('*** DYNAMODB ***');
|
|
114
|
+
const eventDynamoDB = event;
|
|
115
|
+
for (const record of eventDynamoDB.Records) {
|
|
116
|
+
let arn = record.eventSourceARN;
|
|
117
|
+
arn = arn.substring(0, arn.indexOf('/stream/'));
|
|
118
|
+
const data = {
|
|
119
|
+
spyEventType: 'DynamoDB',
|
|
120
|
+
eventName: record.eventName,
|
|
121
|
+
newImage: (0, util_dynamodb_1.unmarshall)(record.dynamodb?.NewImage),
|
|
122
|
+
keys: (0, util_dynamodb_1.unmarshall)(record.dynamodb?.Keys),
|
|
123
|
+
oldImage: record.dynamodb?.OldImage
|
|
124
|
+
? (0, util_dynamodb_1.unmarshall)(record.dynamodb?.OldImage)
|
|
125
|
+
: undefined,
|
|
126
|
+
};
|
|
127
|
+
const fluentEvent = {
|
|
128
|
+
data,
|
|
129
|
+
serviceKey: mapping[arn],
|
|
130
|
+
};
|
|
131
|
+
postDataPromises.push(postData(fluentEvent));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else if (event.detail &&
|
|
135
|
+
event['detail-type'] &&
|
|
136
|
+
event.version &&
|
|
137
|
+
event.source) {
|
|
138
|
+
console.log('*** EventBridge ***');
|
|
139
|
+
const eventEb = event;
|
|
140
|
+
const serviceKey = mapping.eventBridge; // the is new lambda for each subscription
|
|
141
|
+
const spyEventType = getSpyEventType(serviceKey);
|
|
142
|
+
const message = eventEb.detail;
|
|
143
|
+
const data = {
|
|
144
|
+
spyEventType,
|
|
145
|
+
detail: message,
|
|
146
|
+
detailType: eventEb['detail-type'],
|
|
147
|
+
source: eventEb.source,
|
|
148
|
+
time: eventEb.time,
|
|
149
|
+
account: eventEb.account,
|
|
150
|
+
};
|
|
151
|
+
const fluentEvent = {
|
|
152
|
+
data,
|
|
153
|
+
serviceKey,
|
|
154
|
+
};
|
|
155
|
+
postDataPromises.push(postData(fluentEvent));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
console.log('*** OTHER ***');
|
|
159
|
+
const fluentEvent = event;
|
|
160
|
+
postDataPromises.push(postData(fluentEvent));
|
|
161
|
+
}
|
|
162
|
+
await Promise.all(postDataPromises);
|
|
163
|
+
}
|
|
164
|
+
exports.publishSpyEvent = publishSpyEvent;
|
|
165
|
+
async function postData(spyMessage) {
|
|
166
|
+
// const postData = JSON.parse(event.body!).data;
|
|
167
|
+
console.log('postData', JSON.stringify(spyMessage));
|
|
168
|
+
if (!connections) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const postCalls = connections.map(async ({ connectionId }) => {
|
|
172
|
+
console.log(`Sending message to: ${connectionId.S}`);
|
|
173
|
+
try {
|
|
174
|
+
const postToConnectionCommand = new client_apigatewaymanagementapi_1.PostToConnectionCommand({
|
|
175
|
+
ConnectionId: connectionId.S,
|
|
176
|
+
Data: JSON.stringify({
|
|
177
|
+
timestamp: new Date().toISOString(),
|
|
178
|
+
serviceKey: spyMessage.serviceKey,
|
|
179
|
+
data: spyMessage.data,
|
|
180
|
+
}),
|
|
181
|
+
});
|
|
182
|
+
await apigwManagementApi.send(postToConnectionCommand);
|
|
183
|
+
}
|
|
184
|
+
catch (e) {
|
|
185
|
+
console.error(`Fails sending message to: ${connectionId.S}`, e);
|
|
186
|
+
console.error(`Status code: ${e.statusCode}`);
|
|
187
|
+
if (e.$metadata.httpStatusCode === 410) {
|
|
188
|
+
console.log(`Found stale connection, deleting ${connectionId}`);
|
|
189
|
+
const deleteParams = new client_dynamodb_1.DeleteItemCommand({
|
|
190
|
+
TableName: process.env[envVariableNames_1.envVariableNames.SSPY_WS_TABLE_NAME],
|
|
191
|
+
Key: { connectionId },
|
|
192
|
+
});
|
|
193
|
+
await ddb.send(deleteParams);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
throw e;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
await Promise.all(postCalls);
|
|
201
|
+
console.log('Send message finish');
|
|
202
|
+
}
|
|
203
|
+
exports.postData = postData;
|
|
204
|
+
function getSpyEventType(serviceKey) {
|
|
205
|
+
if (!serviceKey) {
|
|
206
|
+
throw new Error('Missing serviceKey');
|
|
207
|
+
}
|
|
208
|
+
return serviceKey.substring(0, serviceKey.indexOf('#'));
|
|
209
|
+
}
|
|
210
|
+
exports.getSpyEventType = getSpyEventType;
|
|
211
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGlzaFNweUV2ZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vY29tbW9uL3B1Ymxpc2hTcHlFdmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw0RkFHaUQ7QUFDakQsOERBS2tDO0FBRWxDLDBEQUFvRDtBQVFwRCxxRUFBa0U7QUFVbEUsTUFBTSxHQUFHLEdBQUcsSUFBSSxnQ0FBYyxDQUFDO0lBQzdCLE1BQU0sRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVU7Q0FDL0IsQ0FBQyxDQUFDO0FBRUgsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLHdEQUF1QixDQUFDO0lBQ3JELFVBQVUsRUFBRSxZQUFZO0lBQ3hCLFFBQVEsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLG1DQUFnQixDQUFDLGdCQUFnQixDQUFFO0NBQzFELENBQUMsQ0FBQztBQUVILElBQUksV0FBeUQsQ0FBQztBQUV2RCxLQUFLLFVBQVUsZUFBZSxDQUFDLEtBQVU7SUFDOUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBRTVDLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQ0FBZ0IsQ0FBQyxrQkFBa0IsQ0FBRSxDQUFDLENBQUM7SUFDOUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBRWhELElBQUksY0FBYyxDQUFDO0lBRW5CLE1BQU0sVUFBVSxHQUFHLElBQUksNkJBQVcsQ0FBQztRQUNqQyxTQUFTLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxtQ0FBZ0IsQ0FBQyxrQkFBa0IsQ0FBVztRQUNyRSxvQkFBb0IsRUFBRSxjQUFjO0tBQ3JDLENBQUMsQ0FBQztJQUVILGNBQWMsR0FBRyxNQUFNLEdBQUcsQ0FBQyxJQUFJ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T0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO0FBQ3JDLENBQUM7QUExQ0QsNEJBMENDO0FBRUQsU0FBZ0IsZUFBZSxDQUFDLFVBQWtCO0lBQ2hELElBQUksQ0FBQyxVQUFVLEVBQUU7UUFDZixNQUFNLElBQUksS0FBSyxDQUFDLG9CQUFvQixDQUFDLENBQUM7S0FDdkM7SUFFRCxPQUFPLFVBQVUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUMxRCxDQUFDO0FBTkQsMENBTUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBcGlHYXRld2F5TWFuYWdlbWVudEFwaSxcbiAgUG9zdFRvQ29ubmVjdGlvbkNvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1hcGlnYXRld2F5bWFuYWdlbWVudGFwaSc7XG5pbXBvcnQge1xuICBBdHRyaWJ1dGVWYWx1ZSxcbiAgRGVsZXRlSXRlbUNvbW1hbmQsXG4gIER5bmFtb0RCQ2xpZW50LFxuICBTY2FuQ29tbWFuZCxcbn0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWR5bmFtb2RiJztcblxuaW1wb3J0IHsgdW5tYXJzaGFsbCB9IGZyb20gJ0Bhd3Mtc2RrL3V0aWwtZHluYW1vZGInO1xuaW1wb3J0IHtcbiAgRHluYW1vREJTdHJlYW1FdmVudCxcbiAgUzNFdmVudCxcbiAgU05TRXZlbnQsXG4gIEV2ZW50QnJpZGdlRXZlbnQsXG4gIFNRU0V2ZW50LFxufSBmcm9tICdhd3MtbGFtYmRhJztcbmltcG9ydCB7IGVudlZhcmlhYmxlTmFtZXMgfSBmcm9tICcuLi9zcmMvY29tbW9uL2VudlZhcmlhYmxlTmFtZXMnO1xuaW1wb3J0IHsgRHluYW1vREJTcHlFdmVudCB9IGZyb20gJy4vc3B5RXZlbnRzL0R5bmFtb0RCU3B5RXZlbnQnO1xuaW1wb3J0IHsgRXZlbnRCcmlkZ2VSdWxlU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9FdmVudEJyaWRnZVJ1bGVTcHlFdmVudCc7XG5pbXBvcnQgeyBFdmVudEJyaWRnZVNweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvRXZlbnRCcmlkZ2VTcHlFdmVudCc7XG5pbXBvcnQgeyBTM1NweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvUzNTcHlFdmVudCc7XG5pbXBvcnQgeyBTbnNTdWJzY3JpcHRpb25TcHlFdmVudCB9IGZyb20gJy4vc3B5RXZlbnRzL1Nuc1N1YnNjcmlwdGlvblNweUV2ZW50JztcbmltcG9ydCB7IFNuc1RvcGljU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9TbnNUb3BpY1NweUV2ZW50JztcbmltcG9ydCB7IFNweU1lc3NhZ2UgfSBmcm9tICcuL3NweUV2ZW50cy9TcHlNZXNzYWdlJztcbmltcG9ydCB7IFNxc1NweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvU3FzU3B5RXZlbnQnO1xuXG5jb25zdCBkZGIgPSBuZXcgRHluYW1vREJDbGllbnQoe1xuICByZWdpb246IHByb2Nlc3MuZW52LkFXU19SRUdJT04sXG59KTtcblxuY29uc3QgYXBpZ3dNYW5hZ2VtZW50QXBpID0gbmV3IEFwaUdhdGV3YXlNYW5hZ2VtZW50QXBpKHtcbiAgYXBpVmVyc2lvbjogJzIwMTgtMTEtMjknLFxuICBlbmRwb2ludDogcHJvY2Vzcy5lbnZbZW52VmFyaWFibGVOYW1lcy5TU1BZX1dTX0VORFBPSU5UXSEsXG59KTtcblxubGV0IGNvbm5lY3Rpb25zOiBSZWNvcmQ8c3RyaW5nLCBBdHRyaWJ1dGVWYWx1ZT5bXSB8IHVuZGVmaW5lZDtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1Ymxpc2hTcHlFdmVudChldmVudDogYW55KSB7XG4gIGNvbnNvbGUubG9nKCdFVkVOVCcsIEpTT04uc3RyaW5naWZ5KGV2ZW50KSk7XG5cbiAgY29uc3QgbWFwcGluZyA9IEpTT04ucGFyc2UocHJvY2Vzcy5lbnZbZW52VmFyaWFibGVOYW1lcy5TU1BZX0lORlJBX01BUFBJTkddISk7XG4gIGNvbnNvbGUubG9nKCdtYXBwaW5nJywgSlNPTi5zdHJpbmdpZnkobWFwcGluZykpO1xuXG4gIGxldCBjb25uZWN0aW9uRGF0YTtcblxuICBjb25zdCBzY2FuUGFyYW1zID0gbmV3IFNjYW5Db21tYW5kKHtcbiAgICBUYWJsZU5hbWU6IHByb2Nlc3MuZW52W2VudlZhcmlhYmxlTmFtZXMuU1NQWV9XU19UQUJMRV9OQU1FXSBhcyBzdHJpbmcsXG4gICAgUHJvamVjdGlvbkV4cHJlc3Npb246ICdjb25uZWN0aW9uSWQnLFxuICB9KTtcblxuICBjb25uZWN0aW9uRGF0YSA9IGF3YWl0IGRkYi5zZW5kKHNjYW5QYXJhbXMpO1xuXG4gIGNvbm5lY3Rpb25zID0gY29ubmVjdGlvbkRhdGEuSXRlbXM7XG5cbiAgY29uc29sZS5sb2coXG4gICAgYGNvbm5lY3Rpb25zIGF0ICR7bmV3IERhdGUoKS50b0lTT1N0cmluZygpfWAsXG4gICAgSlNPTi5zdHJpbmdpZnkoY29ubmVjdGlvbnMpXG4gICk7XG5cbiAgY29uc3QgcG9zdERhdGFQcm9taXNlczogUHJvbWlzZTxhbnk+W10gPSBbXTtcblxuICBpZiAoZXZlbnQ/LlJlY29yZHMgJiYgZXZlbnQuUmVjb3Jkc1swXT8uU25zKSB7XG4gICAgY29uc29sZS5sb2coJyoqKiBTTlMgKioqJyk7XG4gICAgY29uc3QgZXZlbnRTbnMgPSBldmVudCBhcyBTTlNFdmVudDtcbiAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBldmVudFNucy5SZWNvcmRzKSB7XG4gICAgICBjb25zdCBzdWJzY3JpcHRpb25Bcm4gPSByZWNvcmQuRXZlbnRTdWJzY3JpcHRpb25Bcm47XG5cbiAgICAgIGxldCBzZXJ2aWNlS2V5OiBzdHJpbmc7XG4gICAgICBpZiAobWFwcGluZ1tzdWJzY3JpcHRpb25Bcm5dKSB7XG4gICAgICAgIC8vIHN1YnNjcmlwdGlvbiBldmVudCB0aGF0IGNvdWxkIGNvbnRhaW4gZmlsdGVyIGJhc2VkIG9uIGV4aXN0aW5nIHN1YnNjcmlwdGlvblxuICAgICAgICBzZXJ2aWNlS2V5ID0gbWFwcGluZ1tzdWJzY3JpcHRpb25Bcm5dO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gY2F0Y2ggYWxsIHN1YnNjcmlwdGlvblxuICAgICAgICBjb25zdCB0b3BpY0FybiA9IHJlY29yZC5TbnMuVG9waWNBcm47XG4gICAgICAgIHNlcnZpY2VLZXkgPSBtYXBwaW5nW3RvcGljQXJuXTtcbiAgICAgIH1cblxuICAgICAgbGV0IG1lc3NhZ2U6IHN0cmluZztcblxuICAgICAgdHJ5IHtcbiAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2UocmVjb3JkLlNucy5NZXNzYWdlKTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICBtZXNzYWdlID0gcmVjb3JkLlNucy5NZXNzYWdlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBzcHlFdmVudFR5cGUgPSBnZXRTcHlFdmVudFR5cGUoc2VydmljZUtleSkgYXNcbiAgICAgICAgfCAnRnVuY3Rpb25TbnNUb3BpYydcbiAgICAgICAgfCAnRnVuY3Rpb25TbnNTdWJzY3JpcHRpb24nO1xuXG4gICAgICBjb25zdCBkYXRhOiBTbnNUb3BpY1NweUV2ZW50IHwgU25zU3Vic2NyaXB0aW9uU3B5RXZlbnQgPSB7XG4gICAgICAgIHNweUV2ZW50VHlwZSxcbiAgICAgICAgbWVzc2FnZSxcbiAgICAgICAgc3ViamVjdDogcmVjb3JkLlNucy5TdWJqZWN0LFxuICAgICAgICB0aW1lc3RhbXA6IHJlY29yZC5TbnMuVGltZXN0YW1wLFxuICAgICAgICB0b3BpY0FybjogcmVjb3JkLlNucy5Ub3BpY0FybixcbiAgICAgICAgbWVzc2FnZUlkOiByZWNvcmQuU25zLk1lc3NhZ2VJZCxcbiAgICAgICAgbWVzc2FnZUF0dHJpYnV0ZXM6IHJlY29yZC5TbnMuTWVzc2FnZUF0dHJpYnV0ZXMsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICAgIGRhdGEsXG4gICAgICAgIHNlcnZpY2VLZXksXG4gICAgICB9O1xuICAgICAgcG9zdERhdGFQcm9taXNlcy5wdXNoKHBvc3REYXRhKGZsdWVudEV2ZW50KSk7XG4gICAgfVxuICB9IGVsc2UgaWYgKGV2ZW50Py5SZWNvcmRzICYmIGV2ZW50LlJlY29yZHNbMF0/LmV2ZW50U291cmNlID09PSAnYXdzOnNxcycpIHtcbiAgICBjb25zb2xlLmxvZygnKioqIFNRUyAqKionKTtcbiAgICBjb25zdCBldmVudFNxcyA9IGV2ZW50IGFzIFNRU0V2ZW50O1xuICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIGV2ZW50U3FzLlJlY29yZHMpIHtcbiAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbkFybiA9IHJlY29yZC5ldmVudFNvdXJjZUFSTjtcblxuICAgICAgY29uc3Qgc2VydmljZUtleSA9IG1hcHBpbmdbc3Vic2NyaXB0aW9uQXJuXTtcbiAgICAgIGxldCBib2R5OiBzdHJpbmc7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGJvZHkgPSBKU09OLnBhcnNlKHJlY29yZC5ib2R5KTtcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICBib2R5ID0gcmVjb3JkLmJvZHk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGE6IFNxc1NweUV2ZW50ID0ge1xuICAgICAgICBzcHlFdmVudFR5cGU6ICdTcXMnLFxuICAgICAgICBib2R5LFxuICAgICAgICBtZXNzYWdlQXR0cmlidXRlczogcmVjb3JkLm1lc3NhZ2VBdHRyaWJ1dGVzLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0ge1xuICAgICAgICBkYXRhLFxuICAgICAgICBzZXJ2aWNlS2V5LFxuICAgICAgfTtcbiAgICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaChwb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChldmVudD8uUmVjb3JkcyAmJiBldmVudC5SZWNvcmRzWzBdPy5zMykge1xuICAgIGNvbnNvbGUubG9nKCcqKiogUzMgKioqJyk7XG4gICAgY29uc3QgZXZlbnRTMyA9IGV2ZW50IGFzIFMzRXZlbnQ7XG4gICAgZm9yIChjb25zdCByZWNvcmQgb2YgZXZlbnRTMy5SZWNvcmRzKSB7XG4gICAgICBjb25zdCBidWNrZXRBcm4gPSByZWNvcmQuczMuYnVja2V0LmFybjtcblxuICAgICAgY29uc3QgZGF0YTogUzNTcHlFdmVudCA9IHtcbiAgICAgICAgc3B5RXZlbnRUeXBlOiAnUzMnLFxuICAgICAgICBldmVudE5hbWU6IHJlY29yZC5ldmVudE5hbWUsXG4gICAgICAgIGV2ZW50VGltZTogcmVjb3JkLmV2ZW50VGltZSxcbiAgICAgICAgYnVja2V0OiByZWNvcmQuczMuYnVja2V0Lm5hbWUsXG4gICAgICAgIGtleTogcmVjb3JkLnMzLm9iamVjdC5rZXksXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICAgIGRhdGEsXG4gICAgICAgIHNlcnZpY2VLZXk6IG1hcHBpbmdbYnVja2V0QXJuXSxcbiAgICAgIH07XG4gICAgICBwb3N0RGF0YVByb21pc2VzLnB1c2gocG9zdERhdGEoZmx1ZW50RXZlbnQpKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoZXZlbnQuUmVjb3JkcyAmJiBldmVudC5SZWNvcmRzWzBdPy5keW5hbW9kYikge1xuICAgIGNvbnNvbGUubG9nKCcqKiogRFlOQU1PREIgKioqJyk7XG4gICAgY29uc3QgZXZlbnREeW5hbW9EQiA9IGV2ZW50IGFzIER5bmFtb0RCU3RyZWFtRXZlbnQ7XG4gICAgZm9yIChjb25zdCByZWNvcmQgb2YgZXZlbnREeW5hbW9EQi5SZWNvcmRzKSB7XG4gICAgICBsZXQgYXJuID0gcmVjb3JkLmV2ZW50U291cmNlQVJOITtcbiAgICAgIGFybiA9IGFybi5zdWJzdHJpbmcoMCwgYXJuLmluZGV4T2YoJy9zdHJlYW0vJykpO1xuXG4gICAgICBjb25zdCBkYXRhOiBEeW5hbW9EQlNweUV2ZW50ID0ge1xuICAgICAgICBzcHlFdmVudFR5cGU6ICdEeW5hbW9EQicsXG4gICAgICAgIGV2ZW50TmFtZTogcmVjb3JkLmV2ZW50TmFtZSxcbiAgICAgICAgbmV3SW1hZ2U6IHVubWFyc2hhbGwocmVjb3JkLmR5bmFtb2RiPy5OZXdJbWFnZSBhcyBhbnkpLFxuICAgICAgICBrZXlzOiB1bm1hcnNoYWxsKHJlY29yZC5keW5hbW9kYj8uS2V5cyBhcyBhbnkpLFxuICAgICAgICBvbGRJbWFnZTogcmVjb3JkLmR5bmFtb2RiPy5PbGRJbWFnZVxuICAgICAgICAgID8gdW5tYXJzaGFsbChyZWNvcmQuZHluYW1vZGI/Lk9sZEltYWdlIGFzIGFueSlcbiAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGZsdWVudEV2ZW50OiBPbWl0PFNweU1lc3NhZ2UsICd0aW1lc3RhbXAnPiA9IHtcbiAgICAgICAgZGF0YSxcbiAgICAgICAgc2VydmljZUtleTogbWFwcGluZ1thcm5dLFxuICAgICAgfTtcbiAgICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaChwb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgIH1cbiAgfSBlbHNlIGlmIChcbiAgICBldmVudC5kZXRhaWwgJiZcbiAgICBldmVudFsnZGV0YWlsLXR5cGUnXSAmJlxuICAgIGV2ZW50LnZlcnNpb24gJiZcbiAgICBldmVudC5zb3VyY2VcbiAgKSB7XG4gICAgY29uc29sZS5sb2coJyoqKiBFdmVudEJyaWRnZSAqKionKTtcbiAgICBjb25zdCBldmVudEViID0gZXZlbnQgYXMgRXZlbnRCcmlkZ2VFdmVudDxhbnksIGFueT47XG5cbiAgICBjb25zdCBzZXJ2aWNlS2V5ID0gbWFwcGluZy5ldmVudEJyaWRnZTsgLy8gdGhlIGlzIG5ldyBsYW1iZGEgZm9yIGVhY2ggc3Vic2NyaXB0aW9uXG5cbiAgICBjb25zdCBzcHlFdmVudFR5cGUgPSBnZXRTcHlFdmVudFR5cGUoc2VydmljZUtleSkgYXNcbiAgICAgIHwgJ0V2ZW50QnJpZGdlJ1xuICAgICAgfCAnRXZlbnRCcmlkZ2VSdWxlJztcblxuICAgIGNvbnN0IG1lc3NhZ2UgPSBldmVudEViLmRldGFpbDtcblxuICAgIGNvbnN0IGRhdGE6IEV2ZW50QnJpZGdlU3B5RXZlbnQgfCBFdmVudEJyaWRnZVJ1bGVTcHlFdmVudCA9IHtcbiAgICAgIHNweUV2ZW50VHlwZSxcbiAgICAgIGRldGFpbDogbWVzc2FnZSxcbiAgICAgIGRldGFpbFR5cGU6IGV2ZW50RWJbJ2RldGFpbC10eXBlJ10sXG4gICAgICBzb3VyY2U6IGV2ZW50RWIuc291cmNlLFxuICAgICAgdGltZTogZXZlbnRFYi50aW1lLFxuICAgICAgYWNjb3VudDogZXZlbnRFYi5hY2NvdW50LFxuICAgIH07XG5cbiAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICBkYXRhLFxuICAgICAgc2VydmljZUtleSxcbiAgICB9O1xuICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaChwb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICB9IGVsc2Uge1xuICAgIGNvbnNvbGUubG9nKCcqKiogT1RIRVIgKioqJyk7XG4gICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0gZXZlbnQ7XG4gICAgcG9zdERhdGFQcm9taXNlcy5wdXNoKHBvc3REYXRhKGZsdWVudEV2ZW50KSk7XG4gIH1cblxuICBhd2FpdCBQcm9taXNlLmFsbChwb3N0RGF0YVByb21pc2VzKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3REYXRhKHNweU1lc3NhZ2U6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+KSB7XG4gIC8vIGNvbnN0IHBvc3REYXRhID0gSlNPTi5wYXJzZShldmVudC5ib2R5ISkuZGF0YTtcbiAgY29uc29sZS5sb2coJ3Bvc3REYXRhJywgSlNPTi5zdHJpbmdpZnkoc3B5TWVzc2FnZSkpO1xuXG4gIGlmICghY29ubmVjdGlvbnMpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBjb25zdCBwb3N0Q2FsbHMgPSBjb25uZWN0aW9ucy5tYXAoYXN5bmMgKHsgY29ubmVjdGlvbklkIH0pID0+IHtcbiAgICBjb25zb2xlLmxvZyhgU2VuZGluZyBtZXNzYWdlIHRvOiAke2Nvbm5lY3Rpb25JZC5TfWApO1xuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBvc3RUb0Nvbm5lY3Rpb25Db21tYW5kID0gbmV3IFBvc3RUb0Nvbm5lY3Rpb25Db21tYW5kKHtcbiAgICAgICAgQ29ubmVjdGlvbklkOiBjb25uZWN0aW9uSWQuUyxcbiAgICAgICAgRGF0YTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAgIHNlcnZpY2VLZXk6IHNweU1lc3NhZ2Uuc2VydmljZUtleSxcbiAgICAgICAgICBkYXRhOiBzcHlNZXNzYWdlLmRhdGEsXG4gICAgICAgIH0pIGFzIGFueSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBhcGlnd01hbmFnZW1lbnRBcGkuc2VuZChwb3N0VG9Db25uZWN0aW9uQ29tbWFuZCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgY29uc29sZS5lcnJvcihgRmFpbHMgc2VuZGluZyBtZXNzYWdlIHRvOiAke2Nvbm5lY3Rpb25JZC5TfWAsIGUpO1xuICAgICAgY29uc29sZS5lcnJvcihgU3RhdHVzIGNvZGU6ICR7KGUgYXMgYW55KS5zdGF0dXNDb2RlfWApO1xuICAgICAgaWYgKChlIGFzIGFueSkuJG1ldGFkYXRhLmh0dHBTdGF0dXNDb2RlID09PSA0MTApIHtcbiAgICAgICAgY29uc29sZS5sb2coYEZvdW5kIHN0YWxlIGNvbm5lY3Rpb24sIGRlbGV0aW5nICR7Y29ubmVjdGlvbklkfWApO1xuXG4gICAgICAgIGNvbnN0IGRlbGV0ZVBhcmFtcyA9IG5ldyBEZWxldGVJdGVtQ29tbWFuZCh7XG4gICAgICAgICAgVGFibGVOYW1lOiBwcm9jZXNzLmVudltlbnZWYXJpYWJsZU5hbWVzLlNTUFlfV1NfVEFCTEVfTkFNRV0sXG4gICAgICAgICAgS2V5OiB7IGNvbm5lY3Rpb25JZCB9LFxuICAgICAgICB9KTtcblxuICAgICAgICBhd2FpdCBkZGIuc2VuZChkZWxldGVQYXJhbXMpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xuXG4gIGF3YWl0IFByb21pc2UuYWxsKHBvc3RDYWxscyk7XG4gIGNvbnNvbGUubG9nKCdTZW5kIG1lc3NhZ2UgZmluaXNoJyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTcHlFdmVudFR5cGUoc2VydmljZUtleTogc3RyaW5nKSB7XG4gIGlmICghc2VydmljZUtleSkge1xuICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBzZXJ2aWNlS2V5Jyk7XG4gIH1cblxuICByZXR1cm4gc2VydmljZUtleS5zdWJzdHJpbmcoMCwgc2VydmljZUtleS5pbmRleE9mKCcjJykpO1xufVxuIl19
|