UNPKG

@aws/pdk

Version:

All documentation is located at: https://aws.github.io/aws-pdk

166 lines 26 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ThreatModelGenerator = void 0; /*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ const pdk_nag_1 = require("../../pdk-nag"); const lodash_1 = require("lodash"); const BASE_THREAT_MODEL = require("./base-model/threat-composer-base-model.tc.json"); // Mitigation content is the CDK Nag rule name. const NAG_RULE_MITIGATION_PREFIX = "cdk-nag rule: "; /** * Generates Threat Composer threat models based on CDK Nag results */ class ThreatModelGenerator { constructor() { /** * Given a Threat Composer mitigation, return the CDK Nag rule associated (if any) */ this.getRuleFromMitigation = (mitigation) => { if (mitigation?.content.startsWith(NAG_RULE_MITIGATION_PREFIX)) { return mitigation.content.split(NAG_RULE_MITIGATION_PREFIX)[1]; } return undefined; }; /** * Deduplicate suppression reasons, removing resource details if present */ this.prettySuppressions = (suppressions) => { return (0, lodash_1.uniq)(suppressions.map((s) => s.startsWith("[") ? s.slice(s.indexOf("] ") + 2) : s)); }; } /** * Generate a threat model from a set of cdk nag results */ generate(results, options) { // Summarise nag results into rules and the counts of resources compliant/non-compliant const allApplicableRules = new Set(); const compliance = {}; const suppressionReasons = {}; for (const result of results) { const rule = result.ruleOriginalName; if (!compliance[rule]) { compliance[rule] = { compliantResources: new Set(), nonCompliantResources: new Set(), }; } // Add to the set of all applicable rules so long as the rule is applicable if (result.compliance !== pdk_nag_1.NagResultCompliance.NOT_APPLICABLE) { allApplicableRules.add(rule); } if ([ pdk_nag_1.NagResultCompliance.NON_COMPLIANT, pdk_nag_1.NagResultCompliance.ERROR, pdk_nag_1.NagResultCompliance.NON_COMPLIANT_SUPPRESSED, pdk_nag_1.NagResultCompliance.ERROR_SUPPRESSED, ].includes(result.compliance)) { // Add the resource path to the compliance set compliance[rule].nonCompliantResources.add(result.resource.node.path); if (result.suppressionReason) { suppressionReasons[rule] = [ ...(suppressionReasons[rule] ?? []), result.suppressionReason, ]; } } else if (result.compliance === pdk_nag_1.NagResultCompliance.COMPLIANT) { // Resource is compliant compliance[rule].compliantResources.add(result.resource.node.path); } } const mitigationsById = Object.fromEntries(BASE_THREAT_MODEL.mitigations.map((m) => [m.id, m])); const threatIdToMitigationIds = BASE_THREAT_MODEL.mitigationLinks.reduce((byId, m) => ({ ...byId, [m.linkedId]: [...(byId[m.linkedId] ?? []), m.mitigationId], }), {}); // Get applicable threats - ie threats where there is a mitigation which is a CDK nag rule that is applicable to this project const threats = (0, lodash_1.orderBy)(BASE_THREAT_MODEL.threats, "numericId") .filter((threat) => { const mitigationIds = threatIdToMitigationIds[threat.id] ?? []; return mitigationIds.find((id) => { const mitigationRule = this.getRuleFromMitigation(mitigationsById[id]); return mitigationRule && allApplicableRules.has(mitigationRule); }); }) .map((t, i) => ({ ...t, // Re-map numeric ids and display order numericId: i + 1, displayOrder: i + 1, })); // Get applicable mitigations const mitigations = (0, lodash_1.orderBy)(BASE_THREAT_MODEL.mitigations, "numericId") .map((m) => { const mitigationRule = this.getRuleFromMitigation(mitigationsById[m.id]); if (mitigationRule && compliance[mitigationRule]) { const { compliantResources, nonCompliantResources } = compliance[mitigationRule]; const suppressions = suppressionReasons[mitigationRule]; const compliant = compliantResources.size; const nonCompliant = nonCompliantResources.size; // We can't really warrant adding a mitigation when 0 resources are compliant and there are no suppression reasons if (compliant === 0 && (!suppressions || suppressions.length === 0)) { return undefined; } const suppressionComment = suppressions ? `\n\n__Suppression Reasons__:\n${this.prettySuppressions(suppressions) .map((reason) => `* ${reason}`) .join("\n")}` : ""; let comment = `${compliant} of ${compliant + nonCompliant} Resources Compliant.${suppressionComment}`; // Threat composer limits comments to 1000 chars if (comment.length > 1000) { comment = comment.slice(0, 997) + "..."; } return { ...m, metadata: [ // TODO: Consider appending to existing comments rather than overriding { key: "Comments", value: comment, }, ], }; } return undefined; }) .filter((x) => x).map((m, i) => ({ ...m, // Re-map numeric ids and display order numericId: i + 1, displayOrder: i + 1, })); // Include only mitigation links where we have threats and mitigations const projectThreatIds = new Set(threats.map(({ id }) => id)); const projectMitigationIds = new Set(mitigations.map(({ id }) => id)); const mitigationLinks = BASE_THREAT_MODEL.mitigationLinks.filter((link) => projectThreatIds.has(link.linkedId) && projectMitigationIds.has(link.mitigationId)); const threatModel = { ...BASE_THREAT_MODEL, threats, mitigations, mitigationLinks, architecture: { ...BASE_THREAT_MODEL.architecture, image: options?.architectureImageDataUri ?? "", }, applicationInfo: { ...BASE_THREAT_MODEL.applicationInfo, name: options?.applicationDetails?.name ?? BASE_THREAT_MODEL.applicationInfo.name, description: options?.applicationDetails?.description ?? BASE_THREAT_MODEL.applicationInfo.description, }, }; // jest interprets the "import * as" import differently, so we remove this to ensure the snapshot // is more realistic if ("default" in threatModel) { delete threatModel.default; } return threatModel; } } exports.ThreatModelGenerator = ThreatModelGenerator; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhyZWF0LW1vZGVsLWdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRocmVhdC1tb2RlbC1nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUE7c0NBQ3NDO0FBQ3RDLDBDQUFzRTtBQUN0RSxtQ0FBdUM7QUFDdkMscUZBQXFGO0FBWXJGLCtDQUErQztBQUMvQyxNQUFNLDBCQUEwQixHQUFHLGdCQUFnQixDQUFDO0FBZ0JwRDs7R0FFRztBQUNILE1BQWEsb0JBQW9CO0lBQWpDO1FBQ0U7O1dBRUc7UUFDSywwQkFBcUIsR0FBRyxDQUM5QixVQUFxQyxFQUNqQixFQUFFO1lBQ3RCLElBQUksVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVLENBQUMsMEJBQTBCLENBQUMsRUFBRSxDQUFDO2dCQUMvRCxPQUFPLFVBQVUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLDBCQUEwQixDQUFDLENBQUMsQ0FBQyxDQUVoRCxDQUFDO1lBQ2hCLENBQUM7WUFDRCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDLENBQUM7UUFFRjs7V0FFRztRQUNLLHVCQUFrQixHQUFHLENBQUMsWUFBc0IsRUFBWSxFQUFFO1lBQ2hFLE9BQU8sSUFBQSxhQUFJLEVBQ1QsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQ3JCLENBQUMsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUNyRCxDQUNGLENBQUM7UUFDSixDQUFDLENBQUM7SUFvTEosQ0FBQztJQWxMQzs7T0FFRztJQUNJLFFBQVEsQ0FDYixPQUE0QixFQUM1QixPQUFxQztRQUVyQyx1RkFBdUY7UUFDdkYsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO1FBQzdD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LyksIEluYy4gb3IgaXRzIGFmZmlsaWF0ZXMuIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG5TUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMCAqL1xuaW1wb3J0IHsgRXh0ZW5kZWROYWdSZXN1bHQsIE5hZ1Jlc3VsdENvbXBsaWFuY2UgfSBmcm9tIFwiQGF3cy9wZGstbmFnXCI7XG5pbXBvcnQgeyBvcmRlckJ5LCB1bmlxIH0gZnJvbSBcImxvZGFzaFwiO1xuaW1wb3J0ICogYXMgQkFTRV9USFJFQVRfTU9ERUwgZnJvbSBcIi4vYmFzZS1tb2RlbC90aHJlYXQtY29tcG9zZXItYmFzZS1tb2RlbC50Yy5qc29uXCI7XG5pbXBvcnQgeyBUaHJlYXRDb21wb3NlckFwcGxpY2F0aW9uRGV0YWlscyB9IGZyb20gXCIuL3R5cGVzXCI7XG5cbnR5cGUgVGhyZWF0Q29tcG9zZXJNb2RlbCA9IHR5cGVvZiBCQVNFX1RIUkVBVF9NT0RFTDtcbnR5cGUgVGhyZWF0Q29tcG9zZXJUaHJlYXQgPSBUaHJlYXRDb21wb3Nlck1vZGVsW1widGhyZWF0c1wiXVtudW1iZXJdO1xudHlwZSBUaHJlYXRDb21wb3Nlck1pdGlnYXRpb24gPSBUaHJlYXRDb21wb3Nlck1vZGVsW1wibWl0aWdhdGlvbnNcIl1bbnVtYmVyXTtcblxuaW50ZXJmYWNlIENvbXBsaWFuY2VGaW5kaW5ncyB7XG4gIHJlYWRvbmx5IGNvbXBsaWFudFJlc291cmNlczogU2V0PHN0cmluZz47XG4gIHJlYWRvbmx5IG5vbkNvbXBsaWFudFJlc291cmNlczogU2V0PHN0cmluZz47XG59XG5cbi8vIE1pdGlnYXRpb24gY29udGVudCBpcyB0aGUgQ0RLIE5hZyBydWxlIG5hbWUuXG5jb25zdCBOQUdfUlVMRV9NSVRJR0FUSU9OX1BSRUZJWCA9IFwiY2RrLW5hZyBydWxlOiBcIjtcblxuLyoqXG4gKiBPcHRpb25zIGZvciBnZW5lcmF0aW5nIGEgVGhyZWF0IENvbXBvc2VyIHRocmVhdCBtb2RlbFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRocmVhdE1vZGVsR2VuZXJhdG9yT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBEZXRhaWxzIGFib3V0IHRoZSBhcHBsaWNhdGlvbiB0byBpbmNsdWRlIGluIHRoZSB0aHJlYXQgbW9kZWxcbiAgICovXG4gIHJlYWRvbmx5IGFwcGxpY2F0aW9uRGV0YWlscz86IFRocmVhdENvbXBvc2VyQXBwbGljYXRpb25EZXRhaWxzO1xuICAvKipcbiAgICogQSBkYXRhIHVyaSBmb3IgYW4gYXJjaGl0ZWN0dXJlIGRpYWdyYW0gaW1hZ2VcbiAgICovXG4gIHJlYWRvbmx5IGFyY2hpdGVjdHVyZUltYWdlRGF0YVVyaT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBHZW5lcmF0ZXMgVGhyZWF0IENvbXBvc2VyIHRocmVhdCBtb2RlbHMgYmFzZWQgb24gQ0RLIE5hZyByZXN1bHRzXG4gKi9cbmV4cG9ydCBjbGFzcyBUaHJlYXRNb2RlbEdlbmVyYXRvciB7XG4gIC8qKlxuICAgKiBHaXZlbiBhIFRocmVhdCBDb21wb3NlciBtaXRpZ2F0aW9uLCByZXR1cm4gdGhlIENESyBOYWcgcnVsZSBhc3NvY2lhdGVkIChpZiBhbnkpXG4gICAqL1xuICBwcml2YXRlIGdldFJ1bGVGcm9tTWl0aWdhdGlvbiA9IChcbiAgICBtaXRpZ2F0aW9uPzogVGhyZWF0Q29tcG9zZXJNaXRpZ2F0aW9uXG4gICk6IHN0cmluZyB8IHVuZGVmaW5lZCA9PiB7XG4gICAgaWYgKG1pdGlnYXRpb24/LmNvbnRlbnQuc3RhcnRzV2l0aChOQUdfUlVMRV9NSVRJR0FUSU9OX1BSRUZJWCkpIHtcbiAgICAgIHJldHVybiBtaXRpZ2F0aW9uLmNvbnRlbnQuc3BsaXQoTkFHX1JVTEVfTUlUSUdBVElPTl9QUkVGSVgpWzFdIGFzXG4gICAgICAgIHwgc3RyaW5nXG4gICAgICAgIHwgdW5kZWZpbmVkO1xuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9O1xuXG4gIC8qKlxuICAgKiBEZWR1cGxpY2F0ZSBzdXBwcmVzc2lvbiByZWFzb25zLCByZW1vdmluZyByZXNvdXJjZSBkZXRhaWxzIGlmIHByZXNlbnRcbiAgICovXG4gIHByaXZhdGUgcHJldHR5U3VwcHJlc3Npb25zID0gKHN1cHByZXNzaW9uczogc3RyaW5nW10pOiBzdHJpbmdbXSA9PiB7XG4gICAgcmV0dXJuIHVuaXEoXG4gICAgICBzdXBwcmVzc2lvbnMubWFwKChzKSA9PlxuICAgICAgICBzLnN0YXJ0c1dpdGgoXCJbXCIpID8gcy5zbGljZShzLmluZGV4T2YoXCJdIFwiKSArIDIpIDogc1xuICAgICAgKVxuICAgICk7XG4gIH07XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlIGEgdGhyZWF0IG1vZGVsIGZyb20gYSBzZXQgb2YgY2RrIG5hZyByZXN1bHRzXG4gICAqL1xuICBwdWJsaWMgZ2VuZXJhdGUoXG4gICAgcmVzdWx0czogRXh0ZW5kZWROYWdSZXN1bHRbXSxcbiAgICBvcHRpb25zPzogVGhyZWF0TW9kZWxHZW5lcmF0b3JPcHRpb25zXG4gICk6IFRocmVhdENvbXBvc2VyTW9kZWwge1xuICAgIC8vIFN1bW1hcmlzZSBuYWcgcmVzdWx0cyBpbnRvIHJ1bGVzIGFuZCB0aGUgY291bnRzIG9mIHJlc291cmNlcyBjb21wbGlhbnQvbm9uLWNvbXBsaWFudFxuICAgIGNvbnN0IGFsbEFwcGxpY2FibGVSdWxlcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuICAgIGNvbnN0IGNvbXBsaWFuY2U6IHsgW25hZ1J1bGU6IHN0cmluZ106IENvbXBsaWFuY2VGaW5kaW5ncyB9ID0ge307XG4gICAgY29uc3Qgc3VwcHJlc3Npb25SZWFzb25zOiB7IFtuYWdSdWxlOiBzdHJpbmddOiBzdHJpbmdbXSB9ID0ge307XG5cbiAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzKSB7XG4gICAgICBjb25zdCBydWxlID0gcmVzdWx0LnJ1bGVPcmlnaW5hbE5hbWU7XG5cbiAgICAgIGlmICghY29tcGxpYW5jZVtydWxlXSkge1xuICAgICAgICBjb21wbGlhbmNlW3J1bGVdID0ge1xuICAgICAgICAgIGNvbXBsaWFudFJlc291cmNlczogbmV3IFNldCgpLFxuICAgICAgICAgIG5vbkNvbXBsaWFudFJlc291cmNlczogbmV3IFNldCgpLFxuICAgICAgICB9O1xuICAgICAgfVxuXG4gICAgICAvLyBBZGQgdG8gdGhlIHNldCBvZiBhbGwgYXBwbGljYWJsZSBydWxlcyBzbyBsb25nIGFzIHRoZSBydWxlIGlzIGFwcGxpY2FibGVcbiAgICAgIGlmIChyZXN1bHQuY29tcGxpYW5jZSAhPT0gTmFnUmVzdWx0Q29tcGxpYW5jZS5OT1RfQVBQTElDQUJMRSkge1xuICAgICAgICBhbGxBcHBsaWNhYmxlUnVsZXMuYWRkKHJ1bGUpO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgIFtcbiAgICAgICAgICBOYWdSZXN1bHRDb21wbGlhbmNlLk5PTl9DT01QTElBTlQsXG4gICAgICAgICAgTmFnUmVzdWx0Q29tcGxpYW5jZS5FUlJPUixcbiAgICAgICAgICBOYWdSZXN1bHRDb21wbGlhbmNlLk5PTl9DT01QTElBTlRfU1VQUFJFU1NFRCxcbiAgICAgICAgICBOYWdSZXN1bHRDb21wbGlhbmNlLkVSUk9SX1NVUFBSRVNTRUQsXG4gICAgICAgIF0uaW5jbHVkZXMocmVzdWx0LmNvbXBsaWFuY2UpXG4gICAgICApIHtcbiAgICAgICAgLy8gQWRkIHRoZSByZXNvdXJjZSBwYXRoIHRvIHRoZSBjb21wbGlhbmNlIHNldFxuICAgICAgICBjb21wbGlhbmNlW3J1bGVdLm5vbkNvbXBsaWFudFJlc291cmNlcy5hZGQocmVzdWx0LnJlc291cmNlLm5vZGUucGF0aCk7XG4gICAgICAgIGlmIChyZXN1bHQuc3VwcHJlc3Npb25SZWFzb24pIHtcbiAgICAgICAgICBzdXBwcmVzc2lvblJlYXNvbnNbcnVsZV0gPSBbXG4gICAgICAgICAgICAuLi4oc3VwcHJlc3Npb25SZWFzb25zW3J1bGVdID8/IFtdKSxcbiAgICAgICAgICAgIHJlc3VsdC5zdXBwcmVzc2lvblJlYXNvbixcbiAgICAgICAgICBdO1xuICAgICAgICB9XG4gICAgICB9IGVsc2UgaWYgKHJlc3VsdC5jb21wbGlhbmNlID09PSBOYWdSZXN1bHRDb21wbGlhbmNlLkNPTVBMSUFOVCkge1xuICAgICAgICAvLyBSZXNvdXJjZSBpcyBjb21wbGlhbnRcbiAgICAgICAgY29tcGxpYW5jZVtydWxlXS5jb21wbGlhbnRSZXNvdXJjZXMuYWRkKHJlc3VsdC5yZXNvdXJjZS5ub2RlLnBhdGgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IG1pdGlnYXRpb25zQnlJZCA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgIEJBU0VfVEhSRUFUX01PREVMLm1pdGlnYXRpb25zLm1hcCgobSkgPT4gW20uaWQsIG1dKVxuICAgICk7XG4gICAgY29uc3QgdGhyZWF0SWRUb01pdGlnYXRpb25JZHMgPSBCQVNFX1RIUkVBVF9NT0RFTC5taXRpZ2F0aW9uTGlua3MucmVkdWNlKFxuICAgICAgKGJ5SWQsIG0pID0+ICh7XG4gICAgICAgIC4uLmJ5SWQsXG4gICAgICAgIFttLmxpbmtlZElkXTogWy4uLihieUlkW20ubGlua2VkSWRdID8/IFtdKSwgbS5taXRpZ2F0aW9uSWRdLFxuICAgICAgfSksXG4gICAgICB7fSBhcyB7IFt0aHJlYXRJZDogc3RyaW5nXTogc3RyaW5nW10gfVxuICAgICk7XG5cbiAgICAvLyBHZXQgYXBwbGljYWJsZSB0aHJlYXRzIC0gaWUgdGhyZWF0cyB3aGVyZSB0aGVyZSBpcyBhIG1pdGlnYXRpb24gd2hpY2ggaXMgYSBDREsgbmFnIHJ1bGUgdGhhdCBpcyBhcHBsaWNhYmxlIHRvIHRoaXMgcHJvamVjdFxuICAgIGNvbnN0IHRocmVhdHM6IFRocmVhdENvbXBvc2VyVGhyZWF0W10gPSBvcmRlckJ5KFxuICAgICAgQkFTRV9USFJFQVRfTU9ERUwudGhyZWF0cyxcbiAgICAgIFwibnVtZXJpY0lkXCJcbiAgICApXG4gICAgICAuZmlsdGVyKCh0aHJlYXQpID0+IHtcbiAgICAgICAgY29uc3QgbWl0aWdhdGlvbklkcyA9IHRocmVhdElkVG9NaXRpZ2F0aW9uSWRzW3RocmVhdC5pZF0gPz8gW107XG4gICAgICAgIHJldHVybiBtaXRpZ2F0aW9uSWRzLmZpbmQoKGlkKSA9PiB7XG4gICAgICAgICAgY29uc3QgbWl0aWdhdGlvblJ1bGUgPSB0aGlzLmdldFJ1bGVGcm9tTWl0aWdhdGlvbihcbiAgICAgICAgICAgIG1pdGlnYXRpb25zQnlJZFtpZF1cbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiBtaXRpZ2F0aW9uUnVsZSAmJiBhbGxBcHBsaWNhYmxlUnVsZXMuaGFzKG1pdGlnYXRpb25SdWxlKTtcbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLm1hcCgodCwgaSkgPT4gKHtcbiAgICAgICAgLi4udCxcbiAgICAgICAgLy8gUmUtbWFwIG51bWVyaWMgaWRzIGFuZCBkaXNwbGF5IG9yZGVyXG4gICAgICAgIG51bWVyaWNJZDogaSArIDEsXG4gICAgICAgIGRpc3BsYXlPcmRlcjogaSArIDEsXG4gICAgICB9KSk7XG5cbiAgICAvLyBHZXQgYXBwbGljYWJsZSBtaXRpZ2F0aW9uc1xuICAgIGNvbnN0IG1pdGlnYXRpb25zID0gKFxuICAgICAgb3JkZXJCeShCQVNFX1RIUkVBVF9NT0RFTC5taXRpZ2F0aW9ucywgXCJudW1lcmljSWRcIilcbiAgICAgICAgLm1hcCgobSkgPT4ge1xuICAgICAgICAgIGNvbnN0IG1pdGlnYXRpb25SdWxlID0gdGhpcy5nZXRSdWxlRnJvbU1pdGlnYXRpb24oXG4gICAgICAgICAgICBtaXRpZ2F0aW9uc0J5SWRbbS5pZF1cbiAgICAgICAgICApO1xuICAgICAgICAgIGlmIChtaXRpZ2F0aW9uUnVsZSAmJiBjb21wbGlhbmNlW21pdGlnYXRpb25SdWxlXSkge1xuICAgICAgICAgICAgY29uc3QgeyBjb21wbGlhbnRSZXNvdXJjZXMsIG5vbkNvbXBsaWFudFJlc291cmNlcyB9ID1cbiAgICAgICAgICAgICAgY29tcGxpYW5jZVttaXRpZ2F0aW9uUnVsZV07XG4gICAgICAgICAgICBjb25zdCBzdXBwcmVzc2lvbnMgPSBzdXBwcmVzc2lvblJlYXNvbnNbbWl0aWdhdGlvblJ1bGVdO1xuICAgICAgICAgICAgY29uc3QgY29tcGxpYW50ID0gY29tcGxpYW50UmVzb3VyY2VzLnNpemU7XG4gICAgICAgICAgICBjb25zdCBub25Db21wbGlhbnQgPSBub25Db21wbGlhbnRSZXNvdXJjZXMuc2l6ZTtcblxuICAgICAgICAgICAgLy8gV2UgY2FuJ3QgcmVhbGx5IHdhcnJhbnQgYWRkaW5nIGEgbWl0aWdhdGlvbiB3aGVuIDAgcmVzb3VyY2VzIGFyZSBjb21wbGlhbnQgYW5kIHRoZXJlIGFyZSBubyBzdXBwcmVzc2lvbiByZWFzb25zXG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIGNvbXBsaWFudCA9PT0gMCAmJlxuICAgICAgICAgICAgICAoIXN1cHByZXNzaW9ucyB8fCBzdXBwcmVzc2lvbnMubGVuZ3RoID09PSAwKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHN1cHByZXNzaW9uQ29tbWVudCA9IHN1cHByZXNzaW9uc1xuICAgICAgICAgICAgICA/IGBcXG5cXG5fX1N1cHByZXNzaW9uIFJlYXNvbnNfXzpcXG4ke3RoaXMucHJldHR5U3VwcHJlc3Npb25zKFxuICAgICAgICAgICAgICAgICAgc3VwcHJlc3Npb25zXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgICAgLm1hcCgocmVhc29uKSA9PiBgKiAke3JlYXNvbn1gKVxuICAgICAgICAgICAgICAgICAgLmpvaW4oXCJcXG5cIil9YFxuICAgICAgICAgICAgICA6IFwiXCI7XG5cbiAgICAgICAgICAgIGxldCBjb21tZW50ID0gYCR7Y29tcGxpYW50fSBvZiAke1xuICAgICAgICAgICAgICBjb21wbGlhbnQgKyBub25Db21wbGlhbnRcbiAgICAgICAgICAgIH0gUmVzb3VyY2VzIENvbXBsaWFudC4ke3N1cHByZXNzaW9uQ29tbWVudH1gO1xuXG4gICAgICAgICAgICAvLyBUaHJlYXQgY29tcG9zZXIgbGltaXRzIGNvbW1lbnRzIHRvIDEwMDAgY2hhcnNcbiAgICAgICAgICAgIGlmIChjb21tZW50Lmxlbmd0aCA+IDEwMDApIHtcbiAgICAgICAgICAgICAgY29tbWVudCA9IGNvbW1lbnQuc2xpY2UoMCwgOTk3KSArIFwiLi4uXCI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIC4uLm0sXG4gICAgICAgICAgICAgIG1ldGFkYXRhOiBbXG4gICAgICAgICAgICAgICAgLy8gVE9ETzogQ29uc2lkZXIgYXBwZW5kaW5nIHRvIGV4aXN0aW5nIGNvbW1lbnRzIHJhdGhlciB0aGFuIG92ZXJyaWRpbmdcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBrZXk6IFwiQ29tbWVudHNcIixcbiAgICAgICAgICAgICAgICAgIHZhbHVlOiBjb21tZW50LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9KVxuICAgICAgICAuZmlsdGVyKCh4KSA9PiB4KSBhcyBUaHJlYXRDb21wb3Nlck1pdGlnYXRpb25bXVxuICAgICkubWFwKChtLCBpKSA9PiAoe1xuICAgICAgLi4ubSxcbiAgICAgIC8vIFJlLW1hcCBudW1lcmljIGlkcyBhbmQgZGlzcGxheSBvcmRlclxuICAgICAgbnVtZXJpY0lkOiBpICsgMSxcbiAgICAgIGRpc3BsYXlPcmRlcjogaSArIDEsXG4gICAgfSkpO1xuXG4gICAgLy8gSW5jbHVkZSBvbmx5IG1pdGlnYXRpb24gbGlua3Mgd2hlcmUgd2UgaGF2ZSB0aHJlYXRzIGFuZCBtaXRpZ2F0aW9uc1xuICAgIGNvbnN0IHByb2plY3RUaHJlYXRJZHMgPSBuZXcgU2V0KHRocmVhdHMubWFwKCh7IGlkIH0pID0+IGlkKSk7XG4gICAgY29uc3QgcHJvamVjdE1pdGlnYXRpb25JZHMgPSBuZXcgU2V0KG1pdGlnYXRpb25zLm1hcCgoeyBpZCB9KSA9PiBpZCkpO1xuICAgIGNvbnN0IG1pdGlnYXRpb25MaW5rcyA9IEJBU0VfVEhSRUFUX01PREVMLm1pdGlnYXRpb25MaW5rcy5maWx0ZXIoXG4gICAgICAobGluaykgPT5cbiAgICAgICAgcHJvamVjdFRocmVhdElkcy5oYXMobGluay5saW5rZWRJZCkgJiZcbiAgICAgICAgcHJvamVjdE1pdGlnYXRpb25JZHMuaGFzKGxpbmsubWl0aWdhdGlvbklkKVxuICAgICk7XG5cbiAgICBjb25zdCB0aHJlYXRNb2RlbCA9IHtcbiAgICAgIC4uLkJBU0VfVEhSRUFUX01PREVMLFxuICAgICAgdGhyZWF0cyxcbiAgICAgIG1pdGlnYXRpb25zLFxuICAgICAgbWl0aWdhdGlvbkxpbmtzLFxuICAgICAgYXJjaGl0ZWN0dXJlOiB7XG4gICAgICAgIC4uLkJBU0VfVEhSRUFUX01PREVMLmFyY2hpdGVjdHVyZSxcbiAgICAgICAgaW1hZ2U6IG9wdGlvbnM/LmFyY2hpdGVjdHVyZUltYWdlRGF0YVVyaSA/PyBcIlwiLFxuICAgICAgfSxcbiAgICAgIGFwcGxpY2F0aW9uSW5mbzoge1xuICAgICAgICAuLi5CQVNFX1RIUkVBVF9NT0RFTC5hcHBsaWNhdGlvbkluZm8sXG4gICAgICAgIG5hbWU6XG4gICAgICAgICAgb3B0aW9ucz8uYXBwbGljYXRpb25EZXRhaWxzPy5uYW1lID8/XG4gICAgICAgICAgQkFTRV9USFJFQVRfTU9ERUwuYXBwbGljYXRpb25JbmZvLm5hbWUsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgIG9wdGlvbnM/LmFwcGxpY2F0aW9uRGV0YWlscz8uZGVzY3JpcHRpb24gPz9cbiAgICAgICAgICBCQVNFX1RIUkVBVF9NT0RFTC5hcHBsaWNhdGlvbkluZm8uZGVzY3JpcHRpb24sXG4gICAgICB9LFxuICAgIH07XG5cbiAgICAvLyBqZXN0IGludGVycHJldHMgdGhlIFwiaW1wb3J0ICogYXNcIiBpbXBvcnQgZGlmZmVyZW50bHksIHNvIHdlIHJlbW92ZSB0aGlzIHRvIGVuc3VyZSB0aGUgc25hcHNob3RcbiAgICAvLyBpcyBtb3JlIHJlYWxpc3RpY1xuICAgIGlmIChcImRlZmF1bHRcIiBpbiB0aHJlYXRNb2RlbCkge1xuICAgICAgZGVsZXRlIHRocmVhdE1vZGVsLmRlZmF1bHQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRocmVhdE1vZGVsO1xuICB9XG59XG4iXX0=