UNPKG

27 kBJavaScriptView Raw
1"use strict";
2// IAM Statement merging
3//
4// See docs/policy-merging.als for a formal model of the logic
5// implemented here.
6Object.defineProperty(exports, "__esModule", { value: true });
7exports.mergeStatements = void 0;
8const util_1 = require("../util");
9const postprocess_policy_document_1 = require("./postprocess-policy-document");
10/**
11 * Merge as many statements as possible to shrink the total policy doc, modifying the input array in place
12 *
13 * We compare and merge all pairs of statements (O(N^2) complexity), opportunistically
14 * merging them. This is not guaranteed to produce the optimal output, but it's probably
15 * Good Enough(tm). If it merges anything, it's at least going to produce a smaller output
16 * than the input.
17 */
18function mergeStatements(statements) {
19 const compStatements = statements.map(makeComparable);
20 // Keep trying until nothing changes anymore
21 while (onePass()) { /* again */ }
22 return compStatements.map(renderComparable);
23 // Do one optimization pass, return 'true' if we merged anything
24 function onePass() {
25 let ret = false;
26 let i = 0;
27 while (i < compStatements.length) {
28 let didMerge = false;
29 for (let j = i + 1; j < compStatements.length; j++) {
30 const merged = tryMerge(compStatements[i], compStatements[j]);
31 if (merged) {
32 compStatements[i] = merged;
33 compStatements.splice(j, 1);
34 ret = didMerge = true;
35 break;
36 }
37 }
38 if (!didMerge) {
39 i++;
40 }
41 }
42 return ret;
43 }
44}
45exports.mergeStatements = mergeStatements;
46/**
47 * Given two statements, return their merging (if possible)
48 *
49 * We can merge two statements if:
50 *
51 * - Their effects are the same
52 * - They don't have Sids (not really a hard requirement, but just a simplification and an escape hatch)
53 * - Their Conditions are the same
54 * - Their NotAction, NotResource and NotPrincipal sets are the same (empty sets is fine).
55 * - From their Action, Resource and Principal sets, 2 are subsets of each other
56 * (empty sets are fine).
57 */
58function tryMerge(a, b) {
59 // Effects must be the same
60 if (a.effect !== b.effect) {
61 return;
62 }
63 // We don't merge Sids (for now)
64 if (a.sid || b.sid) {
65 return;
66 }
67 if (a.conditionString !== b.conditionString) {
68 return;
69 }
70 if (!setEqual(a.notAction, b.notAction) || !setEqual(a.notResource, b.notResource) || !setEqual(a.notPrincipal, b.notPrincipal)) {
71 return;
72 }
73 // We can merge these statements if 2 out of the 3 sets of Action, Resource, Principal
74 // are the same.
75 const setsEqual = (setEqual(a.action, b.action) ? 1 : 0) +
76 (setEqual(a.resource, b.resource) ? 1 : 0) +
77 (setEqual(a.principal, b.principal) ? 1 : 0);
78 if (setsEqual < 2 || unmergeablePrincipals(a, b)) {
79 return;
80 }
81 return {
82 effect: a.effect,
83 conditionString: a.conditionString,
84 conditionValue: b.conditionValue,
85 notAction: a.notAction,
86 notPrincipal: a.notPrincipal,
87 notResource: a.notResource,
88 action: setMerge(a.action, b.action),
89 resource: setMerge(a.resource, b.resource),
90 principal: setMerge(a.principal, b.principal),
91 };
92}
93/**
94 * Calculate and return cached string set representation of the statement elements
95 *
96 * This is to be able to do comparisons on these sets quickly.
97 */
98function makeComparable(s) {
99 return {
100 effect: s.Effect,
101 sid: s.Sid,
102 action: iamSet(s.Action),
103 notAction: iamSet(s.NotAction),
104 resource: iamSet(s.Resource),
105 notResource: iamSet(s.NotResource),
106 principal: principalIamSet(s.Principal),
107 notPrincipal: principalIamSet(s.NotPrincipal),
108 conditionString: JSON.stringify(s.Condition),
109 conditionValue: s.Condition,
110 };
111 function forceArray(x) {
112 return Array.isArray(x) ? x : [x];
113 }
114 function iamSet(x) {
115 if (x == undefined) {
116 return {};
117 }
118 return mkdict(forceArray(x).map(e => [JSON.stringify(e), e]));
119 }
120 function principalIamSet(x) {
121 if (x === undefined) {
122 return {};
123 }
124 if (Array.isArray(x) || typeof x === 'string') {
125 x = { [util_1.LITERAL_STRING_KEY]: x };
126 }
127 if (typeof x === 'object' && x !== null) {
128 // Turn { AWS: [a, b], Service: [c] } into [{ AWS: a }, { AWS: b }, { Service: c }]
129 const individualPrincipals = Object.entries(x).flatMap(([principalType, value]) => forceArray(value).map(v => ({ [principalType]: v })));
130 return iamSet(individualPrincipals);
131 }
132 return {};
133 }
134}
135/**
136 * Return 'true' if the two principals are unmergeable
137 *
138 * This only happens if one of them is a literal, untyped principal (typically,
139 * `Principal: '*'`) and the other one is typed.
140 *
141 * `Principal: '*'` behaves subtly different than `Principal: { AWS: '*' }` and must
142 * therefore be preserved.
143 */
144function unmergeablePrincipals(a, b) {
145 const aHasLiteral = Object.values(a.principal).some(v => util_1.LITERAL_STRING_KEY in v);
146 const bHasLiteral = Object.values(b.principal).some(v => util_1.LITERAL_STRING_KEY in v);
147 return aHasLiteral !== bHasLiteral;
148}
149/**
150 * Turn a ComparableStatement back into a StatementSchema
151 */
152function renderComparable(s) {
153 return postprocess_policy_document_1.normalizeStatement({
154 Effect: s.effect,
155 Sid: s.sid,
156 Condition: s.conditionValue,
157 Action: renderSet(s.action),
158 NotAction: renderSet(s.notAction),
159 Resource: renderSet(s.resource),
160 NotResource: renderSet(s.notResource),
161 Principal: renderPrincipalSet(s.principal),
162 NotPrincipal: renderPrincipalSet(s.notPrincipal),
163 });
164 function renderSet(x) {
165 // Return as sorted array so that we normalize
166 const keys = Object.keys(x).sort();
167 return keys.length > 0 ? keys.map(key => x[key]) : undefined;
168 }
169 function renderPrincipalSet(x) {
170 const keys = Object.keys(x).sort();
171 // The first level will be an object
172 const ret = {};
173 for (const key of keys) {
174 const principal = x[key];
175 if (principal == null || typeof principal !== 'object') {
176 throw new Error(`Principal should be an object with a principal type, got: ${principal}`);
177 }
178 const principalKeys = Object.keys(principal);
179 if (principalKeys.length !== 1) {
180 throw new Error(`Principal should be an object with 1 key, found keys: ${principalKeys}`);
181 }
182 const pk = principalKeys[0];
183 if (!ret[pk]) {
184 ret[pk] = [];
185 }
186 ret[pk].push(principal[pk]);
187 }
188 return ret;
189 }
190}
191/**
192 * Whether the given sets are equal
193 */
194function setEqual(a, b) {
195 const keysA = Object.keys(a);
196 const keysB = Object.keys(b);
197 return keysA.length === keysB.length && keysA.every(k => k in b);
198}
199/**
200 * Merge two IAM value sets
201 */
202function setMerge(x, y) {
203 return { ...x, ...y };
204}
205function mkdict(xs) {
206 const ret = {};
207 for (const x of xs) {
208 ret[x[0]] = x[1];
209 }
210 return ret;
211}
212//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVyZ2Utc3RhdGVtZW50cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm1lcmdlLXN0YXRlbWVudHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHdCQUF3QjtBQUN4QixFQUFFO0FBQ0YsOERBQThEO0FBQzlELG9CQUFvQjs7O0FBR3BCLGtDQUE2QztBQUM3QywrRUFBOEY7QUFFOUY7Ozs7Ozs7R0FPRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxVQUE2QjtJQUMzRCxNQUFNLGNBQWMsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBRXRELDRDQUE0QztJQUM1QyxPQUFPLE9BQU8sRUFBRSxFQUFFLEVBQUUsV0FBVyxFQUFFO0lBQ2pDLE9BQU8sY0FBYyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBRTVDLGdFQUFnRTtJQUNoRSxTQUFTLE9BQU87UUFDZCxJQUFJLEdBQUcsR0FBRyxLQUFLLENBQUM7UUFDaEIsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ1YsT0FBTyxDQUFDLEdBQUcsY0FBYyxDQUFDLE1BQU0sRUFBRTtZQUNoQyxJQUFJLFFBQVEsR0FBRyxLQUFLLENBQUM7WUFFckIsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxjQUFjLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO2dCQUNsRCxNQUFNLE1BQU0sR0FBRyxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUM5RCxJQUFJLE1BQU0sRUFBRTtvQkFDVixjQUFjLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDO29CQUMzQixjQUFjLENBQUMsTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztvQkFDNUIsR0FBRyxHQUFHLFFBQVEsR0FBRyxJQUFJLENBQUM7b0JBQ3RCLE1BQU07aUJB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Q0FBQyxDQUFDO1lBQzVCLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUU7Z0JBQ1osR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQzthQUNkO1lBQ0EsR0FBRyxDQUFDLEVBQUUsQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7U0FDN0M7UUFDRCxPQUFPLEdBQUcsQ0FBQztJQUNiLENBQUM7QUFDSCxDQUFDO0FBZ0NEOztHQUVHO0FBQ0gsU0FBUyxRQUFRLENBQUMsQ0FBYyxFQUFFLENBQWM7SUFDOUMsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM3QixNQUFNLEtBQUssR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzdCLE9BQU8sS0FBSyxDQUFDLE1BQU0sS0FBSyxLQUFLLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7QUFDbkUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxRQUFRLENBQUMsQ0FBYyxFQUFFLENBQWM7SUFDOUMsT0FBTyxFQUFFLEdBQUcsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7QUFDeEIsQ0FBQztBQUVELFNBQVMsTUFBTSxDQUFJLEVBQXNCO0lBQ3ZDLE1BQU0sR0FBRyxHQUFzQixFQUFFLENBQUM7SUFDbEMsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUU7UUFDbEIsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUNsQjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIElBTSBTdGF0ZW1lbnQgbWVyZ2luZ1xuLy9cbi8vIFNlZSBkb2NzL3BvbGljeS1tZXJnaW5nLmFscyBmb3IgYSBmb3JtYWwgbW9kZWwgb2YgdGhlIGxvZ2ljXG4vLyBpbXBsZW1lbnRlZCBoZXJlLlxuXG5cbmltcG9ydCB7IExJVEVSQUxfU1RSSU5HX0tFWSB9IGZyb20gJy4uL3V0aWwnO1xuaW1wb3J0IHsgU3RhdGVtZW50U2NoZW1hLCBub3JtYWxpemVTdGF0ZW1lbnQsIElhbVZhbHVlIH0gZnJvbSAnLi9wb3N0cHJvY2Vzcy1wb2xpY3ktZG9jdW1lbnQnO1xuXG4vKipcbiAqIE1lcmdlIGFzIG1hbnkgc3RhdGVtZW50cyBhcyBwb3NzaWJsZSB0byBzaHJpbmsgdGhlIHRvdGFsIHBvbGljeSBkb2MsIG1vZGlmeWluZyB0aGUgaW5wdXQgYXJyYXkgaW4gcGxhY2VcbiAqXG4gKiBXZSBjb21wYXJlIGFuZCBtZXJnZSBhbGwgcGFpcnMgb2Ygc3RhdGVtZW50cyAoTyhOXjIpIGNvbXBsZXhpdHkpLCBvcHBvcnR1bmlzdGljYWxseVxuICogbWVyZ2luZyB0aGVtLiBUaGlzIGlzIG5vdCBndWFyYW50ZWVkIHRvIHByb2R1Y2UgdGhlIG9wdGltYWwgb3V0cHV0LCBidXQgaXQncyBwcm9iYWJseVxuICogR29vZCBFbm91Z2godG0pLiBJZiBpdCBtZXJnZXMgYW55dGhpbmcsIGl0J3MgYXQgbGVhc3QgZ29pbmcgdG8gcHJvZHVjZSBhIHNtYWxsZXIgb3V0cHV0XG4gKiB0aGFuIHRoZSBpbnB1dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlU3RhdGVtZW50cyhzdGF0ZW1lbnRzOiBTdGF0ZW1lbnRTY2hlbWFbXSk6IFN0YXRlbWVudFNjaGVtYVtdIHtcbiAgY29uc3QgY29tcFN0YXRlbWVudHMgPSBzdGF0ZW1lbnRzLm1hcChtYWtlQ29tcGFyYWJsZSk7XG5cbiAgLy8gS2VlcCB0cnlpbmcgdW50aWwgbm90aGluZyBjaGFuZ2VzIGFueW1vcmVcbiAgd2hpbGUgKG9uZVBhc3MoKSkgeyAvKiBhZ2FpbiAqLyB9XG4gIHJldHVybiBjb21wU3RhdGVtZW50cy5tYXAocmVuZGVyQ29tcGFyYWJsZSk7XG5cbiAgLy8gRG8gb25lIG9wdGltaXphdGlvbiBwYXNzLCByZXR1cm4gJ3RydWUnIGlmIHdlIG1lcmdlZCBhbnl0aGluZ1xuICBmdW5jdGlvbiBvbmVQYXNzKCkge1xuICAgIGxldCByZXQgPSBmYWxzZTtcbiAgICBsZXQgaSA9IDA7XG4gICAgd2hpbGUgKGkgPCBjb21wU3RhdGVtZW50cy5sZW5ndGgpIHtcbiAgICAgIGxldCBkaWRNZXJnZSA9IGZhbHNlO1xuXG4gICAgICBmb3IgKGxldCBqID0gaSArIDE7IGogPCBjb21wU3RhdGVtZW50cy5sZW5ndGg7IGorKykge1xuICAgICAgICBjb25zdCBtZXJnZWQgPSB0cnlNZXJnZShjb21wU3RhdGVtZW50c1tpXSwgY29tcFN0YXRlbWVudHNbal0pO1xuICAgICAgICBpZiAobWVyZ2VkKSB7XG4gICAgICAgICAgY29tcFN0YXRlbWVudHNbaV0gPSBtZXJnZWQ7XG4gICAgICAgICAgY29tcFN0YXRlbWVudHMuc3BsaWNlKGosIDEpO1xuICAgICAgICAgIHJldCA9IGRpZE1lcmdlID0gdHJ1ZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIWRpZE1lcmdlKSB7XG4gICAgICAgIGkrKztcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxufVxuXG4vKipcbiAqIEdpdmVuIHR3byBzdGF0ZW1lbnRzLCByZXR1cm4gdGhlaXIgbWVyZ2luZyAoaWYgcG9zc2libGUpXG4gKlxuICogV2UgY2FuIG1lcmdlIHR3byBzdGF0ZW1lbnRzIGlmOlxuICpcbiAqIC0gVGhlaXIgZWZmZWN0cyBhcmUgdGhlIHNhbWVcbiAqIC0gVGhleSBkb24ndCBoYXZlIFNpZHMgKG5vdCByZWFsbHkgYSBoYXJkIHJlcXVpcmVtZW50LCBidXQganVzdCBhIHNpbXBsaWZpY2F0aW9uIGFuZCBhbiBlc2NhcGUgaGF0Y2gpXG4gKiAtIFRoZWlyIENvbmRpdGlvbnMgYXJlIHRoZSBzYW1lXG4gKiAtIFRoZWlyIE5vdEFjdGlvbiwgTm90UmVzb3VyY2UgYW5kIE5vdFByaW5jaXBhbCBzZXRzIGFyZSB0aGUgc2FtZSAoZW1wdHkgc2V0cyBpcyBmaW5lKS5cbiAqIC0gRnJvbSB0aGVpciBBY3Rpb24sIFJlc291cmNlIGFuZCBQcmluY2lwYWwgc2V0cywgMiBhcmUgc3Vic2V0cyBvZiBlYWNoIG90aGVyXG4gKiAgIChlbXB0eSBzZXRzIGFyZSBmaW5lKS5cbiAqL1xuZnVuY3Rpb24gdHJ5TWVyZ2UoYTogQ29tcGFyYWJsZVN0YXRlbWVudCwgYjogQ29tcGFyYWJsZVN0YXRlbWVudCk6IENvbXBhcmFibGVTdGF0ZW1lbnQgfCB1bmRlZmluZWQge1xuICAvLyBFZmZlY3RzIG11c3QgYmUgdGhlIHNhbWVcbiAgaWYgKGEuZWZmZWN0ICE9PSBiLmVmZmVjdCkgeyByZXR1cm47IH1cbiAgLy8gV2UgZG9uJ3QgbWVyZ2UgU2lkcyAoZm9yIG5vdylcbiAgaWYgKGEuc2lkIHx8IGIuc2lkKSB7IHJldHVybjsgfVxuXG4gIGlmIChhLmNvbmRpdGlvblN0cmluZyAhPT0gYi5jb25kaXRpb25TdHJpbmcpIHsgcmV0dXJuOyB9XG4gIGlmICghc2V0RXF1YWwoYS5ub3RBY3Rpb24sIGIubm90QWN0aW9uKSB8fCAhc2V0RXF1YWwoYS5ub3RSZXNvdXJjZSwgYi5ub3RSZXNvdXJjZSkgfHwgIXNldEVxdWFsKGEubm90UHJpbmNpcGFsLCBiLm5vdFByaW5jaXBhbCkpIHsgcmV0dXJuOyB9XG5cbiAgLy8gV2UgY2FuIG1lcmdlIHRoZXNlIHN0YXRlbWVudHMgaWYgMiBvdXQgb2YgdGhlIDMgc2V0cyBvZiBBY3Rpb24sIFJlc291cmNlLCBQcmluY2lwYWxcbiAgLy8gYXJlIHRoZSBzYW1lLlxuICBjb25zdCBzZXRzRXF1YWwgPSAoc2V0RXF1YWwoYS5hY3Rpb24sIGIuYWN0aW9uKSA/IDEgOiAwKSArXG4gICAgKHNldEVxdWFsKGEucmVzb3VyY2UsIGIucmVzb3VyY2UpID8gMSA6IDApICtcbiAgICAoc2V0RXF1YWwoYS5wcmluY2lwYWwsIGIucHJpbmNpcGFsKSA/IDEgOiAwKTtcblxuICBpZiAoc2V0c0VxdWFsIDwgMiB8fCB1bm1lcmdlYWJsZVByaW5jaXBhbHMoYSwgYikpIHsgcmV0dXJuOyB9XG5cbiAgcmV0dXJuIHtcbiAgICBlZmZlY3Q6IGEuZWZmZWN0LFxuICAgIGNvbmRpdGlvblN0cmluZzogYS5jb25kaXRpb25TdHJpbmcsXG4gICAgY29uZGl0aW9uVmFsdWU6IGIuY29uZGl0aW9uVmFsdWUsXG4gICAgbm90QWN0aW9uOiBhLm5vdEFjdGlvbixcbiAgICBub3RQcmluY2lwYWw6IGEubm90UHJpbmNpcGFsLFxuICAgIG5vdFJlc291cmNlOiBhLm5vdFJlc291cmNlLFxuXG4gICAgYWN0aW9uOiBzZXRNZXJnZShhLmFjdGlvbiwgYi5hY3Rpb24pLFxuICAgIHJlc291cmNlOiBzZXRNZXJnZShhLnJlc291cmNlLCBiLnJlc291cmNlKSxcbiAgICBwcmluY2lwYWw6IHNldE1lcmdlKGEucHJpbmNpcGFsLCBiLnByaW5jaXBhbCksXG4gIH07XG59XG5cbi8qKlxuICogQ2FsY3VsYXRlIGFuZCByZXR1cm4gY2FjaGVkIHN0cmluZyBzZXQgcmVwcmVzZW50YXRpb24gb2YgdGhlIHN0YXRlbWVudCBlbGVtZW50c1xuICpcbiAqIFRoaXMgaXMgdG8gYmUgYWJsZSB0byBkbyBjb21wYXJpc29ucyBvbiB0aGVzZSBzZXRzIHF1aWNrbHkuXG4gKi9cbmZ1bmN0aW9uIG1ha2VDb21wYXJhYmxlKHM6IFN0YXRlbWVudFNjaGVtYSk6IENvbXBhcmFibGVTdGF0ZW1lbnQge1xuICByZXR1cm4ge1xuICAgIGVmZmVjdDogcy5FZmZlY3QsXG4gICAgc2lkOiBzLlNpZCxcbiAgICBhY3Rpb246IGlhbVNldChzLkFjdGlvbiksXG4gICAgbm90QWN0aW9uOiBpYW1TZXQocy5Ob3RBY3Rpb24pLFxuICAgIHJlc291cmNlOiBpYW1TZXQocy5SZXNvdXJjZSksXG4gICAgbm90UmVzb3VyY2U6IGlhbVNldChzLk5vdFJlc291cmNlKSxcbiAgICBwcmluY2lwYWw6IHByaW5jaXBhbElhbVNldChzLlByaW5jaXBhbCksXG4gICAgbm90UHJpbmNpcGFsOiBwcmluY2lwYWxJYW1TZXQocy5Ob3RQcmluY2lwYWwpLFxuICAgIGNvbmRpdGlvblN0cmluZzogSlNPTi5zdHJpbmdpZnkocy5Db25kaXRpb24pLFxuICAgIGNvbmRpdGlvblZhbHVlOiBzLkNvbmRpdGlvbixcbiAgfTtcblxuICBmdW5jdGlvbiBmb3JjZUFycmF5PEE+KHg6IEEgfCBBcnJheTxBPik6IEFycmF5PEE+IHtcbiAgICByZXR1cm4gQXJyYXkuaXNBcnJheSh4KSA/IHggOiBbeF07XG4gIH1cblxuICBmdW5jdGlvbiBpYW1TZXQoeDogSWFtVmFsdWUgfCB1bmRlZmluZWQpOiBJYW1WYWx1ZVNldCB7XG4gICAgaWYgKHggPT0gdW5kZWZpbmVkKSB7IHJldHVybiB7fTsgfVxuICAgIHJldHVybiBta2RpY3QoZm9yY2VBcnJheSh4KS5tYXAoZSA9PiBbSlNPTi5zdHJpbmdpZnkoZSksIGVdKSk7XG4gIH1cblxuICBmdW5jdGlvbiBwcmluY2lwYWxJYW1TZXQoeDogSWFtVmFsdWUgfCBSZWNvcmQ8c3RyaW5nLCBJYW1WYWx1ZT4gfCB1bmRlZmluZWQpOiBJYW1WYWx1ZVNldCB7XG4gICAgaWYgKHggPT09IHVuZGVmaW5lZCkgeyByZXR1cm4ge307IH1cblxuICAgIGlmIChBcnJheS5pc0FycmF5KHgpIHx8IHR5cGVvZiB4ID09PSAnc3RyaW5nJykge1xuICAgICAgeCA9IHsgW0xJVEVSQUxfU1RSSU5HX0tFWV06IHggfTtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHggPT09ICdvYmplY3QnICYmIHggIT09IG51bGwpIHtcbiAgICAgIC8vIFR1cm4geyBBV1M6IFthLCBiXSwgU2VydmljZTogW2NdIH0gaW50byBbeyBBV1M6IGEgfSwgeyBBV1M6IGIgfSwgeyBTZXJ2aWNlOiBjIH1dXG4gICAgICBjb25zdCBpbmRpdmlkdWFsUHJpbmNpcGFscyA9IE9iamVjdC5lbnRyaWVzKHgpLmZsYXRNYXAoKFtwcmluY2lwYWxUeXBlLCB2YWx1ZV0pID0+IGZvcmNlQXJyYXkodmFsdWUpLm1hcCh2ID0+ICh7IFtwcmluY2lwYWxUeXBlXTogdiB9KSkpO1xuICAgICAgcmV0dXJuIGlhbVNldChpbmRpdmlkdWFsUHJpbmNpcGFscyk7XG4gICAgfVxuICAgIHJldHVybiB7fTtcbiAgfVxufVxuXG4vKipcbiAqIFJldHVybiAndHJ1ZScgaWYgdGhlIHR3byBwcmluY2lwYWxzIGFyZSB1bm1lcmdlYWJsZVxuICpcbiAqIFRoaXMgb25seSBoYXBwZW5zIGlmIG9uZSBvZiB0aGVtIGlzIGEgbGl0ZXJhbCwgdW50eXBlZCBwcmluY2lwYWwgKHR5cGljYWxseSxcbiAqIGBQcmluY2lwYWw6ICcqJ2ApIGFuZCB0aGUgb3RoZXIgb25lIGlzIHR5cGVkLlxuICpcbiAqIGBQcmluY2lwYWw6ICcqJ2AgYmVoYXZlcyBzdWJ0bHkgZGlmZmVyZW50IHRoYW4gYFByaW5jaXBhbDogeyBBV1M6ICcqJyB9YCBhbmQgbXVzdFxuICogdGhlcmVmb3JlIGJlIHByZXNlcnZlZC5cbiAqL1xuZnVuY3Rpb24gdW5tZXJnZWFibGVQcmluY2lwYWxzKGE6IENvbXBhcmFibGVTdGF0ZW1lbnQsIGI6IENvbXBhcmFibGVTdGF0ZW1lbnQpIHtcbiAgY29uc3QgYUhhc0xpdGVyYWwgPSBPYmplY3QudmFsdWVzKGEucHJpbmNpcGFsKS5zb21lKHYgPT4gTElURVJBTF9TVFJJTkdfS0VZIGluIHYpO1xuICBjb25zdCBiSGFzTGl0ZXJhbCA9IE9iamVjdC52YWx1ZXMoYi5wcmluY2lwYWwpLnNvbWUodiA9PiBMSVRFUkFMX1NUUklOR19LRVkgaW4gdik7XG4gIHJldHVybiBhSGFzTGl0ZXJhbCAhPT0gYkhhc0xpdGVyYWw7XG59XG5cbi8qKlxuICogVHVybiBhIENvbXBhcmFibGVTdGF0ZW1lbnQgYmFjayBpbnRvIGEgU3RhdGVtZW50U2NoZW1hXG4gKi9cbmZ1bmN0aW9uIHJlbmRlckNvbXBhcmFibGUoczogQ29tcGFyYWJsZVN0YXRlbWVudCk6IFN0YXRlbWVudFNjaGVtYSB7XG4gIHJldHVybiBub3JtYWxpemVTdGF0ZW1lbnQoe1xuICAgIEVmZmVjdDogcy5lZmZlY3QsXG4gICAgU2lkOiBzLnNpZCxcbiAgICBDb25kaXRpb246IHMuY29uZGl0aW9uVmFsdWUsXG4gICAgQWN0aW9uOiByZW5kZXJTZXQocy5hY3Rpb24pLFxuICAgIE5vdEFjdGlvbjogcmVuZGVyU2V0KHMubm90QWN0aW9uKSxcbiAgICBSZXNvdXJjZTogcmVuZGVyU2V0KHMucmVzb3VyY2UpLFxuICAgIE5vdFJlc291cmNlOiByZW5kZXJTZXQocy5ub3RSZXNvdXJjZSksXG4gICAgUHJpbmNpcGFsOiByZW5kZXJQcmluY2lwYWxTZXQocy5wcmluY2lwYWwpLFxuICAgIE5vdFByaW5jaXBhbDogcmVuZGVyUHJpbmNpcGFsU2V0KHMubm90UHJpbmNpcGFsKSxcbiAgfSk7XG5cbiAgZnVuY3Rpb24gcmVuZGVyU2V0KHg6IElhbVZhbHVlU2V0KTogSWFtVmFsdWUgfCB1bmRlZmluZWQge1xuICAgIC8vIFJldHVybiBhcyBzb3J0ZWQgYXJyYXkgc28gdGhhdCB3ZSBub3JtYWxpemVcbiAgICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoeCkuc29ydCgpO1xuICAgIHJldHVybiBrZXlzLmxlbmd0aCA+IDAgPyBrZXlzLm1hcChrZXkgPT4geFtrZXldKSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHJlbmRlclByaW5jaXBhbFNldCh4OiBJYW1WYWx1ZVNldCk6IFJlY29yZDxzdHJpbmcsIElhbVZhbHVlPiB7XG4gICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKHgpLnNvcnQoKTtcbiAgICAvLyBUaGUgZmlyc3QgbGV2ZWwgd2lsbCBiZSBhbiBvYmplY3RcbiAgICBjb25zdCByZXQ6IFJlY29yZDxzdHJpbmcsIElhbVZhbHVlPiA9IHt9O1xuICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICAgIGNvbnN0IHByaW5jaXBhbCA9IHhba2V5XTtcbiAgICAgIGlmIChwcmluY2lwYWwgPT0gbnVsbCB8fCB0eXBlb2YgcHJpbmNpcGFsICE9PSAnb2JqZWN0Jykge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFByaW5jaXBhbCBzaG91bGQgYmUgYW4gb2JqZWN0IHdpdGggYSBwcmluY2lwYWwgdHlwZSwgZ290OiAke3ByaW5jaXBhbH1gKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHByaW5jaXBhbEtleXMgPSBPYmplY3Qua2V5cyhwcmluY2lwYWwpO1xuICAgICAgaWYgKHByaW5jaXBhbEtleXMubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgUHJpbmNpcGFsIHNob3VsZCBiZSBhbiBvYmplY3Qgd2l0aCAxIGtleSwgZm91bmQga2V5czogJHtwcmluY2lwYWxLZXlzfWApO1xuICAgICAgfVxuICAgICAgY29uc3QgcGsgPSBwcmluY2lwYWxLZXlzWzBdO1xuICAgICAgaWYgKCFyZXRbcGtdKSB7XG4gICAgICAgIHJldFtwa10gPSBbXTtcbiAgICAgIH1cbiAgICAgIChyZXRbcGtdIGFzIElhbVZhbHVlW10pLnB1c2gocHJpbmNpcGFsW3BrXSk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH1cbn1cblxuLyoqXG4gKiBBbiBhbmFseXplZCB2ZXJzaW9uIG9mIGEgc3RhdGVtZW50IHRoYXQgbWFrZXMgaXQgZWFzaWVyIHRvIGRvIGNvbXBhcmlzb25zIGFuZCBtZXJnaW5nIG9uXG4gKlxuICogV2Ugd2lsbCBzdHJpbmdpZnkgcGFydHMgb2YgdGhlIHN0YXRlbWVudDogY29tcGFyaXNvbnMgYXJlIGRvbmUgb24gdGhlIHN0cmluZ3MsIHRoZSBvcmlnaW5hbFxuICogdmFsdWVzIGFyZSByZXRhaW5lZCBzbyB3ZSBjYW4gc3RpdGNoIHRoZW0gYmFjayB0b2dldGhlciBpbnRvIGEgcmVhbCBwb2xpY3kuXG4gKi9cbmludGVyZmFjZSBDb21wYXJhYmxlU3RhdGVtZW50IHtcbiAgcmVhZG9ubHkgZWZmZWN0Pzogc3RyaW5nO1xuICByZWFkb25seSBzaWQ/OiBzdHJpbmc7XG5cbiAgcmVhZG9ubHkgcHJpbmNpcGFsOiBJYW1WYWx1ZVNldDtcbiAgcmVhZG9ubHkgbm90UHJpbmNpcGFsOiBJYW1WYWx1ZVNldDtcbiAgcmVhZG9ubHkgYWN0aW9uOiBJYW1WYWx1ZVNldDtcbiAgcmVhZG9ubHkgbm90QWN0aW9uOiBJYW1WYWx1ZVNldDtcbiAgcmVhZG9ubHkgcmVzb3VyY2U6IElhbVZhbHVlU2V0O1xuICByZWFkb25seSBub3RSZXNvdXJjZTogSWFtVmFsdWVTZXQ7XG5cbiAgcmVhZG9ubHkgY29uZGl0aW9uU3RyaW5nOiBzdHJpbmc7XG4gIHJlYWRvbmx5IGNvbmRpdGlvblZhbHVlOiBhbnk7XG59XG5cbi8qKlxuICogQSBjb2xsZWN0aW9uIG9mIGNvbXBhcmFibGUgSUFNIHZhbHVlc1xuICpcbiAqIEVhY2ggdmFsdWUgaXMgaW5kZXhlZCBieSBpdHMgc3RyaW5naWZpZWQgdmFsdWUsIG1hcHBpbmcgdG8gaXRzIG9yaWdpbmFsIHZhbHVlLlxuICogVGhpcyBhbGxvd3MgdXMgdG8gY29tcGFyZSB2YWx1ZXMgcXVpY2tseSBhbmQgZWFzaWx5IChldmVuIGlmIHRoZXkgYXJlIGNvbXBsZXgpLFxuICogd2hpbGUgYWxzbyBiZWluZyBhYmxlIHRvIGRlZHVwbGljYXRlIHRoZSBvcmlnaW5hbHMuXG4gKi9cbnR5cGUgSWFtVmFsdWVTZXQgPSBSZWNvcmQ8c3RyaW5nLCBhbnk+O1xuXG4vKipcbiAqIFdoZXRoZXIgdGhlIGdpdmVuIHNldHMgYXJlIGVxdWFsXG4gKi9cbmZ1bmN0aW9uIHNldEVxdWFsKGE6IElhbVZhbHVlU2V0LCBiOiBJYW1WYWx1ZVNldCkge1xuICBjb25zdCBrZXlzQSA9IE9iamVjdC5rZXlzKGEpO1xuICBjb25zdCBrZXlzQiA9IE9iamVjdC5rZXlzKGIpO1xuICByZXR1cm4ga2V5c0EubGVuZ3RoID09PSBrZXlzQi5sZW5ndGggJiYga2V5c0EuZXZlcnkoayA9PiBrIGluIGIpO1xufVxuXG4vKipcbiAqIE1lcmdlIHR3byBJQU0gdmFsdWUgc2V0c1xuICovXG5mdW5jdGlvbiBzZXRNZXJnZSh4OiBJYW1WYWx1ZVNldCwgeTogSWFtVmFsdWVTZXQpOiBJYW1WYWx1ZVNldCB7XG4gIHJldHVybiB7IC4uLngsIC4uLnkgfTtcbn1cblxuZnVuY3Rpb24gbWtkaWN0PEE+KHhzOiBBcnJheTxbc3RyaW5nLCBBXT4pOiBSZWNvcmQ8c3RyaW5nLCBBPiB7XG4gIGNvbnN0IHJldDogUmVjb3JkPHN0cmluZywgQT4gPSB7fTtcbiAgZm9yIChjb25zdCB4IG9mIHhzKSB7XG4gICAgcmV0W3hbMF1dID0geFsxXTtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuIl19
\No newline at end of file