UNPKG

serverless-spy

Version:

CDK-based library for writing elegant integration tests on AWS serverless architecture and an additional web console to monitor events in real time.

227 lines 31 kB
import { unmarshall } from '@aws-sdk/util-dynamodb'; import { v4 } from 'uuid'; import { getConnection } from '../listener/iot-connection'; import { getTopic } from '../listener/topic'; import { envVariableNames } from '../src/common/envVariableNames'; export class SpyEventSender { constructor(params) { this.debugMode = process.env[envVariableNames.SSPY_DEBUG] === 'true'; if (params.log) { this.log = params.log; } if (params.logError) { this.logError = params.logError; } this.scope = params.scope; this.iotEndpoint = params.iotEndpoint; } async close() { this.connection?.end(); } async connect() { this.connection = await getConnection(this.debugMode, this.iotEndpoint); } async publishSpyEvent(event) { this.log('Event', JSON.stringify(event)); const mapping = JSON.parse(process.env[envVariableNames.SSPY_INFRA_MAPPING]); this.log('ARN to names mapping', JSON.stringify(mapping)); const postDataPromises = []; if (event?.Records && event.Records[0]?.Sns) { //console.log('*** SNS ***'); const eventSns = event; for (const record of eventSns.Records) { const subscriptionArn = record.EventSubscriptionArn; let serviceKey; if (mapping[subscriptionArn]) { // subscription event that could contain filter based on existing subscription serviceKey = mapping[subscriptionArn]; } else { // catch all subscription const topicArn = record.Sns.TopicArn; serviceKey = mapping[topicArn]; } let message; try { message = JSON.parse(record.Sns.Message); } catch { message = record.Sns.Message; } const spyEventType = this.getSpyEventType(serviceKey); const data = { spyEventType, message, subject: record.Sns.Subject, timestamp: record.Sns.Timestamp, topicArn: record.Sns.TopicArn, messageId: record.Sns.MessageId, messageAttributes: record.Sns.MessageAttributes, }; const fluentEvent = { data, serviceKey, }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event?.Records && event.Records[0]?.eventSource === 'aws:sqs') { //console.log('*** SQS ***'); const eventSqs = event; for (const record of eventSqs.Records) { const subscriptionArn = record.eventSourceARN; const serviceKey = mapping[subscriptionArn]; let body; try { body = JSON.parse(record.body); } catch { body = record.body; } const data = { spyEventType: 'Sqs', body, messageAttributes: record.messageAttributes, }; const fluentEvent = { data, serviceKey, }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event?.Records && event.Records[0]?.s3) { //console.log('*** S3 ***'); const eventS3 = event; for (const record of eventS3.Records) { const bucketArn = record.s3.bucket.arn; const data = { spyEventType: 'S3', eventName: record.eventName, eventTime: record.eventTime, bucket: record.s3.bucket.name, key: record.s3.object.key, }; const fluentEvent = { data, serviceKey: mapping[bucketArn], }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event.Records && event.Records[0]?.dynamodb) { //console.log('*** DYNAMODB ***'); const eventDynamoDB = event; for (const record of eventDynamoDB.Records) { let arn = record.eventSourceARN; arn = arn.substring(0, arn.indexOf('/stream/')); const data = { spyEventType: 'DynamoDB', eventName: record.eventName, newImage: record.dynamodb?.NewImage ? unmarshall(record.dynamodb?.NewImage) : undefined, keys: unmarshall(record.dynamodb?.Keys), oldImage: record.dynamodb?.OldImage ? unmarshall(record.dynamodb?.OldImage) : undefined, }; const fluentEvent = { data, serviceKey: mapping[arn], }; postDataPromises.push(this.postData(fluentEvent)); } } else if (event.detail && event['detail-type'] && event.version && event.source) { //console.log('*** EventBridge ***'); const eventEb = event; const serviceKey = mapping.eventBridge; // the is new lambda for each subscription const spyEventType = this.getSpyEventType(serviceKey); const message = eventEb.detail; const data = { spyEventType, detail: message, detailType: eventEb['detail-type'], eventBridgeId: eventEb['id'], source: eventEb.source, time: eventEb.time, account: eventEb.account, }; const fluentEvent = { data, serviceKey, }; postDataPromises.push(this.postData(fluentEvent)); } else { //console.log('*** OTHER ***'); const fluentEvent = event; postDataPromises.push(this.postData(fluentEvent)); } await Promise.all(postDataPromises); } encode(input) { const payload = JSON.stringify(input); const parts = payload.match(/.{1,50000}/g); if (!parts) return []; this.log(`Encoded iot message, ${parts.length}`); const id = v4(); return parts.map((part, index) => ({ id, index, count: parts.length, data: part, })); } async postData(spyMessage) { if (this.connection === undefined) { throw new Error('No IoT connection created yet, did you forget to call connect()?'); } const withTimeStamp = { ...spyMessage, timestamp: spyMessage.timestamp || new Date().toISOString(), }; this.log('Post spy message', JSON.stringify(withTimeStamp)); const connection = this.connection; const topic = getTopic(this.scope); try { for (const fragment of this.encode(withTimeStamp)) { await new Promise((resolve) => { connection.publish(topic, JSON.stringify(fragment), { qos: 1, }, () => { this.log('Publishing finished'); resolve(); }); }); this.log(`Published fragment ${fragment.index} out of ${fragment.count} to topic ${topic}`); } } catch (e) { this.logError(`Failed to send payload to iot: ${e}`); } this.log('Send spy message finish'); } getSpyEventType(serviceKey) { if (!serviceKey) { throw new Error('Missing serviceKey'); } return serviceKey.substring(0, serviceKey.indexOf('#')); } log(message, ...optionalParams) { if (this.debugMode) { console.debug('SSPY EXTENSION', message, ...optionalParams); } } logError(message, ...optionalParams) { if (this.debugMode) { console.error('SSPY EXTENSION', message, ...optionalParams); } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3B5RXZlbnRTZW5kZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9jb21tb24vU3B5RXZlbnRTZW5kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBU3BELE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFTMUIsT0FBTyxFQUFZLGFBQWEsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ3JFLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUM3QyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUVsRSxNQUFNLE9BQU8sY0FBYztJQU16QixZQUFZLE1BS1g7UUFWRCxjQUFTLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLENBQUMsS0FBSyxNQUFNLENBQUM7UUFXOUQsSUFBSSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDZixJQUFJLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUM7UUFDeEIsQ0FBQztRQUVELElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQztRQUNsQyxDQUFDO1FBRUQsSUFBSSxDQUFDLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDO1FBQzFCLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQztJQUN4QyxDQUFDO0lBRU0sS0FBSyxDQUFDLEtBQUs7UUFDaEIsSUFBSSxDQUFDLFVBQVUsRUFBRSxHQUFHLEVBQUUsQ0FBQztJQUN6QixDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU87UUFDbEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLGFBQWEsQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxXQUFX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Z0JBQWdCLEVBQUUsT0FBTyxFQUFFLEdBQUcsY0FBYyxDQUFDLENBQUM7UUFDOUQsQ0FBQztJQUNILENBQUM7SUFFTyxRQUFRLENBQUMsT0FBZSxFQUFFLEdBQUcsY0FBcUI7UUFDeEQsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDbkIsT0FBTyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsR0FBRyxjQUFjLENBQUMsQ0FBQztRQUM5RCxDQUFDO0lBQ0gsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgdW5tYXJzaGFsbCB9IGZyb20gJ0Bhd3Mtc2RrL3V0aWwtZHluYW1vZGInO1xuaW1wb3J0IGlvdCBmcm9tICdhd3MtaW90LWRldmljZS1zZGsnO1xuaW1wb3J0IHtcbiAgRHluYW1vREJTdHJlYW1FdmVudCxcbiAgUzNFdmVudCxcbiAgU05TRXZlbnQsXG4gIEV2ZW50QnJpZGdlRXZlbnQsXG4gIFNRU0V2ZW50LFxufSBmcm9tICdhd3MtbGFtYmRhJztcbmltcG9ydCB7IHY0IH0gZnJvbSAndXVpZCc7XG5pbXBvcnQgeyBEeW5hbW9EQlNweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvRHluYW1vREJTcHlFdmVudCc7XG5pbXBvcnQgeyBFdmVudEJyaWRnZVJ1bGVTcHlFdmVudCB9IGZyb20gJy4vc3B5RXZlbnRzL0V2ZW50QnJpZGdlUnVsZVNweUV2ZW50JztcbmltcG9ydCB7IEV2ZW50QnJpZGdlU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9FdmVudEJyaWRnZVNweUV2ZW50JztcbmltcG9ydCB7IFMzU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9TM1NweUV2ZW50JztcbmltcG9ydCB7IFNuc1N1YnNjcmlwdGlvblNweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvU25zU3Vic2NyaXB0aW9uU3B5RXZlbnQnO1xuaW1wb3J0IHsgU25zVG9waWNTcHlFdmVudCB9IGZyb20gJy4vc3B5RXZlbnRzL1Nuc1RvcGljU3B5RXZlbnQnO1xuaW1wb3J0IHsgU3B5TWVzc2FnZSB9IGZyb20gJy4vc3B5RXZlbnRzL1NweU1lc3NhZ2UnO1xuaW1wb3J0IHsgU3FzU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9TcXNTcHlFdmVudCc7XG5pbXBvcnQgeyBmcmFnbWVudCwgZ2V0Q29ubmVjdGlvbiB9IGZyb20gJy4uL2xpc3RlbmVyL2lvdC1jb25uZWN0aW9uJztcbmltcG9ydCB7IGdldFRvcGljIH0gZnJvbSAnLi4vbGlzdGVuZXIvdG9waWMnO1xuaW1wb3J0IHsgZW52VmFyaWFibGVOYW1lcyB9IGZyb20gJy4uL3NyYy9jb21tb24vZW52VmFyaWFibGVOYW1lcyc7XG5cbmV4cG9ydCBjbGFzcyBTcHlFdmVudFNlbmRlciB7XG4gIGRlYnVnTW9kZSA9IHByb2Nlc3MuZW52W2VudlZhcmlhYmxlTmFtZXMuU1NQWV9ERUJVR10gPT09ICd0cnVlJztcbiAgY29ubmVjdGlvbjogaW90LmRldmljZSB8IHVuZGVmaW5lZDtcbiAgc2NvcGU6IHN0cmluZztcbiAgaW90RW5kcG9pbnQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihwYXJhbXM6IHtcbiAgICBsb2c/OiAobWVzc2FnZTogc3RyaW5nLCAuLi5vcHRpb25hbFBhcmFtczogYW55W10pID0+IHZvaWQ7XG4gICAgbG9nRXJyb3I/OiAobWVzc2FnZTogc3RyaW5nLCAuLi5vcHRpb25hbFBhcmFtczogYW55W10pID0+IHZvaWQ7XG4gICAgc2NvcGU6IHN0cmluZztcbiAgICBpb3RFbmRwb2ludDogc3RyaW5nO1xuICB9KSB7XG4gICAgaWYgKHBhcmFtcy5sb2cpIHtcbiAgICAgIHRoaXMubG9nID0gcGFyYW1zLmxvZztcbiAgICB9XG5cbiAgICBpZiAocGFyYW1zLmxvZ0Vycm9yKSB7XG4gICAgICB0aGlzLmxvZ0Vycm9yID0gcGFyYW1zLmxvZ0Vycm9yO1xuICAgIH1cblxuICAgIHRoaXMuc2NvcGUgPSBwYXJhbXMuc2NvcGU7XG4gICAgdGhpcy5pb3RFbmRwb2ludCA9IHBhcmFtcy5pb3RFbmRwb2ludDtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjbG9zZSgpIHtcbiAgICB0aGlzLmNvbm5lY3Rpb24/LmVuZCgpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGNvbm5lY3QoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uID0gYXdhaXQgZ2V0Q29ubmVjdGlvbih0aGlzLmRlYnVnTW9kZSwgdGhpcy5pb3RFbmRwb2ludCk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgcHVibGlzaFNweUV2ZW50KGV2ZW50OiBhbnkpIHtcbiAgICB0aGlzLmxvZygnRXZlbnQnLCBKU09OLnN0cmluZ2lmeShldmVudCkpO1xuXG4gICAgY29uc3QgbWFwcGluZyA9IEpTT04ucGFyc2UoXG4gICAgICBwcm9jZXNzLmVudltlbnZWYXJpYWJsZU5hbWVzLlNTUFlfSU5GUkFfTUFQUElOR10hXG4gICAgKTtcbiAgICB0aGlzLmxvZygnQVJOIHRvIG5hbWVzIG1hcHBpbmcnLCBKU09OLnN0cmluZ2lmeShtYXBwaW5nKSk7XG5cbiAgICBjb25zdCBwb3N0RGF0YVByb21pc2VzOiBQcm9taXNlPGFueT5bXSA9IFtdO1xuXG4gICAgaWYgKGV2ZW50Py5SZWNvcmRzICYmIGV2ZW50LlJlY29yZHNbMF0/LlNucykge1xuICAgICAgLy9jb25zb2xlLmxvZygnKioqIFNOUyAqKionKTtcbiAgICAgIGNvbnN0IGV2ZW50U25zID0gZXZlbnQgYXMgU05TRXZlbnQ7XG4gICAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBldmVudFNucy5SZWNvcmRzKSB7XG4gICAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbkFybiA9IHJlY29yZC5FdmVudFN1YnNjcmlwdGlvbkFybjtcblxuICAgICAgICBsZXQgc2VydmljZUtleTogc3RyaW5nO1xuICAgICAgICBpZiAobWFwcGluZ1tzdWJzY3JpcHRpb25Bcm5dKSB7XG4gICAgICAgICAgLy8gc3Vic2NyaXB0aW9uIGV2ZW50IHRoYXQgY291bGQgY29udGFpbiBmaWx0ZXIgYmFzZWQgb24gZXhpc3Rpbmcgc3Vic2NyaXB0aW9uXG4gICAgICAgICAgc2VydmljZUtleSA9IG1hcHBpbmdbc3Vic2NyaXB0aW9uQXJuXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBjYXRjaCBhbGwgc3Vic2NyaXB0aW9uXG4gICAgICAgICAgY29uc3QgdG9waWNBcm4gPSByZWNvcmQuU25zLlRvcGljQXJuO1xuICAgICAgICAgIHNlcnZpY2VLZXkgPSBtYXBwaW5nW3RvcGljQXJuXTtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBtZXNzYWdlOiBzdHJpbmc7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBtZXNzYWdlID0gSlNPTi5wYXJzZShyZWNvcmQuU25zLk1lc3NhZ2UpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICBtZXNzYWdlID0gcmVjb3JkLlNucy5NZXNzYWdlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc3B5RXZlbnRUeXBlID0gdGhpcy5nZXRTcHlFdmVudFR5cGUoc2VydmljZUtleSkgYXNcbiAgICAgICAgICB8ICdGdW5jdGlvblNuc1RvcGljJ1xuICAgICAgICAgIHwgJ0Z1bmN0aW9uU25zU3Vic2NyaXB0aW9uJztcblxuICAgICAgICBjb25zdCBkYXRhOiBTbnNUb3BpY1NweUV2ZW50IHwgU25zU3Vic2NyaXB0aW9uU3B5RXZlbnQgPSB7XG4gICAgICAgICAgc3B5RXZlbnRUeXBlLFxuICAgICAgICAgIG1lc3NhZ2UsXG4gICAgICAgICAgc3ViamVjdDogcmVjb3JkLlNucy5TdWJqZWN0LFxuICAgICAgICAgIHRpbWVzdGFtcDogcmVjb3JkLlNucy5UaW1lc3RhbXAsXG4gICAgICAgICAgdG9waWNBcm46IHJlY29yZC5TbnMuVG9waWNBcm4sXG4gICAgICAgICAgbWVzc2FnZUlkOiByZWNvcmQuU25zLk1lc3NhZ2VJZCxcbiAgICAgICAgICBtZXNzYWdlQXR0cmlidXRlczogcmVjb3JkLlNucy5NZXNzYWdlQXR0cmlidXRlcyxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICAgICAgZGF0YSxcbiAgICAgICAgICBzZXJ2aWNlS2V5LFxuICAgICAgICB9O1xuICAgICAgICBwb3N0RGF0YVByb21pc2VzLnB1c2godGhpcy5wb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZXZlbnQ/LlJlY29yZHMgJiYgZXZlbnQuUmVjb3Jkc1swXT8uZXZlbnRTb3VyY2UgPT09ICdhd3M6c3FzJykge1xuICAgICAgLy9jb25zb2xlLmxvZygnKioqIFNRUyAqKionKTtcbiAgICAgIGNvbnN0IGV2ZW50U3FzID0gZXZlbnQgYXMgU1FTRXZlbnQ7XG4gICAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBldmVudFNxcy5SZWNvcmRzKSB7XG4gICAgICAgIGNvbnN0IHN1YnNjcmlwdGlvbkFybiA9IHJlY29yZC5ldmVudFNvdXJjZUFSTjtcblxuICAgICAgICBjb25zdCBzZXJ2aWNlS2V5ID0gbWFwcGluZ1tzdWJzY3JpcHRpb25Bcm5dO1xuICAgICAgICBsZXQgYm9keTogc3RyaW5nO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYm9keSA9IEpTT04ucGFyc2UocmVjb3JkLmJvZHkpO1xuICAgICAgICB9IGNhdGNoIHtcbiAgICAgICAgICBib2R5ID0gcmVjb3JkLmJvZHk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkYXRhOiBTcXNTcHlFdmVudCA9IHtcbiAgICAgICAgICBzcHlFdmVudFR5cGU6ICdTcXMnLFxuICAgICAgICAgIGJvZHksXG4gICAgICAgICAgbWVzc2FnZUF0dHJpYnV0ZXM6IHJlY29yZC5tZXNzYWdlQXR0cmlidXRlcyxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICAgICAgZGF0YSxcbiAgICAgICAgICBzZXJ2aWNlS2V5LFxuICAgICAgICB9O1xuICAgICAgICBwb3N0RGF0YVByb21pc2VzLnB1c2godGhpcy5wb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZXZlbnQ/LlJlY29yZHMgJiYgZXZlbnQuUmVjb3Jkc1swXT8uczMpIHtcbiAgICAgIC8vY29uc29sZS5sb2coJyoqKiBTMyAqKionKTtcbiAgICAgIGNvbnN0IGV2ZW50UzMgPSBldmVudCBhcyBTM0V2ZW50O1xuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgZXZlbnRTMy5SZWNvcmRzKSB7XG4gICAgICAgIGNvbnN0IGJ1Y2tldEFybiA9IHJlY29yZC5zMy5idWNrZXQuYXJuO1xuXG4gICAgICAgIGNvbnN0IGRhdGE6IFMzU3B5RXZlbnQgPSB7XG4gICAgICAgICAgc3B5RXZlbnRUeXBlOiAnUzMnLFxuICAgICAgICAgIGV2ZW50TmFtZTogcmVjb3JkLmV2ZW50TmFtZSxcbiAgICAgICAgICBldmVudFRpbWU6IHJlY29yZC5ldmVudFRpbWUsXG4gICAgICAgICAgYnVja2V0OiByZWNvcmQuczMuYnVja2V0Lm5hbWUsXG4gICAgICAgICAga2V5OiByZWNvcmQuczMub2JqZWN0LmtleSxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICAgICAgZGF0YSxcbiAgICAgICAgICBzZXJ2aWNlS2V5OiBtYXBwaW5nW2J1Y2tldEFybl0sXG4gICAgICAgIH07XG4gICAgICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaCh0aGlzLnBvc3REYXRhKGZsdWVudEV2ZW50KSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChldmVudC5SZWNvcmRzICYmIGV2ZW50LlJlY29yZHNbMF0/LmR5bmFtb2RiKSB7XG4gICAgICAvL2NvbnNvbGUubG9nKCcqKiogRFlOQU1PREIgKioqJyk7XG4gICAgICBjb25zdCBldmVudER5bmFtb0RCID0gZXZlbnQgYXMgRHluYW1vREJTdHJlYW1FdmVudDtcbiAgICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIGV2ZW50RHluYW1vREIuUmVjb3Jkcykge1xuICAgICAgICBsZXQgYXJuID0gcmVjb3JkLmV2ZW50U291cmNlQVJOITtcbiAgICAgICAgYXJuID0gYXJuLnN1YnN0cmluZygwLCBhcm4uaW5kZXhPZignL3N0cmVhbS8nKSk7XG5cbiAgICAgICAgY29uc3QgZGF0YTogRHluYW1vREJTcHlFdmVudCA9IHtcbiAgICAgICAgICBzcHlFdmVudFR5cGU6ICdEeW5hbW9EQicsXG4gICAgICAgICAgZXZlbnROYW1lOiByZWNvcmQuZXZlbnROYW1lLFxuICAgICAgICAgIG5ld0ltYWdlOiByZWNvcmQuZHluYW1vZGI/Lk5ld0ltYWdlXG4gICAgICAgICAgICA/IHVubWFyc2hhbGwocmVjb3JkLmR5bmFtb2RiPy5OZXdJbWFnZSBhcyBhbnkpXG4gICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICBrZXlzOiB1bm1hcnNoYWxsKHJlY29yZC5keW5hbW9kYj8uS2V5cyBhcyBhbnkpLFxuICAgICAgICAgIG9sZEltYWdlOiByZWNvcmQuZHluYW1vZGI/Lk9sZEltYWdlXG4gICAgICAgICAgICA/IHVubWFyc2hhbGwocmVjb3JkLmR5bmFtb2RiPy5PbGRJbWFnZSBhcyBhbnkpXG4gICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSB7XG4gICAgICAgICAgZGF0YSxcbiAgICAgICAgICBzZXJ2aWNlS2V5OiBtYXBwaW5nW2Fybl0sXG4gICAgICAgIH07XG4gICAgICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaCh0aGlzLnBvc3REYXRhKGZsdWVudEV2ZW50KSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChcbiAgICAgIGV2ZW50LmRldGFpbCAmJlxuICAgICAgZXZlbnRbJ2RldGFpbC10eXBlJ10gJiZcbiAgICAgIGV2ZW50LnZlcnNpb24gJiZcbiAgICAgIGV2ZW50LnNvdXJjZVxuICAgICkge1xuICAgICAgLy9jb25zb2xlLmxvZygnKioqIEV2ZW50QnJpZGdlICoqKicpO1xuICAgICAgY29uc3QgZXZlbnRFYiA9IGV2ZW50IGFzIEV2ZW50QnJpZGdlRXZlbnQ8YW55LCBhbnk+O1xuXG4gICAgICBjb25zdCBzZXJ2aWNlS2V5ID0gbWFwcGluZy5ldmVudEJyaWRnZTsgLy8gdGhlIGlzIG5ldyBsYW1iZGEgZm9yIGVhY2ggc3Vic2NyaXB0aW9uXG5cbiAgICAgIGNvbnN0IHNweUV2ZW50VHlwZSA9IHRoaXMuZ2V0U3B5RXZlbnRUeXBlKHNlcnZpY2VLZXkpIGFzXG4gICAgICAgIHwgJ0V2ZW50QnJpZGdlJ1xuICAgICAgICB8ICdFdmVudEJyaWRnZVJ1bGUnO1xuXG4gICAgICBjb25zdCBtZXNzYWdlID0gZXZlbnRFYi5kZXRhaWw7XG5cbiAgICAgIGNvbnN0IGRhdGE6IEV2ZW50QnJpZGdlU3B5RXZlbnQgfCBFdmVudEJyaWRnZVJ1bGVTcHlFdmVudCA9IHtcbiAgICAgICAgc3B5RXZlbnRUeXBlLFxuICAgICAgICBkZXRhaWw6IG1lc3NhZ2UsXG4gICAgICAgIGRldGFpbFR5cGU6IGV2ZW50RWJbJ2RldGFpbC10eXBlJ10sXG4gICAgICAgIGV2ZW50QnJpZGdlSWQ6IGV2ZW50RWJbJ2lkJ10sXG4gICAgICAgIHNvdXJjZTogZXZlbnRFYi5zb3VyY2UsXG4gICAgICAgIHRpbWU6IGV2ZW50RWIudGltZSxcbiAgICAgICAgYWNjb3VudDogZXZlbnRFYi5hY2NvdW50LFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0ge1xuICAgICAgICBkYXRhLFxuICAgICAgICBzZXJ2aWNlS2V5LFxuICAgICAgfTtcbiAgICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaCh0aGlzLnBvc3REYXRhKGZsdWVudEV2ZW50KSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vY29uc29sZS5sb2coJyoqKiBPVEhFUiAqKionKTtcbiAgICAgIGNvbnN0IGZsdWVudEV2ZW50OiBPbWl0PFNweU1lc3NhZ2UsICd0aW1lc3RhbXAnPiA9IGV2ZW50O1xuICAgICAgcG9zdERhdGFQcm9taXNlcy5wdXNoKHRoaXMucG9zdERhdGEoZmx1ZW50RXZlbnQpKTtcbiAgICB9XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbChwb3N0RGF0YVByb21pc2VzKTtcbiAgfVxuXG4gIHByaXZhdGUgZW5jb2RlKGlucHV0OiBhbnkpOiBmcmFnbWVudFtdIHtcbiAgICBjb25zdCBwYXlsb2FkID0gSlNPTi5zdHJpbmdpZnkoaW5wdXQpO1xuICAgIGNvbnN0IHBhcnRzID0gcGF5bG9hZC5tYXRjaCgvLnsxLDUwMDAwfS9nKTtcbiAgICBpZiAoIXBhcnRzKSByZXR1cm4gW107XG4gICAgdGhpcy5sb2coYEVuY29kZWQgaW90IG1lc3NhZ2UsICR7cGFydHMubGVuZ3RofWApO1xuICAgIGNvbnN0IGlkID0gdjQoKTtcbiAgICByZXR1cm4gcGFydHMubWFwKChwYXJ0LCBpbmRleCkgPT4gKHtcbiAgICAgIGlkLFxuICAgICAgaW5kZXgsXG4gICAgICBjb3VudDogcGFydHMubGVuZ3RoLFxuICAgICAgZGF0YTogcGFydCxcbiAgICB9KSk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHBvc3REYXRhKFxuICAgIHNweU1lc3NhZ2U6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ICYgeyB0aW1lc3RhbXA/OiBzdHJpbmcgfVxuICApIHtcbiAgICBpZiAodGhpcy5jb25uZWN0aW9uID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgJ05vIElvVCBjb25uZWN0aW9uIGNyZWF0ZWQgeWV0LCBkaWQgeW91IGZvcmdldCB0byBjYWxsIGNvbm5lY3QoKT8nXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHdpdGhUaW1lU3RhbXAgPSB7XG4gICAgICAuLi5zcHlNZXNzYWdlLFxuICAgICAgdGltZXN0YW1wOiBzcHlNZXNzYWdlLnRpbWVzdGFtcCB8fCBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgfTtcblxuICAgIHRoaXMubG9nKCdQb3N0IHNweSBtZXNzYWdlJywgSlNPTi5zdHJpbmdpZnkod2l0aFRpbWVTdGFtcCkpO1xuXG4gICAgY29uc3QgY29ubmVjdGlvbiA9IHRoaXMuY29ubmVjdGlvbjtcbiAgICBjb25zdCB0b3BpYyA9IGdldFRvcGljKHRoaXMuc2NvcGUpO1xuXG4gICAgdHJ5IHtcbiAgICAgIGZvciAoY29uc3QgZnJhZ21lbnQgb2YgdGhpcy5lbmNvZGUod2l0aFRpbWVTdGFtcCkpIHtcbiAgICAgICAgYXdhaXQgbmV3IFByb21pc2U8dm9pZD4oKHJlc29sdmUpID0+IHtcbiAgICAgICAgICBjb25uZWN0aW9uLnB1Ymxpc2goXG4gICAgICAgICAgICB0b3BpYyxcbiAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGZyYWdtZW50KSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgcW9zOiAxLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgdGhpcy5sb2coJ1B1Ymxpc2hpbmcgZmluaXNoZWQnKTtcbiAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmxvZyhcbiAgICAgICAgICBgUHVibGlzaGVkIGZyYWdtZW50ICR7ZnJhZ21lbnQuaW5kZXh9IG91dCBvZiAke2ZyYWdtZW50LmNvdW50fSB0byB0b3BpYyAke3RvcGljfWBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICB0aGlzLmxvZ0Vycm9yKGBGYWlsZWQgdG8gc2VuZCBwYXlsb2FkIHRvIGlvdDogJHtlfWApO1xuICAgIH1cblxuICAgIHRoaXMubG9nKCdTZW5kIHNweSBtZXNzYWdlIGZpbmlzaCcpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRTcHlFdmVudFR5cGUoc2VydmljZUtleTogc3RyaW5nKSB7XG4gICAgaWYgKCFzZXJ2aWNlS2V5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3Npbmcgc2VydmljZUtleScpO1xuICAgIH1cblxuICAgIHJldHVybiBzZXJ2aWNlS2V5LnN1YnN0cmluZygwLCBzZXJ2aWNlS2V5LmluZGV4T2YoJyMnKSk7XG4gIH1cblxuICBwcml2YXRlIGxvZyhtZXNzYWdlOiBzdHJpbmcsIC4uLm9wdGlvbmFsUGFyYW1zOiBhbnlbXSkge1xuICAgIGlmICh0aGlzLmRlYnVnTW9kZSkge1xuICAgICAgY29uc29sZS5kZWJ1ZygnU1NQWSBFWFRFTlNJT04nLCBtZXNzYWdlLCAuLi5vcHRpb25hbFBhcmFtcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBsb2dFcnJvcihtZXNzYWdlOiBzdHJpbmcsIC4uLm9wdGlvbmFsUGFyYW1zOiBhbnlbXSkge1xuICAgIGlmICh0aGlzLmRlYnVnTW9kZSkge1xuICAgICAgY29uc29sZS5lcnJvcignU1NQWSBFWFRFTlNJT04nLCBtZXNzYWdlLCAuLi5vcHRpb25hbFBhcmFtcyk7XG4gICAgfVxuICB9XG59XG4iXX0=