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.
231 lines • 31.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SpyEventSender = void 0;
const util_dynamodb_1 = require("@aws-sdk/util-dynamodb");
const uuid_1 = require("uuid");
const iot_connection_1 = require("../listener/iot-connection");
const topic_1 = require("../listener/topic");
const envVariableNames_1 = require("../src/common/envVariableNames");
class SpyEventSender {
constructor(params) {
this.debugMode = process.env[envVariableNames_1.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 (0, iot_connection_1.getConnection)(this.debugMode, this.iotEndpoint);
}
async publishSpyEvent(event) {
this.log('Event', JSON.stringify(event));
const mapping = JSON.parse(process.env[envVariableNames_1.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
? (0, util_dynamodb_1.unmarshall)(record.dynamodb?.NewImage)
: undefined,
keys: (0, util_dynamodb_1.unmarshall)(record.dynamodb?.Keys),
oldImage: record.dynamodb?.OldImage
? (0, util_dynamodb_1.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 = (0, uuid_1.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 = (0, topic_1.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);
}
}
}
exports.SpyEventSender = SpyEventSender;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU3B5RXZlbnRTZW5kZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9jb21tb24vU3B5RXZlbnRTZW5kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsMERBQW9EO0FBU3BELCtCQUEwQjtBQVMxQiwrREFBcUU7QUFDckUsNkNBQTZDO0FBQzdDLHFFQUFrRTtBQUVsRSxNQUFhLGNBQWM7SUFNekIsWUFBWSxNQUtYO1FBVkQsY0FBUyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUNBQWdCLENBQUMsVUFBVSxDQUFDLEtBQUssTUFBTSxDQUFDO1FBVzlELElBQUksTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQ2YsSUFBSSxDQUFDLEdBQUcsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDO1FBQ3hCLENBQUM7UUFFRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQyxRQUFRLENBQUM7UUFDbEMsQ0FBQztRQUVELElBQUksQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztRQUMxQixJQUFJLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQyxXQUFXLENBQUM7SUFDeEMsQ0FBQztJQUVNLEtBQUssQ0FBQyxLQUFLO1FBQ2hCLElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFLENBQUM7SUFDekIsQ0FBQztJQUVNLEtBQUssQ0FBQyxPQUFPO1FBQ2xCLElBQUksQ0FBQyxVQUFVLEdBQUcsTUFBTSxJQUFBLDhCQUFhLEVBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDMUUsQ0FBQztJQUVNLEtBQUssQ0FBQyxlQUFlLENBQUMsS0FBVTtRQUNyQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFFekMsTUFBTSxPQUFPLEdB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QUMsU0FBUyxFQUFFLENBQUM7WUFDbkIsT0FBTyxDQUFDLEtBQUssQ0FBQyxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsR0FBRyxjQUFjLENBQUMsQ0FBQztRQUM5RCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBclJELHdDQXFSQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHVubWFyc2hhbGwgfSBmcm9tICdAYXdzLXNkay91dGlsLWR5bmFtb2RiJztcbmltcG9ydCBpb3QgZnJvbSAnYXdzLWlvdC1kZXZpY2Utc2RrJztcbmltcG9ydCB7XG4gIER5bmFtb0RCU3RyZWFtRXZlbnQsXG4gIFMzRXZlbnQsXG4gIFNOU0V2ZW50LFxuICBFdmVudEJyaWRnZUV2ZW50LFxuICBTUVNFdmVudCxcbn0gZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQgeyB2NCB9IGZyb20gJ3V1aWQnO1xuaW1wb3J0IHsgRHluYW1vREJTcHlFdmVudCB9IGZyb20gJy4vc3B5RXZlbnRzL0R5bmFtb0RCU3B5RXZlbnQnO1xuaW1wb3J0IHsgRXZlbnRCcmlkZ2VSdWxlU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9FdmVudEJyaWRnZVJ1bGVTcHlFdmVudCc7XG5pbXBvcnQgeyBFdmVudEJyaWRnZVNweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvRXZlbnRCcmlkZ2VTcHlFdmVudCc7XG5pbXBvcnQgeyBTM1NweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvUzNTcHlFdmVudCc7XG5pbXBvcnQgeyBTbnNTdWJzY3JpcHRpb25TcHlFdmVudCB9IGZyb20gJy4vc3B5RXZlbnRzL1Nuc1N1YnNjcmlwdGlvblNweUV2ZW50JztcbmltcG9ydCB7IFNuc1RvcGljU3B5RXZlbnQgfSBmcm9tICcuL3NweUV2ZW50cy9TbnNUb3BpY1NweUV2ZW50JztcbmltcG9ydCB7IFNweU1lc3NhZ2UgfSBmcm9tICcuL3NweUV2ZW50cy9TcHlNZXNzYWdlJztcbmltcG9ydCB7IFNxc1NweUV2ZW50IH0gZnJvbSAnLi9zcHlFdmVudHMvU3FzU3B5RXZlbnQnO1xuaW1wb3J0IHsgZnJhZ21lbnQsIGdldENvbm5lY3Rpb24gfSBmcm9tICcuLi9saXN0ZW5lci9pb3QtY29ubmVjdGlvbic7XG5pbXBvcnQgeyBnZXRUb3BpYyB9IGZyb20gJy4uL2xpc3RlbmVyL3RvcGljJztcbmltcG9ydCB7IGVudlZhcmlhYmxlTmFtZXMgfSBmcm9tICcuLi9zcmMvY29tbW9uL2VudlZhcmlhYmxlTmFtZXMnO1xuXG5leHBvcnQgY2xhc3MgU3B5RXZlbnRTZW5kZXIge1xuICBkZWJ1Z01vZGUgPSBwcm9jZXNzLmVudltlbnZWYXJpYWJsZU5hbWVzLlNTUFlfREVCVUddID09PSAndHJ1ZSc7XG4gIGNvbm5lY3Rpb246IGlvdC5kZXZpY2UgfCB1bmRlZmluZWQ7XG4gIHNjb3BlOiBzdHJpbmc7XG4gIGlvdEVuZHBvaW50OiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3IocGFyYW1zOiB7XG4gICAgbG9nPzogKG1lc3NhZ2U6IHN0cmluZywgLi4ub3B0aW9uYWxQYXJhbXM6IGFueVtdKSA9PiB2b2lkO1xuICAgIGxvZ0Vycm9yPzogKG1lc3NhZ2U6IHN0cmluZywgLi4ub3B0aW9uYWxQYXJhbXM6IGFueVtdKSA9PiB2b2lkO1xuICAgIHNjb3BlOiBzdHJpbmc7XG4gICAgaW90RW5kcG9pbnQ6IHN0cmluZztcbiAgfSkge1xuICAgIGlmIChwYXJhbXMubG9nKSB7XG4gICAgICB0aGlzLmxvZyA9IHBhcmFtcy5sb2c7XG4gICAgfVxuXG4gICAgaWYgKHBhcmFtcy5sb2dFcnJvcikge1xuICAgICAgdGhpcy5sb2dFcnJvciA9IHBhcmFtcy5sb2dFcnJvcjtcbiAgICB9XG5cbiAgICB0aGlzLnNjb3BlID0gcGFyYW1zLnNjb3BlO1xuICAgIHRoaXMuaW90RW5kcG9pbnQgPSBwYXJhbXMuaW90RW5kcG9pbnQ7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgY2xvc2UoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uPy5lbmQoKTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBjb25uZWN0KCkge1xuICAgIHRoaXMuY29ubmVjdGlvbiA9IGF3YWl0IGdldENvbm5lY3Rpb24odGhpcy5kZWJ1Z01vZGUsIHRoaXMuaW90RW5kcG9pbnQpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIHB1Ymxpc2hTcHlFdmVudChldmVudDogYW55KSB7XG4gICAgdGhpcy5sb2coJ0V2ZW50JywgSlNPTi5zdHJpbmdpZnkoZXZlbnQpKTtcblxuICAgIGNvbnN0IG1hcHBpbmcgPSBKU09OLnBhcnNlKFxuICAgICAgcHJvY2Vzcy5lbnZbZW52VmFyaWFibGVOYW1lcy5TU1BZX0lORlJBX01BUFBJTkddIVxuICAgICk7XG4gICAgdGhpcy5sb2coJ0FSTiB0byBuYW1lcyBtYXBwaW5nJywgSlNPTi5zdHJpbmdpZnkobWFwcGluZykpO1xuXG4gICAgY29uc3QgcG9zdERhdGFQcm9taXNlczogUHJvbWlzZTxhbnk+W10gPSBbXTtcblxuICAgIGlmIChldmVudD8uUmVjb3JkcyAmJiBldmVudC5SZWNvcmRzWzBdPy5TbnMpIHtcbiAgICAgIC8vY29uc29sZS5sb2coJyoqKiBTTlMgKioqJyk7XG4gICAgICBjb25zdCBldmVudFNucyA9IGV2ZW50IGFzIFNOU0V2ZW50O1xuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgZXZlbnRTbnMuUmVjb3Jkcykge1xuICAgICAgICBjb25zdCBzdWJzY3JpcHRpb25Bcm4gPSByZWNvcmQuRXZlbnRTdWJzY3JpcHRpb25Bcm47XG5cbiAgICAgICAgbGV0IHNlcnZpY2VLZXk6IHN0cmluZztcbiAgICAgICAgaWYgKG1hcHBpbmdbc3Vic2NyaXB0aW9uQXJuXSkge1xuICAgICAgICAgIC8vIHN1YnNjcmlwdGlvbiBldmVudCB0aGF0IGNvdWxkIGNvbnRhaW4gZmlsdGVyIGJhc2VkIG9uIGV4aXN0aW5nIHN1YnNjcmlwdGlvblxuICAgICAgICAgIHNlcnZpY2VLZXkgPSBtYXBwaW5nW3N1YnNjcmlwdGlvbkFybl07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgLy8gY2F0Y2ggYWxsIHN1YnNjcmlwdGlvblxuICAgICAgICAgIGNvbnN0IHRvcGljQXJuID0gcmVjb3JkLlNucy5Ub3BpY0FybjtcbiAgICAgICAgICBzZXJ2aWNlS2V5ID0gbWFwcGluZ1t0b3BpY0Fybl07XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgbWVzc2FnZTogc3RyaW5nO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2UocmVjb3JkLlNucy5NZXNzYWdlKTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgbWVzc2FnZSA9IHJlY29yZC5TbnMuTWVzc2FnZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHNweUV2ZW50VHlwZSA9IHRoaXMuZ2V0U3B5RXZlbnRUeXBlKHNlcnZpY2VLZXkpIGFzXG4gICAgICAgICAgfCAnRnVuY3Rpb25TbnNUb3BpYydcbiAgICAgICAgICB8ICdGdW5jdGlvblNuc1N1YnNjcmlwdGlvbic7XG5cbiAgICAgICAgY29uc3QgZGF0YTogU25zVG9waWNTcHlFdmVudCB8IFNuc1N1YnNjcmlwdGlvblNweUV2ZW50ID0ge1xuICAgICAgICAgIHNweUV2ZW50VHlwZSxcbiAgICAgICAgICBtZXNzYWdlLFxuICAgICAgICAgIHN1YmplY3Q6IHJlY29yZC5TbnMuU3ViamVjdCxcbiAgICAgICAgICB0aW1lc3RhbXA6IHJlY29yZC5TbnMuVGltZXN0YW1wLFxuICAgICAgICAgIHRvcGljQXJuOiByZWNvcmQuU25zLlRvcGljQXJuLFxuICAgICAgICAgIG1lc3NhZ2VJZDogcmVjb3JkLlNucy5NZXNzYWdlSWQsXG4gICAgICAgICAgbWVzc2FnZUF0dHJpYnV0ZXM6IHJlY29yZC5TbnMuTWVzc2FnZUF0dHJpYnV0ZXMsXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0ge1xuICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgc2VydmljZUtleSxcbiAgICAgICAgfTtcbiAgICAgICAgcG9zdERhdGFQcm9taXNlcy5wdXNoKHRoaXMucG9zdERhdGEoZmx1ZW50RXZlbnQpKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGV2ZW50Py5SZWNvcmRzICYmIGV2ZW50LlJlY29yZHNbMF0/LmV2ZW50U291cmNlID09PSAnYXdzOnNxcycpIHtcbiAgICAgIC8vY29uc29sZS5sb2coJyoqKiBTUVMgKioqJyk7XG4gICAgICBjb25zdCBldmVudFNxcyA9IGV2ZW50IGFzIFNRU0V2ZW50O1xuICAgICAgZm9yIChjb25zdCByZWNvcmQgb2YgZXZlbnRTcXMuUmVjb3Jkcykge1xuICAgICAgICBjb25zdCBzdWJzY3JpcHRpb25Bcm4gPSByZWNvcmQuZXZlbnRTb3VyY2VBUk47XG5cbiAgICAgICAgY29uc3Qgc2VydmljZUtleSA9IG1hcHBpbmdbc3Vic2NyaXB0aW9uQXJuXTtcbiAgICAgICAgbGV0IGJvZHk6IHN0cmluZztcblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGJvZHkgPSBKU09OLnBhcnNlKHJlY29yZC5ib2R5KTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgYm9keSA9IHJlY29yZC5ib2R5O1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZGF0YTogU3FzU3B5RXZlbnQgPSB7XG4gICAgICAgICAgc3B5RXZlbnRUeXBlOiAnU3FzJyxcbiAgICAgICAgICBib2R5LFxuICAgICAgICAgIG1lc3NhZ2VBdHRyaWJ1dGVzOiByZWNvcmQubWVzc2FnZUF0dHJpYnV0ZXMsXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0ge1xuICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgc2VydmljZUtleSxcbiAgICAgICAgfTtcbiAgICAgICAgcG9zdERhdGFQcm9taXNlcy5wdXNoKHRoaXMucG9zdERhdGEoZmx1ZW50RXZlbnQpKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGV2ZW50Py5SZWNvcmRzICYmIGV2ZW50LlJlY29yZHNbMF0/LnMzKSB7XG4gICAgICAvL2NvbnNvbGUubG9nKCcqKiogUzMgKioqJyk7XG4gICAgICBjb25zdCBldmVudFMzID0gZXZlbnQgYXMgUzNFdmVudDtcbiAgICAgIGZvciAoY29uc3QgcmVjb3JkIG9mIGV2ZW50UzMuUmVjb3Jkcykge1xuICAgICAgICBjb25zdCBidWNrZXRBcm4gPSByZWNvcmQuczMuYnVja2V0LmFybjtcblxuICAgICAgICBjb25zdCBkYXRhOiBTM1NweUV2ZW50ID0ge1xuICAgICAgICAgIHNweUV2ZW50VHlwZTogJ1MzJyxcbiAgICAgICAgICBldmVudE5hbWU6IHJlY29yZC5ldmVudE5hbWUsXG4gICAgICAgICAgZXZlbnRUaW1lOiByZWNvcmQuZXZlbnRUaW1lLFxuICAgICAgICAgIGJ1Y2tldDogcmVjb3JkLnMzLmJ1Y2tldC5uYW1lLFxuICAgICAgICAgIGtleTogcmVjb3JkLnMzLm9iamVjdC5rZXksXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0ge1xuICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgc2VydmljZUtleTogbWFwcGluZ1tidWNrZXRBcm5dLFxuICAgICAgICB9O1xuICAgICAgICBwb3N0RGF0YVByb21pc2VzLnB1c2godGhpcy5wb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZXZlbnQuUmVjb3JkcyAmJiBldmVudC5SZWNvcmRzWzBdPy5keW5hbW9kYikge1xuICAgICAgLy9jb25zb2xlLmxvZygnKioqIERZTkFNT0RCICoqKicpO1xuICAgICAgY29uc3QgZXZlbnREeW5hbW9EQiA9IGV2ZW50IGFzIER5bmFtb0RCU3RyZWFtRXZlbnQ7XG4gICAgICBmb3IgKGNvbnN0IHJlY29yZCBvZiBldmVudER5bmFtb0RCLlJlY29yZHMpIHtcbiAgICAgICAgbGV0IGFybiA9IHJlY29yZC5ldmVudFNvdXJjZUFSTiE7XG4gICAgICAgIGFybiA9IGFybi5zdWJzdHJpbmcoMCwgYXJuLmluZGV4T2YoJy9zdHJlYW0vJykpO1xuXG4gICAgICAgIGNvbnN0IGRhdGE6IER5bmFtb0RCU3B5RXZlbnQgPSB7XG4gICAgICAgICAgc3B5RXZlbnRUeXBlOiAnRHluYW1vREInLFxuICAgICAgICAgIGV2ZW50TmFtZTogcmVjb3JkLmV2ZW50TmFtZSxcbiAgICAgICAgICBuZXdJbWFnZTogcmVjb3JkLmR5bmFtb2RiPy5OZXdJbWFnZVxuICAgICAgICAgICAgPyB1bm1hcnNoYWxsKHJlY29yZC5keW5hbW9kYj8uTmV3SW1hZ2UgYXMgYW55KVxuICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAga2V5czogdW5tYXJzaGFsbChyZWNvcmQuZHluYW1vZGI/LktleXMgYXMgYW55KSxcbiAgICAgICAgICBvbGRJbWFnZTogcmVjb3JkLmR5bmFtb2RiPy5PbGRJbWFnZVxuICAgICAgICAgICAgPyB1bm1hcnNoYWxsKHJlY29yZC5keW5hbW9kYj8uT2xkSW1hZ2UgYXMgYW55KVxuICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgIH07XG5cbiAgICAgICAgY29uc3QgZmx1ZW50RXZlbnQ6IE9taXQ8U3B5TWVzc2FnZSwgJ3RpbWVzdGFtcCc+ID0ge1xuICAgICAgICAgIGRhdGEsXG4gICAgICAgICAgc2VydmljZUtleTogbWFwcGluZ1thcm5dLFxuICAgICAgICB9O1xuICAgICAgICBwb3N0RGF0YVByb21pc2VzLnB1c2godGhpcy5wb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoXG4gICAgICBldmVudC5kZXRhaWwgJiZcbiAgICAgIGV2ZW50WydkZXRhaWwtdHlwZSddICYmXG4gICAgICBldmVudC52ZXJzaW9uICYmXG4gICAgICBldmVudC5zb3VyY2VcbiAgICApIHtcbiAgICAgIC8vY29uc29sZS5sb2coJyoqKiBFdmVudEJyaWRnZSAqKionKTtcbiAgICAgIGNvbnN0IGV2ZW50RWIgPSBldmVudCBhcyBFdmVudEJyaWRnZUV2ZW50PGFueSwgYW55PjtcblxuICAgICAgY29uc3Qgc2VydmljZUtleSA9IG1hcHBpbmcuZXZlbnRCcmlkZ2U7IC8vIHRoZSBpcyBuZXcgbGFtYmRhIGZvciBlYWNoIHN1YnNjcmlwdGlvblxuXG4gICAgICBjb25zdCBzcHlFdmVudFR5cGUgPSB0aGlzLmdldFNweUV2ZW50VHlwZShzZXJ2aWNlS2V5KSBhc1xuICAgICAgICB8ICdFdmVudEJyaWRnZSdcbiAgICAgICAgfCAnRXZlbnRCcmlkZ2VSdWxlJztcblxuICAgICAgY29uc3QgbWVzc2FnZSA9IGV2ZW50RWIuZGV0YWlsO1xuXG4gICAgICBjb25zdCBkYXRhOiBFdmVudEJyaWRnZVNweUV2ZW50IHwgRXZlbnRCcmlkZ2VSdWxlU3B5RXZlbnQgPSB7XG4gICAgICAgIHNweUV2ZW50VHlwZSxcbiAgICAgICAgZGV0YWlsOiBtZXNzYWdlLFxuICAgICAgICBkZXRhaWxUeXBlOiBldmVudEViWydkZXRhaWwtdHlwZSddLFxuICAgICAgICBldmVudEJyaWRnZUlkOiBldmVudEViWydpZCddLFxuICAgICAgICBzb3VyY2U6IGV2ZW50RWIuc291cmNlLFxuICAgICAgICB0aW1lOiBldmVudEViLnRpbWUsXG4gICAgICAgIGFjY291bnQ6IGV2ZW50RWIuYWNjb3VudCxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGZsdWVudEV2ZW50OiBPbWl0PFNweU1lc3NhZ2UsICd0aW1lc3RhbXAnPiA9IHtcbiAgICAgICAgZGF0YSxcbiAgICAgICAgc2VydmljZUtleSxcbiAgICAgIH07XG4gICAgICBwb3N0RGF0YVByb21pc2VzLnB1c2godGhpcy5wb3N0RGF0YShmbHVlbnRFdmVudCkpO1xuICAgIH0gZWxzZSB7XG4gICAgICAvL2NvbnNvbGUubG9nKCcqKiogT1RIRVIgKioqJyk7XG4gICAgICBjb25zdCBmbHVlbnRFdmVudDogT21pdDxTcHlNZXNzYWdlLCAndGltZXN0YW1wJz4gPSBldmVudDtcbiAgICAgIHBvc3REYXRhUHJvbWlzZXMucHVzaCh0aGlzLnBvc3REYXRhKGZsdWVudEV2ZW50KSk7XG4gICAgfVxuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwocG9zdERhdGFQcm9taXNlcyk7XG4gIH1cblxuICBwcml2YXRlIGVuY29kZShpbnB1dDogYW55KTogZnJhZ21lbnRbXSB7XG4gICAgY29uc3QgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KGlucHV0KTtcbiAgICBjb25zdCBwYXJ0cyA9IHBheWxvYWQubWF0Y2goLy57MSw1MDAwMH0vZyk7XG4gICAgaWYgKCFwYXJ0cykgcmV0dXJuIFtdO1xuICAgIHRoaXMubG9nKGBFbmNvZGVkIGlvdCBtZXNzYWdlLCAke3BhcnRzLmxlbmd0aH1gKTtcbiAgICBjb25zdCBpZCA9IHY0KCk7XG4gICAgcmV0dXJuIHBhcnRzLm1hcCgocGFydCwgaW5kZXgpID0+ICh7XG4gICAgICBpZCxcbiAgICAgIGluZGV4LFxuICAgICAgY291bnQ6IHBhcnRzLmxlbmd0aCxcbiAgICAgIGRhdGE6IHBhcnQsXG4gICAgfSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBwb3N0RGF0YShcbiAgICBzcHlNZXNzYWdlOiBPbWl0PFNweU1lc3NhZ2UsICd0aW1lc3RhbXAnPiAmIHsgdGltZXN0YW1wPzogc3RyaW5nIH1cbiAgKSB7XG4gICAgaWYgKHRoaXMuY29ubmVjdGlvbiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICdObyBJb1QgY29ubmVjdGlvbiBjcmVhdGVkIHlldCwgZGlkIHlvdSBmb3JnZXQgdG8gY2FsbCBjb25uZWN0KCk/J1xuICAgICAgKTtcbiAgICB9XG5cbiAgICBjb25zdCB3aXRoVGltZVN0YW1wID0ge1xuICAgICAgLi4uc3B5TWVzc2FnZSxcbiAgICAgIHRpbWVzdGFtcDogc3B5TWVzc2FnZS50aW1lc3RhbXAgfHwgbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgIH07XG5cbiAgICB0aGlzLmxvZygnUG9zdCBzcHkgbWVzc2FnZScsIEpTT04uc3RyaW5naWZ5KHdpdGhUaW1lU3RhbXApKTtcblxuICAgIGNvbnN0IGNvbm5lY3Rpb24gPSB0aGlzLmNvbm5lY3Rpb247XG4gICAgY29uc3QgdG9waWMgPSBnZXRUb3BpYyh0aGlzLnNjb3BlKTtcblxuICAgIHRyeSB7XG4gICAgICBmb3IgKGNvbnN0IGZyYWdtZW50IG9mIHRoaXMuZW5jb2RlKHdpdGhUaW1lU3RhbXApKSB7XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlKSA9PiB7XG4gICAgICAgICAgY29ubmVjdGlvbi5wdWJsaXNoKFxuICAgICAgICAgICAgdG9waWMsXG4gICAgICAgICAgICBKU09OLnN0cmluZ2lmeShmcmFnbWVudCksXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHFvczogMSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgICAgIHRoaXMubG9nKCdQdWJsaXNoaW5nIGZpbmlzaGVkJyk7XG4gICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5sb2coXG4gICAgICAgICAgYFB1Ymxpc2hlZCBmcmFnbWVudCAke2ZyYWdtZW50LmluZGV4fSBvdXQgb2YgJHtmcmFnbWVudC5jb3VudH0gdG8gdG9waWMgJHt0b3BpY31gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgdGhpcy5sb2dFcnJvcihgRmFpbGVkIHRvIHNlbmQgcGF5bG9hZCB0byBpb3Q6ICR7ZX1gKTtcbiAgICB9XG5cbiAgICB0aGlzLmxvZygnU2VuZCBzcHkgbWVzc2FnZSBmaW5pc2gnKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0U3B5RXZlbnRUeXBlKHNlcnZpY2VLZXk6IHN0cmluZykge1xuICAgIGlmICghc2VydmljZUtleSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHNlcnZpY2VLZXknKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VydmljZUtleS5zdWJzdHJpbmcoMCwgc2VydmljZUtleS5pbmRleE9mKCcjJykpO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2cobWVzc2FnZTogc3RyaW5nLCAuLi5vcHRpb25hbFBhcmFtczogYW55W10pIHtcbiAgICBpZiAodGhpcy5kZWJ1Z01vZGUpIHtcbiAgICAgIGNvbnNvbGUuZGVidWcoJ1NTUFkgRVhURU5TSU9OJywgbWVzc2FnZSwgLi4ub3B0aW9uYWxQYXJhbXMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgbG9nRXJyb3IobWVzc2FnZTogc3RyaW5nLCAuLi5vcHRpb25hbFBhcmFtczogYW55W10pIHtcbiAgICBpZiAodGhpcy5kZWJ1Z01vZGUpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoJ1NTUFkgRVhURU5TSU9OJywgbWVzc2FnZSwgLi4ub3B0aW9uYWxQYXJhbXMpO1xuICAgIH1cbiAgfVxufVxuIl19