raindancers-network
Version:
Extensions to the ec2.Vpc Constructs
260 lines • 37.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SuricataRuleGroup = exports.PrefixList = exports.IPAddressFamily = exports.FQDNStatefulRule = exports.Direction = exports.FWProtocol = exports.StatefulAction = void 0;
const path = require("path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const cdk = require("aws-cdk-lib");
const constructs = require("constructs");
const resourceGroups_1 = require("./resourceGroups");
var StatefulAction;
(function (StatefulAction) {
/**
* Traffic will pass
*/
StatefulAction["PASS"] = "pass";
/**
* Traffic will be droped silently. Note, When will cause a timeout for TCP, Consider using REJECT
*/
StatefulAction["DROP"] = "drop";
/**
* Traffic will be dropped, and a TCP reset sent to the source
*/
StatefulAction["REJECT"] = "reject";
/**
* Raises an alert according to the firewalls logging/alert
*/
StatefulAction["ALERT"] = "alert";
})(StatefulAction = exports.StatefulAction || (exports.StatefulAction = {}));
var FWProtocol;
(function (FWProtocol) {
FWProtocol["TCP"] = "tcp";
FWProtocol["UPD"] = "udp";
FWProtocol["ICMP"] = "icmp";
FWProtocol["IP"] = "ip";
FWProtocol["HTTP"] = "http";
FWProtocol["TLS"] = "tls";
})(FWProtocol = exports.FWProtocol || (exports.FWProtocol = {}));
var Direction;
(function (Direction) {
/**
* Traffic allowed from Src to destination only
*/
Direction["OUTBOUND"] = "->";
/**
* Traffic allowed in both directions
*/
Direction["BOTH"] = "<>";
})(Direction = exports.Direction || (exports.Direction = {}));
class FQDNStatefulRule extends constructs.Construct {
constructor(scope, id, props) {
super(scope, id);
this.prefixListSet = [];
this.resourceGroupSets = [];
if (!([FWProtocol.HTTP, FWProtocol.TLS].includes(props.protocol))) {
throw new Error('The protocol for FQDN Rules must be HTTP or TLS');
}
let priority = 1;
if (props.priority) {
priority = props.priority;
}
let matchingMessage = 'matching denyed FQDNs';
if (props.action == StatefulAction.PASS) {
matchingMessage = 'matching allowed FQDNs';
}
var options = '';
if (props.protocol === FWProtocol.HTTP) {
options = `(http.host; content:"${props.fqdn}"; startswith; endswith; msg:"${matchingMessage}"; priority:${priority}; flow:to_server, established;`; //sid:${getSid()}; rev:1;)`
}
if (props.protocol === FWProtocol.TLS) {
options = `(tls.sni; content:"${props.fqdn}"; startswith; endswith; msg:"${matchingMessage}"; priority:${priority}; flow:to_server, established;`; //sid:${getSid()}; rev:1;)`
}
let source = '';
if (props.source instanceof PrefixList) {
source = '@' + props.source.prefixlist.prefixListName;
this.prefixListSet.push(props.source.prefixListSet);
}
else if (props.source instanceof resourceGroups_1.DynamicTagResourceGroup) {
source = '@' + props.source.name;
this.resourceGroupSets.push({ name: props.source.name, arn: props.source.groupArn });
}
else {
source = props.source;
}
let destination = '';
if (props.destination instanceof PrefixList) {
destination = '@' + props.destination.prefixlist.prefixListName;
this.prefixListSet.push(props.destination.prefixListSet);
}
else if (props.destination instanceof resourceGroups_1.DynamicTagResourceGroup) {
source = '@' + props.destination;
this.resourceGroupSets.push({ name: props.destination.name, arn: props.destination.groupArn });
}
else {
destination = props.destination;
}
var rule = ''.concat(props.action, ' ', //drop
props.protocol, ' ', // protocol
source, ' ', // @example
props.srcPort, ' ', // any
props.direction, ' ', // ->
destination, ' ', // $EXTERNAL_NET
props.destPort, ' ', // any
options);
const suricataRule = new cdk.CustomResource(this, `${id}customresource`, {
serviceToken: props.rulesDatabase?.crudServiceToken,
properties: {
Rule: rule,
},
});
this.uuid = suricataRule.getAttString('UUID');
}
}
exports.FQDNStatefulRule = FQDNStatefulRule;
var IPAddressFamily;
(function (IPAddressFamily) {
IPAddressFamily["IPV4"] = "IPv4";
IPAddressFamily["IPV6"] = "IPv6";
})(IPAddressFamily = exports.IPAddressFamily || (exports.IPAddressFamily = {}));
class PrefixList extends constructs.Construct {
constructor(scope, id, props) {
super(scope, id);
this.entries = [];
this.prefixlist = new aws_cdk_lib_1.aws_ec2.CfnPrefixList(this, `prefix-list${id}`, {
addressFamily: props.addressFamily,
prefixListName: props.prefixListName,
maxEntries: props.maxEntries,
entries: this.entries,
});
this.prefixlistArn = this.prefixlist.attrArn;
this.prefixListSet = { arn: this.prefixlist.attrArn, name: props.prefixListName };
}
addEC2Instance(props) {
this.entries.push({
cidr: props.instancePrivateIp + '/32',
description: props.instancePrivateDnsName,
});
}
}
exports.PrefixList = PrefixList;
class SuricataRuleGroup extends constructs.Construct {
constructor(scope, id, props) {
super(scope, id);
this.ruleGroupArn = '';
this.ruleReferenceSets = [];
this.ruleuuidlist = [];
this.rulesDatabase = props.networkFirewallEngine.rulesDatabase;
const suricataRuleGroupLambda = new aws_cdk_lib_1.aws_lambda.Function(this, 'fqdnLambda', {
timeout: cdk.Duration.seconds(300),
runtime: aws_cdk_lib_1.aws_lambda.Runtime.PYTHON_3_9,
handler: 'suricata_rule.on_event',
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(__dirname, '../../lambda/firewall'), {
bundling: {
image: aws_cdk_lib_1.aws_lambda.Runtime.PYTHON_3_9.bundlingImage,
command: [
'bash', '-c',
'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output',
],
},
}),
environment: {
TableName: props.networkFirewallEngine.rulesDatabase.policyTable.tableName,
},
});
this.crLambda = suricataRuleGroupLambda;
suricataRuleGroupLambda.addToRolePolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
resources: ['*'],
actions: [
'network-firewall:DescribeRuleGroup',
'network-firewall:DeleteRuleGroup',
'network-firewall:CreateRuleGroup',
'network-firewall:UpdateRuleGroup',
'iam:CreateServiceLinkedRole',
'ec2:GetManagedPrefixListEntries',
'resource-groups:Get*',
'resource-groups:List*',
],
}));
props.networkFirewallEngine.rulesDatabase.policyTable.grantReadData(suricataRuleGroupLambda);
// this is not permitted by default in 'read?'
suricataRuleGroupLambda.addToRolePolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
resources: [props.networkFirewallEngine.rulesDatabase.policyTable.tableArn],
actions: [
'dynamodb:PartiQLSelect',
],
}));
const suricataRuleCr = new cdk.CustomResource(this, `${props.ruleGroupName}customresource`, {
serviceToken: new aws_cdk_lib_1.custom_resources.Provider(this, `${props.ruleGroupName}serviceprovider`, {
onEventHandler: this.crLambda,
}).serviceToken,
properties: {
Capacity: props.capacity,
RuleGroupName: props.ruleGroupName,
Description: props.description,
Rules: this.ruleuuidlist,
ReferenceSets: this.ruleReferenceSets,
},
});
this.ruleGroupArn = suricataRuleCr.getAttString('RuleGroupArn');
new aws_cdk_lib_1.aws_ram.CfnResourceShare(this, 'shareRuleGroup', {
name: props.ruleGroupName,
allowExternalPrincipals: false,
principals: [props.networkFirewallEngine.firewallAccount],
resourceArns: [this.ruleGroupArn],
});
}
addRule(props) {
let priority = 1;
if (props.priority) {
priority = props.priority;
}
let rulesDatabase = this.rulesDatabase;
// create a new rule, and insert it in the table.
const ruleToAdd = new FQDNStatefulRule(this, props.name + 'FQDNRule', {
name: props.name,
action: props.action,
protocol: props.protocol,
source: props.source,
destination: props.destination,
srcPort: props.srcPort,
destPort: props.destPort,
direction: props.direction,
fqdn: props.fqdn,
priority: priority,
rulesDatabase: rulesDatabase,
});
this.ruleuuidlist.push(ruleToAdd.uuid);
// add prefixlists to the RulereferenceSets
ruleToAdd.prefixListSet.forEach((plset) => {
// need to check if adding this to to the ruleprefix list is bad.
const checklist = this.ruleReferenceSets;
checklist.push(plset);
const errorCheck = checkForDuplicateNamedPL(checklist); // this will raise an error if there is one
if (errorCheck.length > this.ruleReferenceSets.length) { // we had a new unique one, so we can add it
this.ruleReferenceSets.push(plset);
}
});
// add TagGroups: TODO. THis needs some validation.
ruleToAdd.resourceGroupSets.forEach((resourceGroup) => {
this.ruleReferenceSets.push(resourceGroup);
});
}
}
exports.SuricataRuleGroup = SuricataRuleGroup;
function checkForDuplicateNamedPL(prefixlistSet) {
const unique = [...new Set(prefixlistSet.map(item => item.name))];
unique.forEach((setname) => {
const filtered = prefixlistSet.filter((obj) => {
return obj.name === setname;
});
if (filtered.length > 1) {
const uniqueArn = [...new Set(filtered.map(item => item.arn))];
if (uniqueArn.length > 1) {
throw Error(`Reference Set names must be unique. Set name ${setname} has been used more than once`);
}
}
});
return [...new Map(prefixlistSet.map((item) => [item.arn, item])).values()];
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VyaWNhdGFSdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL253ZmlyZXdhbGwvc3VyaWNhdGFSdWxlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDZCQUE2QjtBQUM3Qiw2Q0FPcUI7QUFDckIsbUNBQW1DO0FBQ25DLHlDQUF5QztBQUN6QyxxREFBdUY7QUFFdkYsSUFBWSxjQWlCWDtBQWpCRCxXQUFZLGNBQWM7SUFDeEI7O09BRUc7SUFDSCwrQkFBYSxDQUFBO0lBQ2I7O09BRUc7SUFDSCwrQkFBYSxDQUFBO0lBQ2I7O09BRUc7SUFDSCxtQ0FBaUIsQ0FBQTtJQUNqQjs7T0FFRztJQUNILGlDQUFlLENBQUE7QUFDakIsQ0FBQyxFQWpCVyxjQUFjLEdBQWQsc0JBQWMsS0FBZCxzQkFBYyxRQWlCekI7QUFFRCxJQUFZLFVBT1g7QUFQRCxXQUFZLFVBQVU7SUFDcEIseUJBQVcsQ0FBQTtJQUNYLHlCQUFXLENBQUE7SUFDWCwyQkFBYSxDQUFBO0lBQ2IsdUJBQVMsQ0FBQTtJQUNULDJCQUFhLENBQUE7SUFDYix5QkFBVyxDQUFBO0FBQ2IsQ0FBQyxFQVBXLFVBQVUsR0FBVixrQkFBVSxLQUFWLGtCQUFVLFFBT3JCO0FBRUQsSUFBWSxTQVNYO0FBVEQsV0FBWSxTQUFTO0lBQ25COztPQUVHO0lBQ0gsNEJBQWUsQ0FBQTtJQUNmOztPQUVHO0lBQ0gsd0JBQVcsQ0FBQTtBQUNiLENBQUMsRUFUVyxTQUFTLEdBQVQsaUJBQVMsS0FBVCxpQkFBUyxRQVNwQjtBQW9DRCxNQUFhLGdCQUFpQixTQUFRLFVBQVUsQ0FBQyxTQUFTO0lBT3hELFlBQVksS0FBMkIsRUFBRSxFQUFVLEVBQUUsS0FBNEI7UUFDL0UsS0FBSyxDQUFFLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUxiLGtCQUFhLEdBQW9CLEVBQUUsQ0FBQztRQUNwQyxzQkFBaUIsR0FBaUMsRUFBRSxDQUFDO1FBTTFELElBQUksQ0FBQyxDQUFDLENBQUMsVUFB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aCc7XG5pbXBvcnQge1xuICBjdXN0b21fcmVzb3VyY2VzIGFzIGNyLFxuICBhd3NfbGFtYmRhLFxuICBhd3NfaWFtIGFzIGlhbSxcbiAgYXdzX2VjMiBhcyBlYzIsXG4gIGF3c19yYW0gYXMgcmFtLFxufVxuICBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgY29uc3RydWN0cyBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IER5bmFtaWNUYWdSZXNvdXJjZUdyb3VwLCBEeW5hbWljVGFnUmVzb3VyY2VHcm91cFNldCB9IGZyb20gJy4vcmVzb3VyY2VHcm91cHMnO1xuaW1wb3J0IHsgU3RhdGVmdWxSdWxlRGF0YWJhc2UgfSBmcm9tICcuL3N0YXRlZnVsZGF0YWJhc2UnO1xuZXhwb3J0IGVudW0gU3RhdGVmdWxBY3Rpb24ge1xuICAvKipcbiAgICogVHJhZmZpYyB3aWxsIHBhc3NcbiAgICovXG4gIFBBU1MgPSAncGFzcycsXG4gIC8qKlxuICAgKiBUcmFmZmljIHdpbGwgYmUgZHJvcGVkIHNpbGVudGx5LiBOb3RlLCBXaGVuIHdpbGwgY2F1c2UgYSB0aW1lb3V0IGZvciBUQ1AsIENvbnNpZGVyIHVzaW5nIFJFSkVDVFxuICAgKi9cbiAgRFJPUCA9ICdkcm9wJyxcbiAgLyoqXG4gICAqIFRyYWZmaWMgd2lsbCBiZSBkcm9wcGVkLCBhbmQgYSBUQ1AgcmVzZXQgc2VudCB0byB0aGUgc291cmNlXG4gICAqL1xuICBSRUpFQ1QgPSAncmVqZWN0JyxcbiAgLyoqXG4gICAqIFJhaXNlcyBhbiBhbGVydCBhY2NvcmRpbmcgdG8gdGhlIGZpcmV3YWxscyBsb2dnaW5nL2FsZXJ0XG4gICAqL1xuICBBTEVSVCA9ICdhbGVydCcsXG59XG5cbmV4cG9ydCBlbnVtIEZXUHJvdG9jb2wge1xuICBUQ1AgPSAndGNwJyxcbiAgVVBEID0gJ3VkcCcsXG4gIElDTVAgPSAnaWNtcCcsXG4gIElQID0gJ2lwJyxcbiAgSFRUUCA9ICdodHRwJyxcbiAgVExTID0gJ3Rscydcbn1cblxuZXhwb3J0IGVudW0gRGlyZWN0aW9uIHtcbiAgLyoqXG4gICAqIFRyYWZmaWMgYWxsb3dlZCBmcm9tIFNyYyB0byBkZXN0aW5hdGlvbiBvbmx5XG4gICAqL1xuICBPVVRCT1VORCA9ICctPicsXG4gIC8qKlxuICAgKiBUcmFmZmljIGFsbG93ZWQgaW4gYm90aCBkaXJlY3Rpb25zXG4gICAqL1xuICBCT1RIID0gJzw+J1xufVxuXG5leHBvcnQgdHlwZSBTcmNEc3RBZGRyID0gc3RyaW5nIHwgUHJlZml4TGlzdCB8IER5bmFtaWNUYWdSZXNvdXJjZUdyb3VwO1xuZXhwb3J0IHR5cGUgU3JjRHN0UG9ydCA9IHN0cmluZztcblxuXG5leHBvcnQgaW50ZXJmYWNlIFN1cmljYXRhUnVsZVByb3Bze1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGFjdGlvbjogU3RhdGVmdWxBY3Rpb247XG4gIHJlYWRvbmx5IHByb3RvY29sOiBGV1Byb3RvY29sO1xuICByZWFkb25seSBzb3VyY2U6IFNyY0RzdEFkZHI7XG4gIHJlYWRvbmx5IGRlc3RpbmF0aW9uOiBTcmNEc3RBZGRyO1xuICByZWFkb25seSBzcmNQb3J0OiBTcmNEc3RQb3J0O1xuICByZWFkb25seSBkZXN0UG9ydDogU3JjRHN0UG9ydDtcbiAgcmVhZG9ubHkgZGlyZWN0aW9uOiBEaXJlY3Rpb247XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRlFETlN0YXRlZnVsUnVsZVByb3BzIGV4dGVuZHMgU3VyaWNhdGFSdWxlUHJvcHMge1xuICByZWFkb25seSBmcWRuOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHByaW9yaXR5PzogbnVtYmVyIHwgdW5kZWZpbmVkO1xuICByZWFkb25seSBydWxlc0RhdGFiYXNlPzogU3RhdGVmdWxSdWxlRGF0YWJhc2UgfCB1bmRlZmluZWQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJlZml4TGlzdFNldEludGVyZmFjZSB7XG4gIHJlYWRvbmx5IGFybjogc3RyaW5nO1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVmZXJlbmNlU2V0IHtcbiAgcmVhZG9ubHkgYXJuOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcbn1cblxudHlwZSBQcmVmaXhMaXN0U2V0ID0gUHJlZml4TGlzdFNldEludGVyZmFjZVxuXG5cbmV4cG9ydCBjbGFzcyBGUUROU3RhdGVmdWxSdWxlIGV4dGVuZHMgY29uc3RydWN0cy5Db25zdHJ1Y3Qge1xuXG4gIHB1YmxpYyB1dWlkOiBzdHJpbmc7XG4gIHB1YmxpYyBwcmVmaXhMaXN0U2V0OiBQcmVmaXhMaXN0U2V0W10gPSBbXTtcbiAgcHVibGljIHJlc291cmNlR3JvdXBTZXRzOiBEeW5hbWljVGFnUmVzb3VyY2VHcm91cFNldFtdID0gW107XG5cblxuICBjb25zdHJ1Y3RvcihzY29wZTogY29uc3RydWN0cy5Db25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBGUUROU3RhdGVmdWxSdWxlUHJvcHMpIHtcbiAgICBzdXBlciggc2NvcGUsIGlkKTtcblxuICAgIGlmICghKFtGV1Byb3RvY29sLkhUVFAsIEZXUHJvdG9jb2wuVExTXS5pbmNsdWRlcyhwcm9wcy5wcm90b2NvbCkpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1RoZSBwcm90b2NvbCBmb3IgRlFETiBSdWxlcyBtdXN0IGJlIEhUVFAgb3IgVExTJyk7XG4gICAgfVxuXG4gICAgbGV0IHByaW9yaXR5ID0gMTtcbiAgICBpZiAocHJvcHMucHJpb3JpdHkpIHtcbiAgICAgIHByaW9yaXR5ID0gcHJvcHMucHJpb3JpdHk7XG4gICAgfVxuICAgIGxldCBtYXRjaGluZ01lc3NhZ2UgPSAnbWF0Y2hpbmcgZGVueWVkIEZRRE5zJztcbiAgICBpZiAocHJvcHMuYWN0aW9uID09IFN0YXRlZnVsQWN0aW9uLlBBU1MpIHtcbiAgICAgIG1hdGNoaW5nTWVzc2FnZSA9ICdtYXRjaGluZyBhbGxvd2VkIEZRRE5zJztcbiAgICB9XG5cbiAgICB2YXIgb3B0aW9uczogc3RyaW5nID0gJyc7XG4gICAgaWYgKHByb3BzLnByb3RvY29sID09PSBGV1Byb3RvY29sLkhUVFApIHtcbiAgICAgIG9wdGlvbnMgPSBgKGh0dHAuaG9zdDsgY29udGVudDpcIiR7cHJvcHMuZnFkbn1cIjsgc3RhcnRzd2l0aDsgZW5kc3dpdGg7IG1zZzpcIiR7bWF0Y2hpbmdNZXNzYWdlfVwiOyBwcmlvcml0eToke3ByaW9yaXR5fTsgZmxvdzp0b19zZXJ2ZXIsIGVzdGFibGlzaGVkO2A7IC8vc2lkOiR7Z2V0U2lkKCl9OyByZXY6MTspYFxuICAgIH1cblxuICAgIGlmIChwcm9wcy5wcm90b2NvbCA9PT0gRldQcm90b2NvbC5UTFMpIHtcbiAgICAgIG9wdGlvbnMgPSBgKHRscy5zbmk7IGNvbnRlbnQ6XCIke3Byb3BzLmZxZG59XCI7IHN0YXJ0c3dpdGg7IGVuZHN3aXRoOyBtc2c6XCIke21hdGNoaW5nTWVzc2FnZX1cIjsgcHJpb3JpdHk6JHtwcmlvcml0eX07IGZsb3c6dG9fc2VydmVyLCBlc3RhYmxpc2hlZDtgOyAvL3NpZDoke2dldFNpZCgpfTsgcmV2OjE7KWBcbiAgICB9XG5cbiAgICBsZXQgc291cmNlID0gJyc7XG5cbiAgICBpZiAocHJvcHMuc291cmNlIGluc3RhbmNlb2YgUHJlZml4TGlzdCkge1xuICAgICAgc291cmNlID0gJ0AnICsgcHJvcHMuc291cmNlLnByZWZpeGxpc3QucHJlZml4TGlzdE5hbWU7XG4gICAgICB0aGlzLnByZWZpeExpc3RTZXQucHVzaChwcm9wcy5zb3VyY2UucHJlZml4TGlzdFNldCk7XG4gICAgfSBlbHNlIGlmIChwcm9wcy5zb3VyY2UgaW5zdGFuY2VvZiBEeW5hbWljVGFnUmVzb3VyY2VHcm91cCkge1xuICAgICAgc291cmNlID0gJ0AnICsgcHJvcHMuc291cmNlLm5hbWU7XG4gICAgICB0aGlzLnJlc291cmNlR3JvdXBTZXRzLnB1c2goeyBuYW1lOiBwcm9wcy5zb3VyY2UubmFtZSwgYXJuOiBwcm9wcy5zb3VyY2UuZ3JvdXBBcm4gfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNvdXJjZSA9IHByb3BzLnNvdXJjZSBhcyBzdHJpbmc7XG4gICAgfVxuXG4gICAgbGV0IGRlc3RpbmF0aW9uID0gJyc7XG4gICAgaWYgKHByb3BzLmRlc3RpbmF0aW9uIGluc3RhbmNlb2YgUHJlZml4TGlzdCkge1xuICAgICAgZGVzdGluYXRpb24gPSAnQCcgKyBwcm9wcy5kZXN0aW5hdGlvbi5wcmVmaXhsaXN0LnByZWZpeExpc3ROYW1lO1xuICAgICAgdGhpcy5wcmVmaXhMaXN0U2V0LnB1c2gocHJvcHMuZGVzdGluYXRpb24ucHJlZml4TGlzdFNldCk7XG4gICAgfSBlbHNlIGlmIChwcm9wcy5kZXN0aW5hdGlvbiBpbnN0YW5jZW9mIER5bmFtaWNUYWdSZXNvdXJjZUdyb3VwKSB7XG4gICAgICBzb3VyY2UgPSAnQCcgKyBwcm9wcy5kZXN0aW5hdGlvbjtcbiAgICAgIHRoaXMucmVzb3VyY2VHcm91cFNldHMucHVzaCh7IG5hbWU6IHByb3BzLmRlc3RpbmF0aW9uLm5hbWUsIGFybjogcHJvcHMuZGVzdGluYXRpb24uZ3JvdXBBcm4gfSk7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgZGVzdGluYXRpb24gPSBwcm9wcy5kZXN0aW5hdGlvbiBhcyBzdHJpbmc7XG4gICAgfVxuXG4gICAgdmFyIHJ1bGUgPSAnJy5jb25jYXQoXG4gICAgICBwcm9wcy5hY3Rpb24sICcgJywgLy9kcm9wXG4gICAgICBwcm9wcy5wcm90b2NvbCwgJyAnLCAvLyBwcm90b2NvbFxuICAgICAgc291cmNlLCAnICcsIC8vIEBleGFtcGxlXG4gICAgICBwcm9wcy5zcmNQb3J0LCAnICcsIC8vIGFueVxuICAgICAgcHJvcHMuZGlyZWN0aW9uLCAnICcsIC8vIC0+XG4gICAgICBkZXN0aW5hdGlvbiwgJyAnLCAvLyAkRVhURVJOQUxfTkVUXG4gICAgICBwcm9wcy5kZXN0UG9ydCwgJyAnLCAvLyBhbnlcbiAgICAgIG9wdGlvbnMsXG4gICAgKTtcblxuICAgIGNvbnN0IHN1cmljYXRhUnVsZSA9IG5ldyBjZGsuQ3VzdG9tUmVzb3VyY2UodGhpcywgYCR7aWR9Y3VzdG9tcmVzb3VyY2VgLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IHByb3BzLnJ1bGVzRGF0YWJhc2U/LmNydWRTZXJ2aWNlVG9rZW4gYXMgc3RyaW5nLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBSdWxlOiBydWxlLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHRoaXMudXVpZCA9IHN1cmljYXRhUnVsZS5nZXRBdHRTdHJpbmcoJ1VVSUQnKTtcblxuXG4gIH1cbn1cblxuXG5leHBvcnQgZW51bSBJUEFkZHJlc3NGYW1pbHkge1xuICBJUFY0ID0gJ0lQdjQnLFxuICBJUFY2ID0gJ0lQdjYnXG59XG5cblxuZXhwb3J0IGludGVyZmFjZSBQcmVmaXhMaXN0UHJvcHMge1xuICByZWFkb25seSBhZGRyZXNzRmFtaWx5OiBJUEFkZHJlc3NGYW1pbHk7XG4gIHJlYWRvbmx5IHByZWZpeExpc3ROYW1lOiBzdHJpbmc7XG4gIHJlYWRvbmx5IG1heEVudHJpZXM6IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBQcmVmaXhMaXN0RW50cnkge1xuICByZWFkb25seSBjaWRyOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGRlc2NyaXB0aW9uOiBzdHJpbmc7XG59XG5cblxuZXhwb3J0IGNsYXNzIFByZWZpeExpc3QgZXh0ZW5kcyBjb25zdHJ1Y3RzLkNvbnN0cnVjdCB7XG5cbiAgcHVibGljIHJlYWRvbmx5IHByZWZpeGxpc3Q6IGVjMi5DZm5QcmVmaXhMaXN0O1xuICBwdWJsaWMgcmVhZG9ubHkgcHJlZml4bGlzdEFybjogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgcHJlZml4TGlzdFNldDogUHJlZml4TGlzdFNldDtcblxuICBwcml2YXRlIGVudHJpZXM6IFByZWZpeExpc3RFbnRyeVtdID0gW107XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IGNvbnN0cnVjdHMuQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogUHJlZml4TGlzdFByb3BzKSB7XG4gICAgc3VwZXIoIHNjb3BlLCBpZCk7XG5cbiAgICB0aGlzLnByZWZpeGxpc3QgPSBuZXcgZWMyLkNmblByZWZpeExpc3QodGhpcywgYHByZWZpeC1saXN0JHtpZH1gLCB7XG4gICAgICBhZGRyZXNzRmFtaWx5OiBwcm9wcy5hZGRyZXNzRmFtaWx5LFxuICAgICAgcHJlZml4TGlzdE5hbWU6IHByb3BzLnByZWZpeExpc3ROYW1lLFxuICAgICAgbWF4RW50cmllczogcHJvcHMubWF4RW50cmllcyxcbiAgICAgIGVudHJpZXM6IHRoaXMuZW50cmllcyxcbiAgICB9KTtcblxuICAgIHRoaXMucHJlZml4bGlzdEFybiA9IHRoaXMucHJlZml4bGlzdC5hdHRyQXJuO1xuICAgIHRoaXMucHJlZml4TGlzdFNldCA9IHsgYXJuOiB0aGlzLnByZWZpeGxpc3QuYXR0ckFybiwgbmFtZTogcHJvcHMucHJlZml4TGlzdE5hbWUgfTtcblxuICB9XG5cbiAgcHVibGljIGFkZEVDMkluc3RhbmNlKHByb3BzOiBlYzIuSW5zdGFuY2UpOiB2b2lkIHtcblxuICAgIHRoaXMuZW50cmllcy5wdXNoKFxuICAgICAge1xuICAgICAgICBjaWRyOiBwcm9wcy5pbnN0YW5jZVByaXZhdGVJcCArICcvMzInLFxuICAgICAgICBkZXNjcmlwdGlvbjogcHJvcHMuaW5zdGFuY2VQcml2YXRlRG5zTmFtZSxcbiAgICAgIH0sXG4gICAgKTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5XRldSdWxlc0VuZ2luZSB7XG4gIHJlYWRvbmx5IGZpcmV3YWxsQWNjb3VudDogc3RyaW5nO1xuICByZWFkb25seSBydWxlc0RhdGFiYXNlOiBTdGF0ZWZ1bFJ1bGVEYXRhYmFzZTtcbn1cblxuXG5leHBvcnQgaW50ZXJmYWNlIFN1cmljYXRhUnVsZUdyb3VwUHJvcHN7XG4gIHJlYWRvbmx5IHJ1bGVHcm91cE5hbWU6IHN0cmluZztcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIHJlYWRvbmx5IHN1cmljYXRhUnVsZXM/OiBGUUROU3RhdGVmdWxSdWxlW107IC8vIGFkZCBvaHRlciBraW5kcyBvZiBydWxlcyBpbiBoZXJlLlxuICByZWFkb25seSBjYXBhY2l0eTogbnVtYmVyO1xuICByZWFkb25seSBuZXR3b3JrRmlyZXdhbGxFbmdpbmU6IE5XRldSdWxlc0VuZ2luZTtcbiAgLy9yZWFkb25seSBydWxlc0RhdGFiYXNlOiBTdGF0ZWZ1bFJ1bGVEYXRhYmFzZTtcbn1cblxuZXhwb3J0IGNsYXNzIFN1cmljYXRhUnVsZUdyb3VwIGV4dGVuZHMgY29uc3RydWN0cy5Db25zdHJ1Y3Qge1xuXG4gIHB1YmxpYyBydWxlR3JvdXBBcm46IHN0cmluZyA9ICcnO1xuXG4gIHByaXZhdGUgcnVsZVJlZmVyZW5jZVNldHM6IFJlZmVyZW5jZVNldFtdID1bXTtcbiAgcHJpdmF0ZSBydWxldXVpZGxpc3Q6IHN0cmluZ1tdID0gW107XG4gIHByaXZhdGUgcnVsZXNEYXRhYmFzZTogU3RhdGVmdWxSdWxlRGF0YWJhc2U7XG4gIHByaXZhdGUgY3JMYW1iZGE6IGF3c19sYW1iZGEuRnVuY3Rpb247XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IGNvbnN0cnVjdHMuQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogU3VyaWNhdGFSdWxlR3JvdXBQcm9wcykge1xuICAgIHN1cGVyKCBzY29wZSwgaWQpO1xuXG4gICAgdGhpcy5ydWxlc0RhdGFiYXNlID0gcHJvcHMubmV0d29ya0ZpcmV3YWxsRW5naW5lLnJ1bGVzRGF0YWJhc2U7XG5cbiAgICBjb25zdCBzdXJpY2F0YVJ1bGVHcm91cExhbWJkYSA9IG5ldyBhd3NfbGFtYmRhLkZ1bmN0aW9uKHRoaXMsICdmcWRuTGFtYmRhJywge1xuICAgICAgdGltZW91dDogY2RrLkR1cmF0aW9uLnNlY29uZHMoMzAwKSxcbiAgICAgIHJ1bnRpbWU6IGF3c19sYW1iZGEuUnVudGltZS5QWVRIT05fM185LFxuICAgICAgaGFuZGxlcjogJ3N1cmljYXRhX3J1bGUub25fZXZlbnQnLFxuICAgICAgY29kZTogYXdzX2xhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4vLi4vbGFtYmRhL2ZpcmV3YWxsJyksIHtcbiAgICAgICAgYnVuZGxpbmc6IHtcbiAgICAgICAgICBpbWFnZTogYXdzX2xhbWJkYS5SdW50aW1lLlBZVEhPTl8zXzkuYnVuZGxpbmdJbWFnZSxcbiAgICAgICAgICBjb21tYW5kOiBbXG4gICAgICAgICAgICAnYmFzaCcsICctYycsXG4gICAgICAgICAgICAncGlwIGluc3RhbGwgLXIgcmVxdWlyZW1lbnRzLnR4dCAtdCAvYXNzZXQtb3V0cHV0ICYmIGNwIC1hdSAuIC9hc3NldC1vdXRwdXQnLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIFRhYmxlTmFtZTogcHJvcHMubmV0d29ya0ZpcmV3YWxsRW5naW5lLnJ1bGVzRGF0YWJhc2UucG9saWN5VGFibGUudGFibGVOYW1lLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIHRoaXMuY3JMYW1iZGEgPSBzdXJpY2F0YVJ1bGVHcm91cExhbWJkYTtcblxuICAgIHN1cmljYXRhUnVsZUdyb3VwTGFtYmRhLmFkZFRvUm9sZVBvbGljeShcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgJ25ldHdvcmstZmlyZXdhbGw6RGVzY3JpYmVSdWxlR3JvdXAnLFxuICAgICAgICAgICduZXR3b3JrLWZpcmV3YWxsOkRlbGV0ZVJ1bGVHcm91cCcsXG4gICAgICAgICAgJ25ldHdvcmstZmlyZXdhbGw6Q3JlYXRlUnVsZUdyb3VwJyxcbiAgICAgICAgICAnbmV0d29yay1maXJld2FsbDpVcGRhdGVSdWxlR3JvdXAnLFxuICAgICAgICAgICdpYW06Q3JlYXRlU2VydmljZUxpbmtlZFJvbGUnLFxuICAgICAgICAgICdlYzI6R2V0TWFuYWdlZFByZWZpeExpc3RFbnRyaWVzJyxcbiAgICAgICAgICAncmVzb3VyY2UtZ3JvdXBzOkdldConLFxuICAgICAgICAgICdyZXNvdXJjZS1ncm91cHM6TGlzdConLFxuICAgICAgICBdLFxuICAgICAgfSksXG4gICAgKTtcblxuXG4gICAgcHJvcHMubmV0d29ya0ZpcmV3YWxsRW5naW5lLnJ1bGVzRGF0YWJhc2UucG9saWN5VGFibGUuZ3JhbnRSZWFkRGF0YShzdXJpY2F0YVJ1bGVHcm91cExhbWJkYSk7XG5cbiAgICAvLyB0aGlzIGlzIG5vdCBwZXJtaXR0ZWQgYnkgZGVmYXVsdCBpbiAncmVhZD8nXG4gICAgc3VyaWNhdGFSdWxlR3JvdXBMYW1iZGEuYWRkVG9Sb2xlUG9saWN5KFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIHJlc291cmNlczogW3Byb3BzLm5ldHdvcmtGaXJld2FsbEVuZ2luZS5ydWxlc0RhdGFiYXNlLnBvbGljeVRhYmxlLnRhYmxlQXJuXSxcbiAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICdkeW5hbW9kYjpQYXJ0aVFMU2VsZWN0JyxcbiAgICAgICAgXSxcbiAgICAgIH0pLFxuICAgICk7XG5cblxuICAgIGNvbnN0IHN1cmljYXRhUnVsZUNyID0gbmV3IGNkay5DdXN0b21SZXNvdXJjZSh0aGlzLCBgJHtwcm9wcy5ydWxlR3JvdXBOYW1lfWN1c3RvbXJlc291cmNlYCwge1xuICAgICAgc2VydmljZVRva2VuOiBuZXcgY3IuUHJvdmlkZXIodGhpcywgYCR7cHJvcHMucnVsZUdyb3VwTmFtZX1zZXJ2aWNlcHJvdmlkZXJgLCB7XG4gICAgICAgIG9uRXZlbnRIYW5kbGVyOiB0aGlzLmNyTGFtYmRhLFxuICAgICAgfSkuc2VydmljZVRva2VuLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBDYXBhY2l0eTogcHJvcHMuY2FwYWNpdHksXG4gICAgICAgIFJ1bGVHcm91cE5hbWU6IHByb3BzLnJ1bGVHcm91cE5hbWUsXG4gICAgICAgIERlc2NyaXB0aW9uOiBwcm9wcy5kZXNjcmlwdGlvbixcbiAgICAgICAgUnVsZXM6IHRoaXMucnVsZXV1aWRsaXN0LFxuICAgICAgICBSZWZlcmVuY2VTZXRzOiB0aGlzLnJ1bGVSZWZlcmVuY2VTZXRzLFxuICAgICAgfSxcbiAgICB9KTtcblxuXG4gICAgdGhpcy5ydWxlR3JvdXBBcm4gPSBzdXJpY2F0YVJ1bGVDci5nZXRBdHRTdHJpbmcoJ1J1bGVHcm91cEFybicpO1xuXG4gICAgbmV3IHJhbS5DZm5SZXNvdXJjZVNoYXJlKHRoaXMsICdzaGFyZVJ1bGVHcm91cCcsIHtcbiAgICAgIG5hbWU6IHByb3BzLnJ1bGVHcm91cE5hbWUsXG4gICAgICBhbGxvd0V4dGVybmFsUHJpbmNpcGFsczogZmFsc2UsXG4gICAgICBwcmluY2lwYWxzOiBbcHJvcHMubmV0d29ya0ZpcmV3YWxsRW5naW5lLmZpcmV3YWxsQWNjb3VudF0sXG4gICAgICByZXNvdXJjZUFybnM6IFt0aGlzLnJ1bGVHcm91cEFybl0sXG4gICAgfSk7XG5cblxuICB9XG5cblxuICBwdWJsaWMgYWRkUnVsZShwcm9wczogRlFETlN0YXRlZnVsUnVsZVByb3BzKTogdm9pZCB7XG5cbiAgICBsZXQgcHJpb3JpdHkgPSAxO1xuICAgIGlmIChwcm9wcy5wcmlvcml0eSkge1xuICAgICAgcHJpb3JpdHkgPSBwcm9wcy5wcmlvcml0eTtcbiAgICB9XG5cbiAgICBsZXQgcnVsZXNEYXRhYmFzZTogU3RhdGVmdWxSdWxlRGF0YWJhc2UgPSB0aGlzLnJ1bGVzRGF0YWJhc2U7XG5cbiAgICAvLyBjcmVhdGUgYSBuZXcgcnVsZSwgYW5kIGluc2VydCBpdCBpbiB0aGUgdGFibGUuXG4gICAgY29uc3QgcnVsZVRvQWRkID0gbmV3IEZRRE5TdGF0ZWZ1bFJ1bGUodGhpcywgcHJvcHMubmFtZSArICdGUUROUnVsZScsIHtcbiAgICAgIG5hbWU6IHByb3BzLm5hbWUsXG4gICAgICBhY3Rpb246IHByb3BzLmFjdGlvbixcbiAgICAgIHByb3RvY29sOiBwcm9wcy5wcm90b2NvbCxcbiAgICAgIHNvdXJjZTogcHJvcHMuc291cmNlLFxuICAgICAgZGVzdGluYXRpb246IHByb3BzLmRlc3RpbmF0aW9uLFxuICAgICAgc3JjUG9ydDogcHJvcHMuc3JjUG9ydCxcbiAgICAgIGRlc3RQb3J0OiBwcm9wcy5kZXN0UG9ydCxcbiAgICAgIGRpcmVjdGlvbjogcHJvcHMuZGlyZWN0aW9uLFxuICAgICAgZnFkbjogcHJvcHMuZnFkbixcbiAgICAgIHByaW9yaXR5OiBwcmlvcml0eSxcbiAgICAgIHJ1bGVzRGF0YWJhc2U6IHJ1bGVzRGF0YWJhc2UsXG5cbiAgICB9KTtcblxuXG4gICAgdGhpcy5ydWxldXVpZGxpc3QucHVzaChydWxlVG9BZGQudXVpZCk7XG5cblxuICAgIC8vIGFkZCBwcmVmaXhsaXN0cyB0byB0aGUgUnVsZXJlZmVyZW5jZVNldHNcbiAgICBydWxlVG9BZGQucHJlZml4TGlzdFNldC5mb3JFYWNoKChwbHNldCkgPT4ge1xuXG4gICAgICAvLyBuZWVkIHRvIGNoZWNrIGlmIGFkZGluZyB0aGlzIHRvIHRvIHRoZSBydWxlcHJlZml4IGxpc3QgaXMgYmFkLlxuICAgICAgY29uc3QgY2hlY2tsaXN0ID0gdGhpcy5ydWxlUmVmZXJlbmNlU2V0cztcbiAgICAgIGNoZWNrbGlzdC5wdXNoKHBsc2V0KTtcbiAgICAgIGNvbnN0IGVycm9yQ2hlY2sgPSBjaGVja0ZvckR1cGxpY2F0ZU5hbWVkUEwoY2hlY2tsaXN0KTsgLy8gdGhpcyB3aWxsIHJhaXNlIGFuIGVycm9yIGlmIHRoZXJlIGlzIG9uZVxuICAgICAgaWYgKGVycm9yQ2hlY2subGVuZ3RoID4gdGhpcy5ydWxlUmVmZXJlbmNlU2V0cy5sZW5ndGgpIHsgLy8gd2UgaGFkIGEgbmV3IHVuaXF1ZSBvbmUsIHNvIHdlIGNhbiBhZGQgaXRcbiAgICAgICAgdGhpcy5ydWxlUmVmZXJlbmNlU2V0cy5wdXNoKHBsc2V0KTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIGFkZCBUYWdHcm91cHM6IFRPRE8uIFRIaXMgbmVlZHMgc29tZSB2YWxpZGF0aW9uLlxuICAgIHJ1bGVUb0FkZC5yZXNvdXJjZUdyb3VwU2V0cy5mb3JFYWNoKChyZXNvdXJjZUdyb3VwKSA9PiB7XG4gICAgICB0aGlzLnJ1bGVSZWZlcmVuY2VTZXRzLnB1c2gocmVzb3VyY2VHcm91cCk7XG4gICAgfSk7XG5cbiAgfVxufVxuXG5mdW5jdGlvbiBjaGVja0ZvckR1cGxpY2F0ZU5hbWVkUEwocHJlZml4bGlzdFNldDpQcmVmaXhMaXN0U2V0SW50ZXJmYWNlW10pOiBQcmVmaXhMaXN0U2V0SW50ZXJmYWNlW10ge1xuXG4gIGNvbnN0IHVuaXF1ZSA9IFsuLi5uZXcgU2V0KHByZWZpeGxpc3RTZXQubWFwKGl0ZW0gPT4gaXRlbS5uYW1lKSldO1xuICB1bmlxdWUuZm9yRWFjaCgoc2V0bmFtZSkgPT4ge1xuICAgIGNvbnN0IGZpbHRlcmVkID0gcHJlZml4bGlzdFNldC5maWx0ZXIoKG9iaikgPT4ge1xuICAgICAgcmV0dXJuIG9iai5uYW1lID09PSBzZXRuYW1lO1xuICAgIH0pO1xuICAgIGlmIChmaWx0ZXJlZC5sZW5ndGggPiAxKSB7XG4gICAgICBjb25zdCB1bmlxdWVBcm4gPSBbLi4ubmV3IFNldChmaWx0ZXJlZC5tYXAoaXRlbSA9PiBpdGVtLmFybikpXTtcbiAgICAgIGlmICh1bmlxdWVBcm4ubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBFcnJvcihgUmVmZXJlbmNlIFNldCBuYW1lcyBtdXN0IGJlIHVuaXF1ZS4gU2V0IG5hbWUgJHtzZXRuYW1lfSBoYXMgYmVlbiB1c2VkIG1vcmUgdGhhbiBvbmNlYCk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIFsuLi5uZXcgTWFwKHByZWZpeGxpc3RTZXQubWFwKChpdGVtKSA9PiBbaXRlbS5hcm4sIGl0ZW1dKSkudmFsdWVzKCldO1xufSJdfQ==