1 | ;
|
2 | // IAM Statement merging
|
3 | //
|
4 | // See docs/policy-merging.als for a formal model of the logic
|
5 | // implemented here.
|
6 | Object.defineProperty(exports, "__esModule", { value: true });
|
7 | exports.mergeStatements = void 0;
|
8 | const util_1 = require("../util");
|
9 | const 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 | */
|
18 | function 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 | }
|
45 | exports.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 | */
|
58 | function 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 | */
|
98 | function 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 | */
|
144 | function 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 | */
|
152 | function 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 | */
|
194 | function 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 | */
|
202 | function setMerge(x, y) {
|
203 | return { ...x, ...y };
|
204 | }
|
205 | function 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 |