sliftutils 1.7.129 → 1.7.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/misc/dist/ownIPs.ts.cache +30 -4
  2. package/misc/dist/strings.ts.cache +2 -2
  3. package/misc/https/dist/certs.ts.cache +2 -2
  4. package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
  5. package/misc/ownIPs.ts +29 -1
  6. package/package.json +1 -1
  7. package/security/authorizedKeys/daemon/dist/paths.ts.cache +3 -6
  8. package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
  9. package/security/authorizedKeys/daemon/dist/state.ts.cache +5 -3
  10. package/security/authorizedKeys/daemon/paths.ts +0 -3
  11. package/security/authorizedKeys/daemon/revocation.ts +0 -0
  12. package/security/authorizedKeys/daemon/state.ts +4 -8
  13. package/security/authorizedKeys/dist/keysRepo.ts.cache +111 -0
  14. package/security/authorizedKeys/dist/secureSSH.ts.cache +147 -71
  15. package/security/authorizedKeys/dist/unrevoke.ts.cache +70 -51
  16. package/security/authorizedKeys/keysRepo.ts +111 -0
  17. package/security/authorizedKeys/secureSSH.ts +28 -38
  18. package/security/authorizedKeys/unrevoke.ts +9 -36
  19. package/security/machines/addMachine.ts +4 -3
  20. package/security/machines/dist/identity.ts.cache +2 -2
  21. package/security/machines/dist/machines.ts.cache +36 -94
  22. package/security/machines/machines.ts +39 -90
  23. package/security/machines/trustServer.ts +5 -3
  24. package/security/notifications/dist/remoteWebhook.ts.cache +78 -0
  25. package/security/notifications/dist/setupNotify.ts.cache +39 -0
  26. package/security/signedFiles/dist/signFiles.ts.cache +8 -10
  27. package/security/signedFiles/signFiles.ts +6 -10
  28. package/security/machines/trustState.ts +0 -53
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
- //exports.main = exports.revokedKeysInRepo = exports.readRemoteRevocations = exports.revocationIP = void 0;
6
+ //exports.main = exports.revokedKeysInRepo = exports.readRemoteRevocations = exports.revocationIdentity = exports.revocationIP = void 0;
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
8
  const os_1 = __importDefault(require("os"));
9
9
  const path_1 = __importDefault(require("path"));
@@ -13,8 +13,9 @@ const revokeSource_1 = require("./revokeSource");
13
13
  const sources_1 = require("./sources");
14
14
  const signFiles_1 = require("../signedFiles/signFiles");
15
15
  const authorizedKeys_2 = require("./authorizedKeys");
16
- const paths_1 = require("../helpers/paths");
17
16
  const spawn_1 = require("../helpers/spawn");
17
+ const machines_1 = require("../machines/machines");
18
+ const keysRepo_1 = require("./keysRepo");
18
19
  const UNREVOKES_DIR = "unrevoked";
19
20
  const REVOCATIONS_DIR = "revocations";
20
21
  const GIT_KEYWORD = "git";
@@ -22,8 +23,8 @@ const COMMIT_MESSAGE = "unrevoke keys";
22
23
  const USAGE = `Usage: yarn unrevoke [keys-repo] [${GIT_KEYWORD}]
23
24
 
24
25
  Run this in a keys repo, or name one. It reads that repo's revoke repo and writes one unrevoke file
25
- naming every revocation in it, so the keys are accepted again once each machine's hour long wait
26
- passes. It signs the result, and with ${GIT_KEYWORD} it commits and pushes it too.
26
+ naming every revocation in it, so the keys are accepted again as each machine picks it up. It signs
27
+ the result, and with ${GIT_KEYWORD} it commits and pushes it too.
27
28
 
28
29
  Keys that were revoked should normally be deleted from the repo instead. Unrevoking only matters
29
30
  for a key you still want.`;
@@ -33,6 +34,11 @@ function revocationIP(revocation) {
33
34
  return revocation.ip || ((_a = revocation.attempt) === null || _a === void 0 ? void 0 : _a.ip) || "";
34
35
  }
35
36
  exports.revocationIP = revocationIP;
37
+ /** What the revocation is about, which is what an unrevoke has to name to undo it. */
38
+ function revocationIdentity(revocation) {
39
+ return revocation.fingerprint || revocation.machineId || "";
40
+ }
41
+ exports.revocationIdentity = revocationIdentity;
36
42
  /** Every revocation the revoke repo lists. Cloned read only into a temp directory.
37
43
 
38
44
  A person running this has their own access to the repo, so their credentials are what is used.
@@ -87,7 +93,7 @@ async function revokedKeysInRepo(config) {
87
93
  }
88
94
  let parsed = JSON.parse(await promises_1.default.readFile(path_1.default.join(directory, name), "utf8"));
89
95
  for (let allowed of parsed.allowed || []) {
90
- unrevoked.add(`${allowed.fingerprint} ${allowed.ip}`);
96
+ unrevoked.add(`${allowed.fingerprint || allowed.machineId} ${allowed.ip}`);
91
97
  }
92
98
  // Named ids, for the unrevokes written before this was about pairs.
93
99
  for (let revocationId of parsed.revocationIds || []) {
@@ -139,30 +145,38 @@ async function allowAddressesInRepo(config) {
139
145
  }
140
146
  return added;
141
147
  }
142
- /** The repo named, or the one we are standing in. Checked the same way securessh checks it: a git
143
- repo that actually holds keys and has an origin to clone from. */
144
- async function resolveKeysRepo(named) {
145
- let cwd = named && (0, paths_1.expandHome)(named) || undefined;
146
- // spawnPromise rather than runPromise, because these two are read for their value. runPromise
147
- // returns stdout and stderr joined, so one git warning ends up glued to the front of the path.
148
- let topLevel = await (0, spawn_1.spawnPromise)({ command: "git", args: ["rev-parse", "--show-toplevel"], cwd });
149
- let repoPath = topLevel.stdout.trim();
150
- if (topLevel.status !== 0 || !repoPath) {
151
- throw new Error(`Expected ${named || "the current directory"} to be inside a git repo, it is not.\n`
152
- + `${(topLevel.stdout + topLevel.stderr).trim()}\n${USAGE}`);
153
- }
154
- try {
155
- await (0, authorizedKeys_2.readRepoKeys)(repoPath);
156
- }
157
- catch (e) {
158
- throw new Error(`Expected ${repoPath} to be a keys repo, it holds no keys.\n${e}\n${USAGE}`);
148
+ /** Puts each machine's addresses back into its own file, which is the machine equivalent of adding
149
+ an address to a key's from= list: without it the machine is allowed again in principle and
150
+ still rejected on sight, which revokes it once more. */
151
+ async function allowAddressesForMachines(config) {
152
+ let { repoPath, revocations } = config;
153
+ let added = new Map();
154
+ // Read the whole list, change what these revocations are about, write it back. Setting is by
155
+ // the whole set, so writing one machine at a time would delete every other machine.
156
+ let machines = await (0, machines_1.getMachines)(repoPath);
157
+ for (let revocation of revocations) {
158
+ let machineId = revocation.machineId;
159
+ let ip = revocationIP(revocation);
160
+ if (!machineId || !ip) {
161
+ continue;
162
+ }
163
+ let existing = machines.find(machine => machine.machineId === machineId);
164
+ if (!existing) {
165
+ // Removed from the repo since it was revoked, so there is nothing to allow. Deleting a
166
+ // machine is the stronger statement and it stands.
167
+ console.log(`machines/${machineId}.json is not in this repo, so ${ip} was not added to it`);
168
+ continue;
169
+ }
170
+ if (existing.ips.includes(ip)) {
171
+ continue;
172
+ }
173
+ existing.ips = [...existing.ips, ip];
174
+ added.set(machineId, [...(added.get(machineId) || []), ip]);
159
175
  }
160
- let origin = await (0, spawn_1.spawnPromise)({ command: "git", args: ["remote", "get-url", "origin"], cwd: repoPath });
161
- let originURL = origin.stdout.trim();
162
- if (origin.status !== 0 || !originURL) {
163
- throw new Error(`Expected ${repoPath} to have an origin remote, it has none.\n${USAGE}`);
176
+ if (added.size) {
177
+ await (0, machines_1.setMachines)({ repoPath, machines });
164
178
  }
165
- return { repoPath, originURL };
179
+ return added;
166
180
  }
167
181
  async function main() {
168
182
  let argv = process.argv.slice(2);
@@ -171,7 +185,7 @@ async function main() {
171
185
  if (positional.length > 1) {
172
186
  throw new Error(`Expected at most a keys repo, was ${positional.length} argument(s)\n${USAGE}`);
173
187
  }
174
- let { repoPath, originURL } = await resolveKeysRepo(positional[0]);
188
+ let { repoPath, sourceURL: originURL } = await (0, keysRepo_1.resolveKeysRepo)(positional[0]);
175
189
  let revocations = await readRemoteRevocations({ sourceURL: originURL });
176
190
  if (!revocations.length) {
177
191
  console.log(`${(0, revokeSource_1.revokeRepoURL)(originURL)} lists no revocations, so there is nothing to undo.`);
@@ -189,11 +203,13 @@ async function main() {
189
203
  // still revoked the moment it is used from another.
190
204
  allowed: revocations.map(revocation => ({
191
205
  fingerprint: revocation.fingerprint,
206
+ machineId: revocation.machineId,
192
207
  ip: revocationIP(revocation),
193
208
  })),
194
209
  revocations: revocations.map(revocation => ({
195
210
  revocationId: revocation.revocationId,
196
211
  fingerprint: revocation.fingerprint,
212
+ machineId: revocation.machineId,
197
213
  ip: revocationIP(revocation),
198
214
  revokedAt: revocation.revokedAt,
199
215
  revokedBy: revocation.revokedBy,
@@ -208,56 +224,59 @@ async function main() {
208
224
  keysByFingerprint.set((0, authorizedKeys_1.keyFingerprint)(key), key);
209
225
  }
210
226
  let describeKey = (revocation) => {
211
- let key = keysByFingerprint.get(revocation.fingerprint) || revocation.key || "";
227
+ let key = keysByFingerprint.get(revocation.fingerprint || "") || revocation.key || "";
212
228
  return key && (0, authorizedKeys_1.summarizeKey)(key) || `a key no longer in this repo (${revocation.fingerprint})`;
213
229
  };
214
- let addressesByFingerprint = new Map();
230
+ let addressesByIdentity = new Map();
215
231
  for (let revocation of revocations) {
216
232
  let ip = revocationIP(revocation);
217
- let existing = addressesByFingerprint.get(revocation.fingerprint) || [];
233
+ let identity = revocationIdentity(revocation);
234
+ let existing = addressesByIdentity.get(identity) || [];
218
235
  if (ip && !existing.includes(ip)) {
219
236
  existing.push(ip);
220
237
  }
221
- addressesByFingerprint.set(revocation.fingerprint, existing);
238
+ addressesByIdentity.set(identity, existing);
222
239
  }
223
- // Cancelling the revocation on its own would leave sshd refusing that address and the machines
224
- // revoking the key all over again, so the addresses go into the key's from= here. We are in
225
- // the repo that owns authorized_keys, so there is nothing to hand back to whoever ran this.
226
- let added = await allowAddressesInRepo({ repoPath, addressesByFingerprint });
240
+ // Cancelling the revocation on its own would leave sshd refusing that address, and the machines
241
+ // revoking all over again, so the addresses go into the key's from= list and into the machine's
242
+ // own file here. We are in the repo that owns both, so there is nothing to hand back to whoever
243
+ // ran this.
244
+ let added = await allowAddressesInRepo({ repoPath, addressesByFingerprint: addressesByIdentity });
245
+ let addedForMachines = await allowAddressesForMachines({ repoPath, revocations });
227
246
  console.log("");
228
- for (let [fingerprint, addresses] of addressesByFingerprint) {
229
- let revocation = revocations.find(entry => entry.fingerprint === fingerprint);
230
- console.log(`Unfreezing ${describeKey(revocation)}`);
247
+ for (let [identity, addresses] of addressesByIdentity) {
248
+ let entries = revocations.filter(entry => revocationIdentity(entry) === identity);
249
+ let machineId = entries[0].machineId;
250
+ console.log(`Unfreezing ${machineId && `machine ${machineId}` || describeKey(entries[0])}`);
231
251
  console.log(`Allowing IP ${addresses.join(", ") || "(no address recorded)"}`);
232
- let addedHere = added.get(fingerprint) || [];
252
+ let addedHere = machineId && addedForMachines.get(machineId) || added.get(identity) || [];
233
253
  if (addedHere.length) {
234
- console.log(` added to that key's from= list in authorized_keys: ${addedHere.join(", ")}`);
254
+ let where = machineId && `machines/${machineId}.json` || `that key's from= list in authorized_keys`;
255
+ console.log(` added to ${where}: ${addedHere.join(", ")}`);
235
256
  }
236
257
  else {
237
- console.log(` that key's from= list already allowed ${addresses.join(", ") ? "them" : "everything"}`);
258
+ console.log(` already allowed from ${addresses.join(", ") || "everywhere"}`);
238
259
  }
239
- for (let entry of revocations.filter(entry => entry.fingerprint === fingerprint)) {
260
+ for (let entry of entries) {
240
261
  console.log(` frozen by ${entry.revokedBy || "?"} ${entry.revokedAt || "at an unrecorded time"}`);
241
262
  }
242
263
  console.log("");
243
264
  }
244
- console.log(`Every other address stays frozen, and one of these keys used from anywhere else`);
245
- console.log(`is frozen again.`);
265
+ console.log(`Every other address stays frozen, and any of these used from anywhere else is`);
266
+ console.log(`frozen again.`);
246
267
  // Signed here rather than left as a step to remember. An unrevoke nobody signed does nothing at
247
268
  // all, and the repo would sit there looking done while every machine ignored it.
248
269
  await (0, signFiles_1.signRepo)({ repoPath });
249
270
  if (!pushToGit) {
250
- console.log(`\nCommit and push it, and each machine will wait an hour after seeing it before`);
251
- console.log(`those keys work again:`);
271
+ console.log(`\nCommit and push it, and those keys work again as each machine picks it up:`);
252
272
  console.log(`\`\`\`\ngit add -A\ngit commit -m "${COMMIT_MESSAGE}"\ngit push\n\`\`\``);
253
273
  return;
254
274
  }
255
275
  await (0, runPromise_1.runPromise)(`git add -A`, { cwd: repoPath });
256
276
  await (0, runPromise_1.runPromise)(`git commit -m "${COMMIT_MESSAGE}"`, { cwd: repoPath });
257
277
  await (0, runPromise_1.runPromise)(`git push`, { cwd: repoPath });
258
- console.log(`\nCommitted and pushed. Each machine waits an hour after seeing it before those`);
259
- console.log(`keys work again.`);
278
+ console.log(`\nCommitted and pushed. Those keys work again as each machine picks it up.`);
260
279
  }
261
280
  exports.main = main;
262
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5yZXZva2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1bnJldm9rZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwyREFBNkI7QUFDN0IsNENBQW9CO0FBQ3BCLGdEQUF3QjtBQUN4QiwrREFBNEQ7QUFDNUQscURBQStGO0FBQy9GLGlEQUFnRTtBQUNoRSx1Q0FBMEM7QUFDMUMsd0RBQW9EO0FBQ3BELHFEQUFnRDtBQUNoRCw0Q0FBOEM7QUFDOUMsNENBQWdEO0FBRWhELE1BQU0sYUFBYSxHQUFHLFdBQVcsQ0FBQztBQUNsQyxNQUFNLGVBQWUsR0FBRyxhQUFhLENBQUM7QUFDdEMsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDO0FBQzFCLE1BQU0sY0FBYyxHQUFHLGVBQWUsQ0FBQztBQUN2QyxNQUFNLEtBQUssR0FBRyxxQ0FBcUMsV0FBVzs7Ozt3Q0FJdEIsV0FBVzs7OzBCQUd6QixDQUFDO0FBZTNCLG1FQUFtRTtBQUNuRSxTQUFnQixZQUFZLENBQUMsVUFBc0I7O0lBQy9DLE9BQU8sVUFBVSxDQUFDLEVBQUUsS0FBSSxNQUFBLFVBQVUsQ0FBQyxPQUFPLDBDQUFFLEVBQUUsQ0FBQSxJQUFJLEVBQUUsQ0FBQztBQUN6RCxDQUFDO0FBRkQsb0NBRUM7QUFFRDs7OztrR0FJa0c7QUFDM0YsS0FBSyxVQUFVLHFCQUFxQixDQUFDLE1BQTZCO0lBQ3JFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDM0IsSUFBSSxrQkFBa0IsR0FBRyxNQUFNLGtCQUFFLENBQUMsT0FBTyxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsWUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFDL0UsSUFBSSxRQUFRLEdBQUcsY0FBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUNyRCxJQUFJLFNBQVMsR0FBRyxDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsR0FB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LENBQUMsaUZBQWlGLENBQUMsQ0FBQztJQUMvRixPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUM7QUFDcEMsQ0FBQztBQXRHRCxvQkFzR0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgb3MgZnJvbSBcIm9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgcnVuUHJvbWlzZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL3J1blByb21pc2VcIjtcbmltcG9ydCB7IGFsbG93QWRkcmVzc2VzLCBrZXlGaW5nZXJwcmludCwgbm9ybWFsaXplS2V5cywgc3VtbWFyaXplS2V5IH0gZnJvbSBcIi4vYXV0aG9yaXplZEtleXNcIjtcbmltcG9ydCB7IGRlcml2ZVJldm9rZUtleSwgcmV2b2tlUmVwb1VSTCB9IGZyb20gXCIuL3Jldm9rZVNvdXJjZVwiO1xuaW1wb3J0IHsgZmluZFNvdXJjZUtleSB9IGZyb20gXCIuL3NvdXJjZXNcIjtcbmltcG9ydCB7IHNpZ25SZXBvIH0gZnJvbSBcIi4uL3NpZ25lZEZpbGVzL3NpZ25GaWxlc1wiO1xuaW1wb3J0IHsgcmVhZFJlcG9LZXlzIH0gZnJvbSBcIi4vYXV0aG9yaXplZEtleXNcIjtcbmltcG9ydCB7IGV4cGFuZEhvbWUgfSBmcm9tIFwiLi4vaGVscGVycy9wYXRoc1wiO1xuaW1wb3J0IHsgc3Bhd25Qcm9taXNlIH0gZnJvbSBcIi4uL2hlbHBlcnMvc3Bhd25cIjtcblxuY29uc3QgVU5SRVZPS0VTX0RJUiA9IFwidW5yZXZva2VkXCI7XG5jb25zdCBSRVZPQ0FUSU9OU19ESVIgPSBcInJldm9jYXRpb25zXCI7XG5jb25zdCBHSVRfS0VZV09SRCA9IFwiZ2l0XCI7XG5jb25zdCBDT01NSVRfTUVTU0FHRSA9IFwidW5yZXZva2Uga2V5c1wiO1xuY29uc3QgVVNBR0UgPSBgVXNhZ2U6IHlhcm4gdW5yZXZva2UgW2tleXMtcmVwb10gWyR7R0lUX0tFWVdPUkR9XVxuXG5SdW4gdGhpcyBpbiBhIGtleXMgcmVwbywgb3IgbmFtZSBvbmUuIEl0IHJlYWRzIHRoYXQgcmVwbydzIHJldm9rZSByZXBvIGFuZCB3cml0ZXMgb25lIHVucmV2b2tlIGZpbGVcbm5hbWluZyBldmVyeSByZXZvY2F0aW9uIGluIGl0LCBzbyB0aGUga2V5cyBhcmUgYWNjZXB0ZWQgYWdhaW4gb25jZSBlYWNoIG1hY2hpbmUncyBob3VyIGxvbmcgd2FpdFxucGFzc2VzLiBJdCBzaWducyB0aGUgcmVzdWx0LCBhbmQgd2l0aCAke0dJVF9LRVlXT1JEfSBpdCBjb21taXRzIGFuZCBwdXNoZXMgaXQgdG9vLlxuXG5LZXlzIHRoYXQgd2VyZSByZXZva2VkIHNob3VsZCBub3JtYWxseSBiZSBkZWxldGVkIGZyb20gdGhlIHJlcG8gaW5zdGVhZC4gVW5yZXZva2luZyBvbmx5IG1hdHRlcnNcbmZvciBhIGtleSB5b3Ugc3RpbGwgd2FudC5gO1xuXG5leHBvcnQgdHlwZSBSZXZvY2F0aW9uID0ge1xuICAgIHJldm9jYXRpb25JZDogc3RyaW5nO1xuICAgIGZpbmdlcnByaW50OiBzdHJpbmc7XG4gICAgLy8gVGhlIGFkZHJlc3MgdGhlIGtleSB3YXMgdXNlZCBmcm9tLiBBIHJldm9jYXRpb24gaXMgYWJvdXQgdGhpcyBwYWlyLCBhbmQgYW4gdW5yZXZva2UgdW5kb2VzXG4gICAgLy8gaXQgYnkgYWxsb3dpbmcgdGhhdCBzYW1lIHBhaXIgLSB3aGljaCBpcyB3aHkgdW5yZXZva2luZyBuZXZlciBtYWtlcyBhIGtleSB1bnJldm9rYWJsZTogdXNlZFxuICAgIC8vIGZyb20gc29tZSBvdGhlciBhZGRyZXNzLCBpdCBpcyByZXZva2VkIGFnYWluLlxuICAgIGlwPzogc3RyaW5nO1xuICAgIGtleT86IHN0cmluZztcbiAgICByZXZva2VkQXQ/OiBzdHJpbmc7XG4gICAgcmV2b2tlZEJ5Pzogc3RyaW5nO1xuICAgIGF0dGVtcHQ/OiB7IGlwPzogc3RyaW5nOyB1c2VyPzogc3RyaW5nOyByZXF1aXJlZD86IHN0cmluZyB9O1xufTtcblxuLyoqIE9sZGVyIHJldm9jYXRpb24gZmlsZXMgY2FycnkgdGhlIGFkZHJlc3MgdW5kZXIgYXR0ZW1wdCBvbmx5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJldm9jYXRpb25JUChyZXZvY2F0aW9uOiBSZXZvY2F0aW9uKSB7XG4gICAgcmV0dXJuIHJldm9jYXRpb24uaXAgfHwgcmV2b2NhdGlvbi5hdHRlbXB0Py5pcCB8fCBcIlwiO1xufVxuXG4vKiogRXZlcnkgcmV2b2NhdGlvbiB0aGUgcmV2b2tlIHJlcG8gbGlzdHMuIENsb25lZCByZWFkIG9ubHkgaW50byBhIHRlbXAgZGlyZWN0b3J5LlxuXG4gICAgQSBwZXJzb24gcnVubmluZyB0aGlzIGhhcyB0aGVpciBvd24gYWNjZXNzIHRvIHRoZSByZXBvLCBzbyB0aGVpciBjcmVkZW50aWFscyBhcmUgd2hhdCBpcyB1c2VkLlxuICAgIE9uIGEgbWFjaGluZSB0aGF0IGlzIGFscmVhZHkgYSBwb3J0c2VjdXJlIGhvc3QgdGhlcmUgbWF5IGJlIG5vIHN1Y2ggY3JlZGVudGlhbHMsIGJ1dCB0aGUgc291cmNlXG4gICAgZGVwbG95IGtleSBpcyByaWdodCB0aGVyZSwgYW5kIHRoZSBrZXkgZGVyaXZlZCBmcm9tIGl0IGlzIG9uZSB0aGF0IHJlcG8gZGVmaW5pdGVseSBhY2NlcHRzLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRSZW1vdGVSZXZvY2F0aW9ucyhjb25maWc6IHsgc291cmNlVVJMOiBzdHJpbmcgfSkge1xuICAgIGxldCB7IHNvdXJjZVVSTCB9ID0gY29uZmlnO1xuICAgIGxldCB0ZW1wb3JhcnlEaXJlY3RvcnkgPSBhd2FpdCBmcy5ta2R0ZW1wKHBhdGguam9pbihvcy50bXBkaXIoKSwgXCJ1bnJldm9rZS1cIikpO1xuICAgIGxldCByZXBvUGF0aCA9IHBhdGguam9pbih0ZW1wb3JhcnlEaXJlY3RvcnksIFwicmVwb1wiKTtcbiAgICBsZXQgY2xvbmVBcmdzID0gW1wiY2xvbmVcIiwgXCItLWRlcHRoXCIsIFwiMVwiLCByZXZva2VSZXBvVVJMKHNvdXJjZVVSTCksIHJlcG9QYXRoXTtcbiAgICBsZXQgc291cmNlS2V5ID0gYXdhaXQgZmluZFNvdXJjZUtleShzb3VyY2VVUkwpO1xuICAgIGlmIChzb3VyY2VLZXkpIHtcbiAgICAgICAgbGV0IGRlcml2ZWQgPSBkZXJpdmVSZXZva2VLZXkoYXdhaXQgZnMucmVhZEZpbGUoc291cmNlS2V5LCBcInV0ZjhcIikpO1xuICAgICAgICBsZXQgZGVyaXZlZEtleVBhdGggPSBwYXRoLmpvaW4odGVtcG9yYXJ5RGlyZWN0b3J5LCBcImtleVwiKTtcbiAgICAgICAgYXdhaXQgZnMud3JpdGVGaWxlKGRlcml2ZWRLZXlQYXRoLCBkZXJpdmVkLnByaXZhdGVLZXlGaWxlLCB7IG1vZGU6IDBvNjAwIH0pO1xuICAgICAgICBsZXQgc3NoQ29tbWFuZCA9IGBzc2ggLWkgJHtkZXJpdmVkS2V5UGF0aH0gLW8gSWRlbnRpdGllc09ubHk9eWVzIC1vIEJhdGNoTW9kZT15ZXMgLW8gU3RyaWN0SG9zdEtleUNoZWNraW5nPWFjY2VwdC1uZXdgO1xuICAgICAgICBjbG9uZUFyZ3MgPSBbXCItY1wiLCBgY29yZS5zc2hDb21tYW5kPSR7c3NoQ29tbWFuZH1gLCAuLi5jbG9uZUFyZ3NdO1xuICAgIH1cbiAgICBsZXQgY2xvbmUgPSBhd2FpdCBzcGF3blByb21pc2UoeyBjb21tYW5kOiBcImdpdFwiLCBhcmdzOiBjbG9uZUFyZ3MgfSk7XG4gICAgaWYgKGNsb25lLnN0YXR1cyAhPT0gMCkge1xuICAgICAgICBhd2FpdCBmcy5ybSh0ZW1wb3JhcnlEaXJlY3RvcnksIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEV4cGVjdGVkIHRvIGJlIGFibGUgdG8gcmVhZCAke3Jldm9rZVJlcG9VUkwoc291cmNlVVJMKX0uXFxuYFxuICAgICAgICAgICAgKyBgJHsoY2xvbmUuc3Rkb3V0ICsgY2xvbmUuc3RkZXJyKS50cmltKCl9YFxuICAgICAgICApO1xuICAgIH1cbiAgICBsZXQgcmV2b2NhdGlvbnM6IFJldm9jYXRpb25bXSA9IFtdO1xuICAgIGxldCBkaXJlY3RvcnkgPSBwYXRoLmpvaW4ocmVwb1BhdGgsIFJFVk9DQVRJT05TX0RJUik7XG4gICAgdHJ5IHtcbiAgICAgICAgZm9yIChsZXQgbmFtZSBvZiAoYXdhaXQgZnMucmVhZGRpcihkaXJlY3RvcnkpKS5zb3J0KCkpIHtcbiAgICAgICAgICAgIGlmIChuYW1lLmVuZHNXaXRoKFwiLmpzb25cIikpIHtcbiAgICAgICAgICAgICAgICByZXZvY2F0aW9ucy5wdXNoKEpTT04ucGFyc2UoYXdhaXQgZnMucmVhZEZpbGUocGF0aC5qb2luKGRpcmVjdG9yeSwgbmFtZSksIFwidXRmOFwiKSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyBObyByZXZvY2F0aW9ucyBkaXJlY3RvcnkgYXQgYWxsIGp1c3QgbWVhbnMgbm90aGluZyBoYXMgZXZlciBiZWVuIHJldm9rZWQuXG4gICAgfVxuICAgIGF3YWl0IGZzLnJtKHRlbXBvcmFyeURpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIHJldHVybiByZXZvY2F0aW9ucztcbn1cblxuLyoqIFdoaWNoIGtleXMgaW4gYSByZXBvIGFyZSByZXZva2VkLiBXaGF0IHNpZ25maWxlcyBhbmQgc2VjdXJlc3NoIHJlZnVzZSBvdmVyLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJldm9rZWRLZXlzSW5SZXBvKGNvbmZpZzogeyByZXBvUGF0aDogc3RyaW5nOyBzb3VyY2VVUkw6IHN0cmluZyB9KSB7XG4gICAgbGV0IHsgcmVwb1BhdGgsIHNvdXJjZVVSTCB9ID0gY29uZmlnO1xuICAgIGxldCByZXZvY2F0aW9ucyA9IGF3YWl0IHJlYWRSZW1vdGVSZXZvY2F0aW9ucyh7IHNvdXJjZVVSTCB9KTtcbiAgICBsZXQgcmV2b2tlZEZpbmdlcnByaW50cyA9IG5ldyBTZXQocmV2b2NhdGlvbnMubWFwKHJldm9jYXRpb24gPT4gcmV2b2NhdGlvbi5maW5nZXJwcmludCkpO1xuICAgIGxldCB1bnJldm9rZWQgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICB0cnkge1xuICAgICAgICBsZXQgZGlyZWN0b3J5ID0gcGF0aC5qb2luKHJlcG9QYXRoLCBVTlJFVk9LRVNfRElSKTtcbiAgICAgICAgZm9yIChsZXQgbmFtZSBvZiBhd2FpdCBmcy5yZWFkZGlyKGRpcmVjdG9yeSkpIHtcbiAgICAgICAgICAgIGlmICghbmFtZS5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgcGFyc2VkID0gSlNPTi5wYXJzZShhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4oZGlyZWN0b3J5LCBuYW1lKSwgXCJ1dGY4XCIpKTtcbiAgICAgICAgICAgIGZvciAobGV0IGFsbG93ZWQgb2YgcGFyc2VkLmFsbG93ZWQgfHwgW10pIHtcbiAgICAgICAgICAgICAgICB1bnJldm9rZWQuYWRkKGAke2FsbG93ZWQuZmluZ2VycHJpbnR9ICR7YWxsb3dlZC5pcH1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIE5hbWVkIGlkcywgZm9yIHRoZSB1bnJldm9rZXMgd3JpdHRlbiBiZWZvcmUgdGhpcyB3YXMgYWJvdXQgcGFpcnMuXG4gICAgICAgICAgICBmb3IgKGxldCByZXZvY2F0aW9uSWQgb2YgcGFyc2VkLnJldm9jYXRpb25JZHMgfHwgW10pIHtcbiAgICAgICAgICAgICAgICB1bnJldm9rZWQuYWRkKHJldm9jYXRpb25JZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIE5vdGhpbmcgaGFzIGJlZW4gdW5yZXZva2VkLlxuICAgIH1cbiAgICBsZXQgc3RpbGxSZXZva2VkID0gcmV2b2NhdGlvbnMuZmlsdGVyKHJldm9jYXRpb24gPT4gIXVucmV2b2tlZC5oYXMocmV2b2NhdGlvbi5yZXZvY2F0aW9uSWQpXG4gICAgICAgICYmICF1bnJldm9rZWQuaGFzKGAke3Jldm9jYXRpb24uZmluZ2VycHJpbnR9ICR7cmV2b2NhdGlvbklQKHJldm9jYXRpb24pfWApKTtcbiAgICBsZXQga2V5cyA9IG5vcm1hbGl6ZUtleXMoYXdhaXQgZnMucmVhZEZpbGUocGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKSwgXCJ1dGY4XCIpLmNhdGNoKCgpID0+IFwiXCIpKTtcbiAgICByZXR1cm4gc3RpbGxSZXZva2VkXG4gICAgICAgIC5maWx0ZXIocmV2b2NhdGlvbiA9PiBrZXlzLnNvbWUoa2V5ID0+IGtleUZpbmdlcnByaW50KGtleSkgPT09IHJldm9jYXRpb24uZmluZ2VycHJpbnQpKVxuICAgICAgICAubWFwKHJldm9jYXRpb24gPT4gKHsgcmV2b2NhdGlvbiwga2V5OiBrZXlzLmZpbmQoa2V5ID0+IGtleUZpbmdlcnByaW50KGtleSkgPT09IHJldm9jYXRpb24uZmluZ2VycHJpbnQpIHx8IFwiXCIgfSkpO1xufVxuXG4vKiogV3JpdGVzIHRoZSBhZGRyZXNzZXMgaW50byB0aGUgZnJvbT0gbGlzdCBvZiBlYWNoIGtleSBpbiB0aGUgcmVwbydzIGF1dGhvcml6ZWRfa2V5cywgYW5kIHNheXNcbiAgICB3aGljaCBvbmVzIHdlcmUgYWN0dWFsbHkgbmV3LiBPbmx5IHRoZSBsaW5lcyBiZWluZyBjaGFuZ2VkIGFyZSB0b3VjaGVkLCBzbyBjb21tZW50cywgb3JkZXJpbmdcbiAgICBhbmQgYW55IGtleSBub3QgaW52b2x2ZWQgY29tZSBvdXQgb2YgdGhpcyBieXRlIGZvciBieXRlIHRoZSBzYW1lLiAqL1xuYXN5bmMgZnVuY3Rpb24gYWxsb3dBZGRyZXNzZXNJblJlcG8oY29uZmlnOiB7XG4gICAgcmVwb1BhdGg6IHN0cmluZztcbiAgICBhZGRyZXNzZXNCeUZpbmdlcnByaW50OiBNYXA8c3RyaW5nLCBzdHJpbmdbXT47XG59KSB7XG4gICAgbGV0IHsgcmVwb1BhdGgsIGFkZHJlc3Nlc0J5RmluZ2VycHJpbnQgfSA9IGNvbmZpZztcbiAgICBsZXQgYWRkZWQgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gICAgbGV0IGZpbGVQYXRoID0gcGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKTtcbiAgICBsZXQgY29udGVudHM7XG4gICAgdHJ5IHtcbiAgICAgICAgY29udGVudHMgPSBhd2FpdCBmcy5yZWFkRmlsZShmaWxlUGF0aCwgXCJ1dGY4XCIpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgLy8gQSByZXBvIGhvbGRpbmcgaXRzIGtleXMgYXMgc2VwYXJhdGUgLnB1YiBmaWxlcy4gTm90aGluZyB0byBlZGl0IGluIG9uZSBwbGFjZSwgc28gdGhlXG4gICAgICAgIC8vIGNhbGxlcidzIGxpc3RpbmcgaXMgYWxsIHdob2V2ZXIgcmFuIHRoaXMgZ2V0cy5cbiAgICAgICAgY29uc29sZS5sb2coYE5vIGF1dGhvcml6ZWRfa2V5cyBpbiAke3JlcG9QYXRofSwgc28gdGhlIGFkZHJlc3NlcyB3ZXJlIG5vdCBhZGRlZCB0byBhbnkga2V5LmApO1xuICAgICAgICByZXR1cm4gYWRkZWQ7XG4gICAgfVxuICAgIGxldCBsaW5lcyA9IGNvbnRlbnRzLnNwbGl0KFwiXFxuXCIpO1xuICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBsaW5lcy5sZW5ndGg7IGluZGV4KyspIHtcbiAgICAgICAgbGV0IGZpbmdlcnByaW50ID0ga2V5RmluZ2VycHJpbnQobGluZXNbaW5kZXhdKTtcbiAgICAgICAgbGV0IGFkZHJlc3NlcyA9IGZpbmdlcnByaW50ICYmIGFkZHJlc3Nlc0J5RmluZ2VycHJpbnQuZ2V0KGZpbmdlcnByaW50KTtcbiAgICAgICAgaWYgKCFhZGRyZXNzZXMgfHwgIWFkZHJlc3Nlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGxldCByZXN1bHQgPSBhbGxvd0FkZHJlc3NlcyhsaW5lc1tpbmRleF0sIGFkZHJlc3Nlcyk7XG4gICAgICAgIGxpbmVzW2luZGV4XSA9IHJlc3VsdC5rZXlMaW5lO1xuICAgICAgICBhZGRlZC5zZXQoZmluZ2VycHJpbnQsIFsuLi4oYWRkZWQuZ2V0KGZpbmdlcnByaW50KSB8fCBbXSksIC4uLnJlc3VsdC5hZGRlZF0pO1xuICAgIH1cbiAgICBpZiAoWy4uLmFkZGVkLnZhbHVlcygpXS5zb21lKGxpc3QgPT4gbGlzdC5sZW5ndGgpKSB7XG4gICAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShmaWxlUGF0aCwgbGluZXMuam9pbihcIlxcblwiKSk7XG4gICAgfVxuICAgIHJldHVybiBhZGRlZDtcbn1cblxuLyoqIFRoZSByZXBvIG5hbWVkLCBvciB0aGUgb25lIHdlIGFyZSBzdGFuZGluZyBpbi4gQ2hlY2tlZCB0aGUgc2FtZSB3YXkgc2VjdXJlc3NoIGNoZWNrcyBpdDogYSBnaXRcbiAgICByZXBvIHRoYXQgYWN0dWFsbHkgaG9sZHMga2V5cyBhbmQgaGFzIGFuIG9yaWdpbiB0byBjbG9uZSBmcm9tLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVzb2x2ZUtleXNSZXBvKG5hbWVkOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgICBsZXQgY3dkID0gbmFtZWQgJiYgZXhwYW5kSG9tZShuYW1lZCkgfHwgdW5kZWZpbmVkO1xuICAgIC8vIHNwYXduUHJvbWlzZSByYXRoZXIgdGhhbiBydW5Qcm9taXNlLCBiZWNhdXNlIHRoZXNlIHR3byBhcmUgcmVhZCBmb3IgdGhlaXIgdmFsdWUuIHJ1blByb21pc2VcbiAgICAvLyByZXR1cm5zIHN0ZG91dCBhbmQgc3RkZXJyIGpvaW5lZCwgc28gb25lIGdpdCB3YXJuaW5nIGVuZHMgdXAgZ2x1ZWQgdG8gdGhlIGZyb250IG9mIHRoZSBwYXRoLlxuICAgIGxldCB0b3BMZXZlbCA9IGF3YWl0IHNwYXduUHJvbWlzZSh7IGNvbW1hbmQ6IFwiZ2l0XCIsIGFyZ3M6IFtcInJldi1wYXJzZVwiLCBcIi0tc2hvdy10b3BsZXZlbFwiXSwgY3dkIH0pO1xuICAgIGxldCByZXBvUGF0aCA9IHRvcExldmVsLnN0ZG91dC50cmltKCk7XG4gICAgaWYgKHRvcExldmVsLnN0YXR1cyAhPT0gMCB8fCAhcmVwb1BhdGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEV4cGVjdGVkICR7bmFtZWQgfHwgXCJ0aGUgY3VycmVudCBkaXJlY3RvcnlcIn0gdG8gYmUgaW5zaWRlIGEgZ2l0IHJlcG8sIGl0IGlzIG5vdC5cXG5gXG4gICAgICAgICAgICArIGAkeyh0b3BMZXZlbC5zdGRvdXQgKyB0b3BMZXZlbC5zdGRlcnIpLnRyaW0oKX1cXG4ke1VTQUdFfWBcbiAgICAgICAgKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgcmVhZFJlcG9LZXlzKHJlcG9QYXRoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtyZXBvUGF0aH0gdG8gYmUgYSBrZXlzIHJlcG8sIGl0IGhvbGRzIG5vIGtleXMuXFxuJHtlfVxcbiR7VVNBR0V9YCk7XG4gICAgfVxuICAgIGxldCBvcmlnaW4gPSBhd2FpdCBzcGF3blByb21pc2UoeyBjb21tYW5kOiBcImdpdFwiLCBhcmdzOiBbXCJyZW1vdGVcIiwgXCJnZXQtdXJsXCIsIFwib3JpZ2luXCJdLCBjd2Q6IHJlcG9QYXRoIH0pO1xuICAgIGxldCBvcmlnaW5VUkwgPSBvcmlnaW4uc3Rkb3V0LnRyaW0oKTtcbiAgICBpZiAob3JpZ2luLnN0YXR1cyAhPT0gMCB8fCAhb3JpZ2luVVJMKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtyZXBvUGF0aH0gdG8gaGF2ZSBhbiBvcmlnaW4gcmVtb3RlLCBpdCBoYXMgbm9uZS5cXG4ke1VTQUdFfWApO1xuICAgIH1cbiAgICByZXR1cm4geyByZXBvUGF0aCwgb3JpZ2luVVJMIH07XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBtYWluKCkge1xuICAgIGxldCBhcmd2ID0gcHJvY2Vzcy5hcmd2LnNsaWNlKDIpO1xuICAgIGxldCBwdXNoVG9HaXQgPSBhcmd2LmluY2x1ZGVzKEdJVF9LRVlXT1JEKTtcbiAgICBsZXQgcG9zaXRpb25hbCA9IGFyZ3YuZmlsdGVyKGFyZyA9PiBhcmcgIT09IEdJVF9LRVlXT1JEKTtcbiAgICBpZiAocG9zaXRpb25hbC5sZW5ndGggPiAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYXQgbW9zdCBhIGtleXMgcmVwbywgd2FzICR7cG9zaXRpb25hbC5sZW5ndGh9IGFyZ3VtZW50KHMpXFxuJHtVU0FHRX1gKTtcbiAgICB9XG4gICAgbGV0IHsgcmVwb1BhdGgsIG9yaWdpblVSTCB9ID0gYXdhaXQgcmVzb2x2ZUtleXNSZXBvKHBvc2l0aW9uYWxbMF0pO1xuXG4gICAgbGV0IHJldm9jYXRpb25zID0gYXdhaXQgcmVhZFJlbW90ZVJldm9jYXRpb25zKHsgc291cmNlVVJMOiBvcmlnaW5VUkwgfSk7XG4gICAgaWYgKCFyZXZvY2F0aW9ucy5sZW5ndGgpIHtcbiAgICAgICAgY29uc29sZS5sb2coYCR7cmV2b2tlUmVwb1VSTChvcmlnaW5VUkwpfSBsaXN0cyBubyByZXZvY2F0aW9ucywgc28gdGhlcmUgaXMgbm90aGluZyB0byB1bmRvLmApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbGV0IGRpcmVjdG9yeSA9IHBhdGguam9pbihyZXBvUGF0aCwgVU5SRVZPS0VTX0RJUik7XG4gICAgYXdhaXQgZnMubWtkaXIoZGlyZWN0b3J5LCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICBsZXQgc3RhbXAgPSBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCkucmVwbGFjZSgvWzouXS9nLCBcIi1cIik7XG4gICAgbGV0IHVucmV2b2tlSWQgPSBgJHtzdGFtcH0tdW5yZXZva2VgO1xuICAgIGF3YWl0IGZzLndyaXRlRmlsZShwYXRoLmpvaW4oZGlyZWN0b3J5LCBgJHt1bnJldm9rZUlkfS5qc29uYCksIEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgdW5yZXZva2VJZCxcbiAgICAgICAgY3JlYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICAgIC8vIFdoYXQgdGhpcyBmaWxlIHNheXM6IGVhY2ggb2YgdGhlc2Uga2V5cyBpcyBhbGxvd2VkIGZyb20gdGhpcyBhZGRyZXNzLiBQYWlycywgbm90IGtleXMsXG4gICAgICAgIC8vIGFuZCBub3QgYSBibGFua2V0IFwiYWxsb3cgZXZlcnl0aGluZyBhZ2FpblwiIC0gYSBrZXkgZm9yZ2l2ZW4gaGVyZSBmb3Igb25lIGFkZHJlc3MgaXNcbiAgICAgICAgLy8gc3RpbGwgcmV2b2tlZCB0aGUgbW9tZW50IGl0IGlzIHVzZWQgZnJvbSBhbm90aGVyLlxuICAgICAgICBhbGxvd2VkOiByZXZvY2F0aW9ucy5tYXAocmV2b2NhdGlvbiA9PiAoe1xuICAgICAgICAgICAgZmluZ2VycHJpbnQ6IHJldm9jYXRpb24uZmluZ2VycHJpbnQsXG4gICAgICAgICAgICBpcDogcmV2b2NhdGlvbklQKHJldm9jYXRpb24pLFxuICAgICAgICB9KSksXG4gICAgICAgIHJldm9jYXRpb25zOiByZXZvY2F0aW9ucy5tYXAocmV2b2NhdGlvbiA9PiAoe1xuICAgICAgICAgICAgcmV2b2NhdGlvbklkOiByZXZvY2F0aW9uLnJldm9jYXRpb25JZCxcbiAgICAgICAgICAgIGZpbmdlcnByaW50OiByZXZvY2F0aW9uLmZpbmdlcnByaW50LFxuICAgICAgICAgICAgaXA6IHJldm9jYXRpb25JUChyZXZvY2F0aW9uKSxcbiAgICAgICAgICAgIHJldm9rZWRBdDogcmV2b2NhdGlvbi5yZXZva2VkQXQsXG4gICAgICAgICAgICByZXZva2VkQnk6IHJldm9jYXRpb24ucmV2b2tlZEJ5LFxuICAgICAgICAgICAgYXR0ZW1wdDogcmV2b2NhdGlvbi5hdHRlbXB0LFxuICAgICAgICB9KSksXG4gICAgfSwgdW5kZWZpbmVkLCA0KSArIFwiXFxuXCIpO1xuXG4gICAgLy8gTmFtZWQgdGhlIHdheSB0aGUgbm90aWZpY2F0aW9ucyBuYW1lIHRoZW0uIEEgZmluZ2VycHJpbnQgaXMgbm90IGluIGF1dGhvcml6ZWRfa2V5cyBhbmRcbiAgICAvLyBjYW5ub3QgYmUgd29ya2VkIG91dCBieSBleWUsIHNvIG9uIGl0cyBvd24gaXQgdGVsbHMgd2hvZXZlciBpcyByZWFkaW5nIHRoaXMgbm90aGluZyBhYm91dFxuICAgIC8vIHdoaWNoIG9mIHRoZWlyIGtleXMgaXMgYmVpbmcgdGFsa2VkIGFib3V0LlxuICAgIGxldCBrZXlzQnlGaW5nZXJwcmludCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgZm9yIChsZXQga2V5IG9mIGF3YWl0IHJlYWRSZXBvS2V5cyhyZXBvUGF0aCkuY2F0Y2goKCkgPT4gW10gYXMgc3RyaW5nW10pKSB7XG4gICAgICAgIGtleXNCeUZpbmdlcnByaW50LnNldChrZXlGaW5nZXJwcmludChrZXkpLCBrZXkpO1xuICAgIH1cbiAgICBsZXQgZGVzY3JpYmVLZXkgPSAocmV2b2NhdGlvbjogUmV2b2NhdGlvbikgPT4ge1xuICAgICAgICBsZXQga2V5ID0ga2V5c0J5RmluZ2VycHJpbnQuZ2V0KHJldm9jYXRpb24uZmluZ2VycHJpbnQpIHx8IHJldm9jYXRpb24ua2V5IHx8IFwiXCI7XG4gICAgICAgIHJldHVybiBrZXkgJiYgc3VtbWFyaXplS2V5KGtleSkgfHwgYGEga2V5IG5vIGxvbmdlciBpbiB0aGlzIHJlcG8gKCR7cmV2b2NhdGlvbi5maW5nZXJwcmludH0pYDtcbiAgICB9O1xuXG4gICAgbGV0IGFkZHJlc3Nlc0J5RmluZ2VycHJpbnQgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gICAgZm9yIChsZXQgcmV2b2NhdGlvbiBvZiByZXZvY2F0aW9ucykge1xuICAgICAgICBsZXQgaXAgPSByZXZvY2F0aW9uSVAocmV2b2NhdGlvbik7XG4gICAgICAgIGxldCBleGlzdGluZyA9IGFkZHJlc3Nlc0J5RmluZ2VycHJpbnQuZ2V0KHJldm9jYXRpb24uZmluZ2VycHJpbnQpIHx8IFtdO1xuICAgICAgICBpZiAoaXAgJiYgIWV4aXN0aW5nLmluY2x1ZGVzKGlwKSkge1xuICAgICAgICAgICAgZXhpc3RpbmcucHVzaChpcCk7XG4gICAgICAgIH1cbiAgICAgICAgYWRkcmVzc2VzQnlGaW5nZXJwcmludC5zZXQocmV2b2NhdGlvbi5maW5nZXJwcmludCwgZXhpc3RpbmcpO1xuICAgIH1cblxuICAgIC8vIENhbmNlbGxpbmcgdGhlIHJldm9jYXRpb24gb24gaXRzIG93biB3b3VsZCBsZWF2ZSBzc2hkIHJlZnVzaW5nIHRoYXQgYWRkcmVzcyBhbmQgdGhlIG1hY2hpbmVzXG4gICAgLy8gcmV2b2tpbmcgdGhlIGtleSBhbGwgb3ZlciBhZ2Fpbiwgc28gdGhlIGFkZHJlc3NlcyBnbyBpbnRvIHRoZSBrZXkncyBmcm9tPSBoZXJlLiBXZSBhcmUgaW5cbiAgICAvLyB0aGUgcmVwbyB0aGF0IG93bnMgYXV0aG9yaXplZF9rZXlzLCBzbyB0aGVyZSBpcyBub3RoaW5nIHRvIGhhbmQgYmFjayB0byB3aG9ldmVyIHJhbiB0aGlzLlxuICAgIGxldCBhZGRlZCA9IGF3YWl0IGFsbG93QWRkcmVzc2VzSW5SZXBvKHsgcmVwb1BhdGgsIGFkZHJlc3Nlc0J5RmluZ2VycHJpbnQgfSk7XG5cbiAgICBjb25zb2xlLmxvZyhcIlwiKTtcbiAgICBmb3IgKGxldCBbZmluZ2VycHJpbnQsIGFkZHJlc3Nlc10gb2YgYWRkcmVzc2VzQnlGaW5nZXJwcmludCkge1xuICAgICAgICBsZXQgcmV2b2NhdGlvbiA9IHJldm9jYXRpb25zLmZpbmQoZW50cnkgPT4gZW50cnkuZmluZ2VycHJpbnQgPT09IGZpbmdlcnByaW50KSE7XG4gICAgICAgIGNvbnNvbGUubG9nKGBVbmZyZWV6aW5nICR7ZGVzY3JpYmVLZXkocmV2b2NhdGlvbil9YCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBBbGxvd2luZyBJUCAke2FkZHJlc3Nlcy5qb2luKFwiLCBcIikgfHwgXCIobm8gYWRkcmVzcyByZWNvcmRlZClcIn1gKTtcbiAgICAgICAgbGV0IGFkZGVkSGVyZSA9IGFkZGVkLmdldChmaW5nZXJwcmludCkgfHwgW107XG4gICAgICAgIGlmIChhZGRlZEhlcmUubGVuZ3RoKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgICBhZGRlZCB0byB0aGF0IGtleSdzIGZyb209IGxpc3QgaW4gYXV0aG9yaXplZF9rZXlzOiAke2FkZGVkSGVyZS5qb2luKFwiLCBcIil9YCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgICB0aGF0IGtleSdzIGZyb209IGxpc3QgYWxyZWFkeSBhbGxvd2VkICR7YWRkcmVzc2VzLmpvaW4oXCIsIFwiKSA/IFwidGhlbVwiIDogXCJldmVyeXRoaW5nXCJ9YCk7XG4gICAgICAgIH1cbiAgICAgICAgZm9yIChsZXQgZW50cnkgb2YgcmV2b2NhdGlvbnMuZmlsdGVyKGVudHJ5ID0+IGVudHJ5LmZpbmdlcnByaW50ID09PSBmaW5nZXJwcmludCkpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgIGAgIGZyb3plbiBieSAke2VudHJ5LnJldm9rZWRCeSB8fCBcIj9cIn0gJHtlbnRyeS5yZXZva2VkQXQgfHwgXCJhdCBhbiB1bnJlY29yZGVkIHRpbWVcIn1gXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKFwiXCIpO1xuICAgIH1cbiAgICBjb25zb2xlLmxvZyhgRXZlcnkgb3RoZXIgYWRkcmVzcyBzdGF5cyBmcm96ZW4sIGFuZCBvbmUgb2YgdGhlc2Uga2V5cyB1c2VkIGZyb20gYW55d2hlcmUgZWxzZWApO1xuICAgIGNvbnNvbGUubG9nKGBpcyBmcm96ZW4gYWdhaW4uYCk7XG5cbiAgICAvLyBTaWduZWQgaGVyZSByYXRoZXIgdGhhbiBsZWZ0IGFzIGEgc3RlcCB0byByZW1lbWJlci4gQW4gdW5yZXZva2Ugbm9ib2R5IHNpZ25lZCBkb2VzIG5vdGhpbmcgYXRcbiAgICAvLyBhbGwsIGFuZCB0aGUgcmVwbyB3b3VsZCBzaXQgdGhlcmUgbG9va2luZyBkb25lIHdoaWxlIGV2ZXJ5IG1hY2hpbmUgaWdub3JlZCBpdC5cbiAgICBhd2FpdCBzaWduUmVwbyh7IHJlcG9QYXRoIH0pO1xuXG4gICAgaWYgKCFwdXNoVG9HaXQpIHtcbiAgICAgICAgY29uc29sZS5sb2coYFxcbkNvbW1pdCBhbmQgcHVzaCBpdCwgYW5kIGVhY2ggbWFjaGluZSB3aWxsIHdhaXQgYW4gaG91ciBhZnRlciBzZWVpbmcgaXQgYmVmb3JlYCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGB0aG9zZSBrZXlzIHdvcmsgYWdhaW46YCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBcXGBcXGBcXGBcXG5naXQgYWRkIC1BXFxuZ2l0IGNvbW1pdCAtbSBcIiR7Q09NTUlUX01FU1NBR0V9XCJcXG5naXQgcHVzaFxcblxcYFxcYFxcYGApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IHJ1blByb21pc2UoYGdpdCBhZGQgLUFgLCB7IGN3ZDogcmVwb1BhdGggfSk7XG4gICAgYXdhaXQgcnVuUHJvbWlzZShgZ2l0IGNvbW1pdCAtbSBcIiR7Q09NTUlUX01FU1NBR0V9XCJgLCB7IGN3ZDogcmVwb1BhdGggfSk7XG4gICAgYXdhaXQgcnVuUHJvbWlzZShgZ2l0IHB1c2hgLCB7IGN3ZDogcmVwb1BhdGggfSk7XG4gICAgY29uc29sZS5sb2coYFxcbkNvbW1pdHRlZCBhbmQgcHVzaGVkLiBFYWNoIG1hY2hpbmUgd2FpdHMgYW4gaG91ciBhZnRlciBzZWVpbmcgaXQgYmVmb3JlIHRob3NlYCk7XG4gICAgY29uc29sZS5sb2coYGtleXMgd29yayBhZ2Fpbi5gKTtcbn1cbiJdfQ==
263
- /* _JS_SOURCE_HASH = "9b90ba359ba9cd1b6be2a54ba85a896c0ebcf4bac2b38be51f7d4886cdc1820e"; */
281
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidW5yZXZva2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1bnJldm9rZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwyREFBNkI7QUFDN0IsNENBQW9CO0FBQ3BCLGdEQUF3QjtBQUN4QiwrREFBNEQ7QUFDNUQscURBQStGO0FBQy9GLGlEQUFnRTtBQUNoRSx1Q0FBMEM7QUFDMUMsd0RBQW9EO0FBQ3BELHFEQUFnRDtBQUVoRCw0Q0FBZ0Q7QUFDaEQsbURBQWdFO0FBQ2hFLHlDQUE2QztBQUU3QyxNQUFNLGFBQWEsR0FBRyxXQUFXLENBQUM7QUFDbEMsTUFBTSxlQUFlLEdBQUcsYUFBYSxDQUFDO0FBQ3RDLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQztBQUMxQixNQUFNLGNBQWMsR0FBRyxlQUFlLENBQUM7QUFDdkMsTUFBTSxLQUFLLEdBQUcscUNBQXFDLFdBQVc7Ozs7dUJBSXZDLFdBQVc7OzswQkFHUixDQUFDO0FBcUIzQixtRUFBbUU7QUFDbkUsU0FBZ0IsWUFBWSxDQUFDLFVBQXNCOztJQUMvQyxPQUFPLFVBQVUsQ0FBQyxFQUFFLEtBQUksTUFBQSxVQUFVLENBQUMsT0FBTywwQ0FBRSxFQUFFLENBQUEsSUFBSSxFQUFFLENBQUM7QUFDekQsQ0FBQztBQUZELG9DQUVDO0FBRUQsc0ZBQXNGO0FBQ3RGLFNBQWdCLGtCQUFrQixDQUFDLFVBQXNCO0lBQ3JELE9BQU8sVUFBVSxDQUFDLFdBQVcsSUFBSSxVQUFVLENBQUMsU0FBUyxJQUFJLEVBQUUsQ0FBQztBQUNoRSxDQUFDO0FBRkQsZ0RBRUM7QUFFRDs7OztrR0FJa0c7QUFDM0YsS0FBSyxVQUFVLHFCQUFxQixDQUFDLE1BQTZCO0lBQ3JFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxNQUFNLENBQUM7SUFDM0IsSUFBSSxrQkFBa0IsR0FBRyxNQUFNLGtCQUFFLENBQUMsT0FBTyxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsWUFBRSxDQUFDLE1BQU0sRUFBRSxFQUFF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QUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFFN0IsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2IsT0FBTyxDQUFDLEdBQUcsQ0FBQyw4RUFBOEUsQ0FBQyxDQUFDO1FBQzVGLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0NBQXNDLGNBQWMscUJBQXFCLENBQUMsQ0FBQztRQUN2RixPQUFPO0lBQ1gsQ0FBQztJQUNELE1BQU0sSUFBQSx1QkFBVSxFQUFDLFlBQVksRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2xELE1BQU0sSUFBQSx1QkFBVSxFQUFDLGtCQUFrQixjQUFjLEdBQUcsRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ3pFLE1BQU0sSUFBQSx1QkFBVSxFQUFDLFVBQVUsRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2hELE9BQU8sQ0FBQyxHQUFHLENBQUMsNEVBQTRFLENBQUMsQ0FBQztBQUM5RixDQUFDO0FBM0dELG9CQTJHQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBvcyBmcm9tIFwib3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBydW5Qcm9taXNlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvcnVuUHJvbWlzZVwiO1xuaW1wb3J0IHsgYWxsb3dBZGRyZXNzZXMsIGtleUZpbmdlcnByaW50LCBub3JtYWxpemVLZXlzLCBzdW1tYXJpemVLZXkgfSBmcm9tIFwiLi9hdXRob3JpemVkS2V5c1wiO1xuaW1wb3J0IHsgZGVyaXZlUmV2b2tlS2V5LCByZXZva2VSZXBvVVJMIH0gZnJvbSBcIi4vcmV2b2tlU291cmNlXCI7XG5pbXBvcnQgeyBmaW5kU291cmNlS2V5IH0gZnJvbSBcIi4vc291cmNlc1wiO1xuaW1wb3J0IHsgc2lnblJlcG8gfSBmcm9tIFwiLi4vc2lnbmVkRmlsZXMvc2lnbkZpbGVzXCI7XG5pbXBvcnQgeyByZWFkUmVwb0tleXMgfSBmcm9tIFwiLi9hdXRob3JpemVkS2V5c1wiO1xuaW1wb3J0IHsgZXhwYW5kSG9tZSB9IGZyb20gXCIuLi9oZWxwZXJzL3BhdGhzXCI7XG5pbXBvcnQgeyBzcGF3blByb21pc2UgfSBmcm9tIFwiLi4vaGVscGVycy9zcGF3blwiO1xuaW1wb3J0IHsgZ2V0TWFjaGluZXMsIHNldE1hY2hpbmVzIH0gZnJvbSBcIi4uL21hY2hpbmVzL21hY2hpbmVzXCI7XG5pbXBvcnQgeyByZXNvbHZlS2V5c1JlcG8gfSBmcm9tIFwiLi9rZXlzUmVwb1wiO1xuXG5jb25zdCBVTlJFVk9LRVNfRElSID0gXCJ1bnJldm9rZWRcIjtcbmNvbnN0IFJFVk9DQVRJT05TX0RJUiA9IFwicmV2b2NhdGlvbnNcIjtcbmNvbnN0IEdJVF9LRVlXT1JEID0gXCJnaXRcIjtcbmNvbnN0IENPTU1JVF9NRVNTQUdFID0gXCJ1bnJldm9rZSBrZXlzXCI7XG5jb25zdCBVU0FHRSA9IGBVc2FnZTogeWFybiB1bnJldm9rZSBba2V5cy1yZXBvXSBbJHtHSVRfS0VZV09SRH1dXG5cblJ1biB0aGlzIGluIGEga2V5cyByZXBvLCBvciBuYW1lIG9uZS4gSXQgcmVhZHMgdGhhdCByZXBvJ3MgcmV2b2tlIHJlcG8gYW5kIHdyaXRlcyBvbmUgdW5yZXZva2UgZmlsZVxubmFtaW5nIGV2ZXJ5IHJldm9jYXRpb24gaW4gaXQsIHNvIHRoZSBrZXlzIGFyZSBhY2NlcHRlZCBhZ2FpbiBhcyBlYWNoIG1hY2hpbmUgcGlja3MgaXQgdXAuIEl0IHNpZ25zXG50aGUgcmVzdWx0LCBhbmQgd2l0aCAke0dJVF9LRVlXT1JEfSBpdCBjb21taXRzIGFuZCBwdXNoZXMgaXQgdG9vLlxuXG5LZXlzIHRoYXQgd2VyZSByZXZva2VkIHNob3VsZCBub3JtYWxseSBiZSBkZWxldGVkIGZyb20gdGhlIHJlcG8gaW5zdGVhZC4gVW5yZXZva2luZyBvbmx5IG1hdHRlcnNcbmZvciBhIGtleSB5b3Ugc3RpbGwgd2FudC5gO1xuXG4vKiogT25lIHJldm9jYXRpb24gZXZlbnQuIEVpdGhlciBhbiBzc2gga2V5IHVzZWQgZnJvbSBhbiBhZGRyZXNzIGl0IGlzIG5vdCBhbGxvd2VkIGZyb20sIG9yIGFcbiAgICBtYWNoaW5lIHRoYXQgdGFsa2VkIHRvIHVzIGZyb20gb25lLiBCb3RoIGFyZSB0aGUgc2FtZSBzaGFwZSAtIGFuIGlkZW50aXR5IGFuZCBhbiBhZGRyZXNzIC0gYW5kXG4gICAgYW4gdW5yZXZva2UgdW5kb2VzIGVpdGhlciBieSBhbGxvd2luZyB0aGF0IHNhbWUgcGFpci5cblxuICAgIFdoaWNoIGlzIHdoeSB1bnJldm9raW5nIG5ldmVyIG1ha2VzIGFueXRoaW5nIHVucmV2b2thYmxlOiB1c2VkIGZyb20gc29tZSBvdGhlciBhZGRyZXNzLCBpdCBpc1xuICAgIHJldm9rZWQgYWdhaW4sIHVuZGVyIGEgbmV3IGlkIG5vIGV4aXN0aW5nIHVucmV2b2tlIG5hbWVzLiAqL1xuZXhwb3J0IHR5cGUgUmV2b2NhdGlvbiA9IHtcbiAgICByZXZvY2F0aW9uSWQ6IHN0cmluZztcbiAgICAvLyBFeGFjdGx5IG9uZSBvZiB0aGVzZS4gQSBrZXkgcmV2b2NhdGlvbiBuYW1lcyBhIGZpbmdlcnByaW50LCBhIG1hY2hpbmUgcmV2b2NhdGlvbiBhIG1hY2hpbmVJZC5cbiAgICBmaW5nZXJwcmludD86IHN0cmluZztcbiAgICBtYWNoaW5lSWQ/OiBzdHJpbmc7XG4gICAgaXA/OiBzdHJpbmc7XG4gICAga2V5Pzogc3RyaW5nO1xuICAgIHJldm9rZWRBdD86IHN0cmluZztcbiAgICByZXZva2VkQnk/OiBzdHJpbmc7XG4gICAgcmVhc29uPzogc3RyaW5nO1xuICAgIGF0dGVtcHQ/OiB7IGlwPzogc3RyaW5nOyB1c2VyPzogc3RyaW5nOyByZXF1aXJlZD86IHN0cmluZyB9O1xufTtcblxuLyoqIE9sZGVyIHJldm9jYXRpb24gZmlsZXMgY2FycnkgdGhlIGFkZHJlc3MgdW5kZXIgYXR0ZW1wdCBvbmx5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJldm9jYXRpb25JUChyZXZvY2F0aW9uOiBSZXZvY2F0aW9uKSB7XG4gICAgcmV0dXJuIHJldm9jYXRpb24uaXAgfHwgcmV2b2NhdGlvbi5hdHRlbXB0Py5pcCB8fCBcIlwiO1xufVxuXG4vKiogV2hhdCB0aGUgcmV2b2NhdGlvbiBpcyBhYm91dCwgd2hpY2ggaXMgd2hhdCBhbiB1bnJldm9rZSBoYXMgdG8gbmFtZSB0byB1bmRvIGl0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJldm9jYXRpb25JZGVudGl0eShyZXZvY2F0aW9uOiBSZXZvY2F0aW9uKSB7XG4gICAgcmV0dXJuIHJldm9jYXRpb24uZmluZ2VycHJpbnQgfHwgcmV2b2NhdGlvbi5tYWNoaW5lSWQgfHwgXCJcIjtcbn1cblxuLyoqIEV2ZXJ5IHJldm9jYXRpb24gdGhlIHJldm9rZSByZXBvIGxpc3RzLiBDbG9uZWQgcmVhZCBvbmx5IGludG8gYSB0ZW1wIGRpcmVjdG9yeS5cblxuICAgIEEgcGVyc29uIHJ1bm5pbmcgdGhpcyBoYXMgdGhlaXIgb3duIGFjY2VzcyB0byB0aGUgcmVwbywgc28gdGhlaXIgY3JlZGVudGlhbHMgYXJlIHdoYXQgaXMgdXNlZC5cbiAgICBPbiBhIG1hY2hpbmUgdGhhdCBpcyBhbHJlYWR5IGEgcG9ydHNlY3VyZSBob3N0IHRoZXJlIG1heSBiZSBubyBzdWNoIGNyZWRlbnRpYWxzLCBidXQgdGhlIHNvdXJjZVxuICAgIGRlcGxveSBrZXkgaXMgcmlnaHQgdGhlcmUsIGFuZCB0aGUga2V5IGRlcml2ZWQgZnJvbSBpdCBpcyBvbmUgdGhhdCByZXBvIGRlZmluaXRlbHkgYWNjZXB0cy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkUmVtb3RlUmV2b2NhdGlvbnMoY29uZmlnOiB7IHNvdXJjZVVSTDogc3RyaW5nIH0pIHtcbiAgICBsZXQgeyBzb3VyY2VVUkwgfSA9IGNvbmZpZztcbiAgICBsZXQgdGVtcG9yYXJ5RGlyZWN0b3J5ID0gYXdhaXQgZnMubWtkdGVtcChwYXRoLmpvaW4ob3MudG1wZGlyKCksIFwidW5yZXZva2UtXCIpKTtcbiAgICBsZXQgcmVwb1BhdGggPSBwYXRoLmpvaW4odGVtcG9yYXJ5RGlyZWN0b3J5LCBcInJlcG9cIik7XG4gICAgbGV0IGNsb25lQXJncyA9IFtcImNsb25lXCIsIFwiLS1kZXB0aFwiLCBcIjFcIiwgcmV2b2tlUmVwb1VSTChzb3VyY2VVUkwpLCByZXBvUGF0aF07XG4gICAgbGV0IHNvdXJjZUtleSA9IGF3YWl0IGZpbmRTb3VyY2VLZXkoc291cmNlVVJMKTtcbiAgICBpZiAoc291cmNlS2V5KSB7XG4gICAgICAgIGxldCBkZXJpdmVkID0gZGVyaXZlUmV2b2tlS2V5KGF3YWl0IGZzLnJlYWRGaWxlKHNvdXJjZUtleSwgXCJ1dGY4XCIpKTtcbiAgICAgICAgbGV0IGRlcml2ZWRLZXlQYXRoID0gcGF0aC5qb2luKHRlbXBvcmFyeURpcmVjdG9yeSwgXCJrZXlcIik7XG4gICAgICAgIGF3YWl0IGZzLndyaXRlRmlsZShkZXJpdmVkS2V5UGF0aCwgZGVyaXZlZC5wcml2YXRlS2V5RmlsZSwgeyBtb2RlOiAwbzYwMCB9KTtcbiAgICAgICAgbGV0IHNzaENvbW1hbmQgPSBgc3NoIC1pICR7ZGVyaXZlZEtleVBhdGh9IC1vIElkZW50aXRpZXNPbmx5PXllcyAtbyBCYXRjaE1vZGU9eWVzIC1vIFN0cmljdEhvc3RLZXlDaGVja2luZz1hY2NlcHQtbmV3YDtcbiAgICAgICAgY2xvbmVBcmdzID0gW1wiLWNcIiwgYGNvcmUuc3NoQ29tbWFuZD0ke3NzaENvbW1hbmR9YCwgLi4uY2xvbmVBcmdzXTtcbiAgICB9XG4gICAgbGV0IGNsb25lID0gYXdhaXQgc3Bhd25Qcm9taXNlKHsgY29tbWFuZDogXCJnaXRcIiwgYXJnczogY2xvbmVBcmdzIH0pO1xuICAgIGlmIChjbG9uZS5zdGF0dXMgIT09IDApIHtcbiAgICAgICAgYXdhaXQgZnMucm0odGVtcG9yYXJ5RGlyZWN0b3J5LCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBFeHBlY3RlZCB0byBiZSBhYmxlIHRvIHJlYWQgJHtyZXZva2VSZXBvVVJMKHNvdXJjZVVSTCl9LlxcbmBcbiAgICAgICAgICAgICsgYCR7KGNsb25lLnN0ZG91dCArIGNsb25lLnN0ZGVycikudHJpbSgpfWBcbiAgICAgICAgKTtcbiAgICB9XG4gICAgbGV0IHJldm9jYXRpb25zOiBSZXZvY2F0aW9uW10gPSBbXTtcbiAgICBsZXQgZGlyZWN0b3J5ID0gcGF0aC5qb2luKHJlcG9QYXRoLCBSRVZPQ0FUSU9OU19ESVIpO1xuICAgIHRyeSB7XG4gICAgICAgIGZvciAobGV0IG5hbWUgb2YgKGF3YWl0IGZzLnJlYWRkaXIoZGlyZWN0b3J5KSkuc29ydCgpKSB7XG4gICAgICAgICAgICBpZiAobmFtZS5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICAgICAgcmV2b2NhdGlvbnMucHVzaChKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihkaXJlY3RvcnksIG5hbWUpLCBcInV0ZjhcIikpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgLy8gTm8gcmV2b2NhdGlvbnMgZGlyZWN0b3J5IGF0IGFsbCBqdXN0IG1lYW5zIG5vdGhpbmcgaGFzIGV2ZXIgYmVlbiByZXZva2VkLlxuICAgIH1cbiAgICBhd2FpdCBmcy5ybSh0ZW1wb3JhcnlEaXJlY3RvcnksIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICByZXR1cm4gcmV2b2NhdGlvbnM7XG59XG5cbi8qKiBXaGljaCBrZXlzIGluIGEgcmVwbyBhcmUgcmV2b2tlZC4gV2hhdCBzaWduZmlsZXMgYW5kIHNlY3VyZXNzaCByZWZ1c2Ugb3Zlci4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXZva2VkS2V5c0luUmVwbyhjb25maWc6IHsgcmVwb1BhdGg6IHN0cmluZzsgc291cmNlVVJMOiBzdHJpbmcgfSkge1xuICAgIGxldCB7IHJlcG9QYXRoLCBzb3VyY2VVUkwgfSA9IGNvbmZpZztcbiAgICBsZXQgcmV2b2NhdGlvbnMgPSBhd2FpdCByZWFkUmVtb3RlUmV2b2NhdGlvbnMoeyBzb3VyY2VVUkwgfSk7XG4gICAgbGV0IHJldm9rZWRGaW5nZXJwcmludHMgPSBuZXcgU2V0KHJldm9jYXRpb25zLm1hcChyZXZvY2F0aW9uID0+IHJldm9jYXRpb24uZmluZ2VycHJpbnQpKTtcbiAgICBsZXQgdW5yZXZva2VkID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgdHJ5IHtcbiAgICAgICAgbGV0IGRpcmVjdG9yeSA9IHBhdGguam9pbihyZXBvUGF0aCwgVU5SRVZPS0VTX0RJUik7XG4gICAgICAgIGZvciAobGV0IG5hbWUgb2YgYXdhaXQgZnMucmVhZGRpcihkaXJlY3RvcnkpKSB7XG4gICAgICAgICAgICBpZiAoIW5hbWUuZW5kc1dpdGgoXCIuanNvblwiKSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHBhcnNlZCA9IEpTT04ucGFyc2UoYXdhaXQgZnMucmVhZEZpbGUocGF0aC5qb2luKGRpcmVjdG9yeSwgbmFtZSksIFwidXRmOFwiKSk7XG4gICAgICAgICAgICBmb3IgKGxldCBhbGxvd2VkIG9mIHBhcnNlZC5hbGxvd2VkIHx8IFtdKSB7XG4gICAgICAgICAgICAgICAgdW5yZXZva2VkLmFkZChgJHthbGxvd2VkLmZpbmdlcnByaW50IHx8IGFsbG93ZWQubWFjaGluZUlkfSAke2FsbG93ZWQuaXB9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBOYW1lZCBpZHMsIGZvciB0aGUgdW5yZXZva2VzIHdyaXR0ZW4gYmVmb3JlIHRoaXMgd2FzIGFib3V0IHBhaXJzLlxuICAgICAgICAgICAgZm9yIChsZXQgcmV2b2NhdGlvbklkIG9mIHBhcnNlZC5yZXZvY2F0aW9uSWRzIHx8IFtdKSB7XG4gICAgICAgICAgICAgICAgdW5yZXZva2VkLmFkZChyZXZvY2F0aW9uSWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyBOb3RoaW5nIGhhcyBiZWVuIHVucmV2b2tlZC5cbiAgICB9XG4gICAgbGV0IHN0aWxsUmV2b2tlZCA9IHJldm9jYXRpb25zLmZpbHRlcihyZXZvY2F0aW9uID0+ICF1bnJldm9rZWQuaGFzKHJldm9jYXRpb24ucmV2b2NhdGlvbklkKVxuICAgICAgICAmJiAhdW5yZXZva2VkLmhhcyhgJHtyZXZvY2F0aW9uLmZpbmdlcnByaW50fSAke3Jldm9jYXRpb25JUChyZXZvY2F0aW9uKX1gKSk7XG4gICAgbGV0IGtleXMgPSBub3JtYWxpemVLZXlzKGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgXCJhdXRob3JpemVkX2tleXNcIiksIFwidXRmOFwiKS5jYXRjaCgoKSA9PiBcIlwiKSk7XG4gICAgcmV0dXJuIHN0aWxsUmV2b2tlZFxuICAgICAgICAuZmlsdGVyKHJldm9jYXRpb24gPT4ga2V5cy5zb21lKGtleSA9PiBrZXlGaW5nZXJwcmludChrZXkpID09PSByZXZvY2F0aW9uLmZpbmdlcnByaW50KSlcbiAgICAgICAgLm1hcChyZXZvY2F0aW9uID0+ICh7IHJldm9jYXRpb24sIGtleToga2V5cy5maW5kKGtleSA9PiBrZXlGaW5nZXJwcmludChrZXkpID09PSByZXZvY2F0aW9uLmZpbmdlcnByaW50KSB8fCBcIlwiIH0pKTtcbn1cblxuLyoqIFdyaXRlcyB0aGUgYWRkcmVzc2VzIGludG8gdGhlIGZyb209IGxpc3Qgb2YgZWFjaCBrZXkgaW4gdGhlIHJlcG8ncyBhdXRob3JpemVkX2tleXMsIGFuZCBzYXlzXG4gICAgd2hpY2ggb25lcyB3ZXJlIGFjdHVhbGx5IG5ldy4gT25seSB0aGUgbGluZXMgYmVpbmcgY2hhbmdlZCBhcmUgdG91Y2hlZCwgc28gY29tbWVudHMsIG9yZGVyaW5nXG4gICAgYW5kIGFueSBrZXkgbm90IGludm9sdmVkIGNvbWUgb3V0IG9mIHRoaXMgYnl0ZSBmb3IgYnl0ZSB0aGUgc2FtZS4gKi9cbmFzeW5jIGZ1bmN0aW9uIGFsbG93QWRkcmVzc2VzSW5SZXBvKGNvbmZpZzoge1xuICAgIHJlcG9QYXRoOiBzdHJpbmc7XG4gICAgYWRkcmVzc2VzQnlGaW5nZXJwcmludDogTWFwPHN0cmluZywgc3RyaW5nW10+O1xufSkge1xuICAgIGxldCB7IHJlcG9QYXRoLCBhZGRyZXNzZXNCeUZpbmdlcnByaW50IH0gPSBjb25maWc7XG4gICAgbGV0IGFkZGVkID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZ1tdPigpO1xuICAgIGxldCBmaWxlUGF0aCA9IHBhdGguam9pbihyZXBvUGF0aCwgXCJhdXRob3JpemVkX2tleXNcIik7XG4gICAgbGV0IGNvbnRlbnRzO1xuICAgIHRyeSB7XG4gICAgICAgIGNvbnRlbnRzID0gYXdhaXQgZnMucmVhZEZpbGUoZmlsZVBhdGgsIFwidXRmOFwiKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIEEgcmVwbyBob2xkaW5nIGl0cyBrZXlzIGFzIHNlcGFyYXRlIC5wdWIgZmlsZXMuIE5vdGhpbmcgdG8gZWRpdCBpbiBvbmUgcGxhY2UsIHNvIHRoZVxuICAgICAgICAvLyBjYWxsZXIncyBsaXN0aW5nIGlzIGFsbCB3aG9ldmVyIHJhbiB0aGlzIGdldHMuXG4gICAgICAgIGNvbnNvbGUubG9nKGBObyBhdXRob3JpemVkX2tleXMgaW4gJHtyZXBvUGF0aH0sIHNvIHRoZSBhZGRyZXNzZXMgd2VyZSBub3QgYWRkZWQgdG8gYW55IGtleS5gKTtcbiAgICAgICAgcmV0dXJuIGFkZGVkO1xuICAgIH1cbiAgICBsZXQgbGluZXMgPSBjb250ZW50cy5zcGxpdChcIlxcblwiKTtcbiAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgbGluZXMubGVuZ3RoOyBpbmRleCsrKSB7XG4gICAgICAgIGxldCBmaW5nZXJwcmludCA9IGtleUZpbmdlcnByaW50KGxpbmVzW2luZGV4XSk7XG4gICAgICAgIGxldCBhZGRyZXNzZXMgPSBmaW5nZXJwcmludCAmJiBhZGRyZXNzZXNCeUZpbmdlcnByaW50LmdldChmaW5nZXJwcmludCk7XG4gICAgICAgIGlmICghYWRkcmVzc2VzIHx8ICFhZGRyZXNzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgcmVzdWx0ID0gYWxsb3dBZGRyZXNzZXMobGluZXNbaW5kZXhdLCBhZGRyZXNzZXMpO1xuICAgICAgICBsaW5lc1tpbmRleF0gPSByZXN1bHQua2V5TGluZTtcbiAgICAgICAgYWRkZWQuc2V0KGZpbmdlcnByaW50LCBbLi4uKGFkZGVkLmdldChmaW5nZXJwcmludCkgfHwgW10pLCAuLi5yZXN1bHQuYWRkZWRdKTtcbiAgICB9XG4gICAgaWYgKFsuLi5hZGRlZC52YWx1ZXMoKV0uc29tZShsaXN0ID0+IGxpc3QubGVuZ3RoKSkge1xuICAgICAgICBhd2FpdCBmcy53cml0ZUZpbGUoZmlsZVBhdGgsIGxpbmVzLmpvaW4oXCJcXG5cIikpO1xuICAgIH1cbiAgICByZXR1cm4gYWRkZWQ7XG59XG5cbi8qKiBQdXRzIGVhY2ggbWFjaGluZSdzIGFkZHJlc3NlcyBiYWNrIGludG8gaXRzIG93biBmaWxlLCB3aGljaCBpcyB0aGUgbWFjaGluZSBlcXVpdmFsZW50IG9mIGFkZGluZ1xuICAgIGFuIGFkZHJlc3MgdG8gYSBrZXkncyBmcm9tPSBsaXN0OiB3aXRob3V0IGl0IHRoZSBtYWNoaW5lIGlzIGFsbG93ZWQgYWdhaW4gaW4gcHJpbmNpcGxlIGFuZFxuICAgIHN0aWxsIHJlamVjdGVkIG9uIHNpZ2h0LCB3aGljaCByZXZva2VzIGl0IG9uY2UgbW9yZS4gKi9cbmFzeW5jIGZ1bmN0aW9uIGFsbG93QWRkcmVzc2VzRm9yTWFjaGluZXMoY29uZmlnOiB7IHJlcG9QYXRoOiBzdHJpbmc7IHJldm9jYXRpb25zOiBSZXZvY2F0aW9uW10gfSkge1xuICAgIGxldCB7IHJlcG9QYXRoLCByZXZvY2F0aW9ucyB9ID0gY29uZmlnO1xuICAgIGxldCBhZGRlZCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgICAvLyBSZWFkIHRoZSB3aG9sZSBsaXN0LCBjaGFuZ2Ugd2hhdCB0aGVzZSByZXZvY2F0aW9ucyBhcmUgYWJvdXQsIHdyaXRlIGl0IGJhY2suIFNldHRpbmcgaXMgYnlcbiAgICAvLyB0aGUgd2hvbGUgc2V0LCBzbyB3cml0aW5nIG9uZSBtYWNoaW5lIGF0IGEgdGltZSB3b3VsZCBkZWxldGUgZXZlcnkgb3RoZXIgbWFjaGluZS5cbiAgICBsZXQgbWFjaGluZXMgPSBhd2FpdCBnZXRNYWNoaW5lcyhyZXBvUGF0aCk7XG4gICAgZm9yIChsZXQgcmV2b2NhdGlvbiBvZiByZXZvY2F0aW9ucykge1xuICAgICAgICBsZXQgbWFjaGluZUlkID0gcmV2b2NhdGlvbi5tYWNoaW5lSWQ7XG4gICAgICAgIGxldCBpcCA9IHJldm9jYXRpb25JUChyZXZvY2F0aW9uKTtcbiAgICAgICAgaWYgKCFtYWNoaW5lSWQgfHwgIWlwKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgZXhpc3RpbmcgPSBtYWNoaW5lcy5maW5kKG1hY2hpbmUgPT4gbWFjaGluZS5tYWNoaW5lSWQgPT09IG1hY2hpbmVJZCk7XG4gICAgICAgIGlmICghZXhpc3RpbmcpIHtcbiAgICAgICAgICAgIC8vIFJlbW92ZWQgZnJvbSB0aGUgcmVwbyBzaW5jZSBpdCB3YXMgcmV2b2tlZCwgc28gdGhlcmUgaXMgbm90aGluZyB0byBhbGxvdy4gRGVsZXRpbmcgYVxuICAgICAgICAgICAgLy8gbWFjaGluZSBpcyB0aGUgc3Ryb25nZXIgc3RhdGVtZW50IGFuZCBpdCBzdGFuZHMuXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgbWFjaGluZXMvJHttYWNoaW5lSWR9Lmpzb24gaXMgbm90IGluIHRoaXMgcmVwbywgc28gJHtpcH0gd2FzIG5vdCBhZGRlZCB0byBpdGApO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV4aXN0aW5nLmlwcy5pbmNsdWRlcyhpcCkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGV4aXN0aW5nLmlwcyA9IFsuLi5leGlzdGluZy5pcHMsIGlwXTtcbiAgICAgICAgYWRkZWQuc2V0KG1hY2hpbmVJZCwgWy4uLihhZGRlZC5nZXQobWFjaGluZUlkKSB8fCBbXSksIGlwXSk7XG4gICAgfVxuICAgIGlmIChhZGRlZC5zaXplKSB7XG4gICAgICAgIGF3YWl0IHNldE1hY2hpbmVzKHsgcmVwb1BhdGgsIG1hY2hpbmVzIH0pO1xuICAgIH1cbiAgICByZXR1cm4gYWRkZWQ7XG59XG5cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7XG4gICAgbGV0IGFyZ3YgPSBwcm9jZXNzLmFyZ3Yuc2xpY2UoMik7XG4gICAgbGV0IHB1c2hUb0dpdCA9IGFyZ3YuaW5jbHVkZXMoR0lUX0tFWVdPUkQpO1xuICAgIGxldCBwb3NpdGlvbmFsID0gYXJndi5maWx0ZXIoYXJnID0+IGFyZyAhPT0gR0lUX0tFWVdPUkQpO1xuICAgIGlmIChwb3NpdGlvbmFsLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhdCBtb3N0IGEga2V5cyByZXBvLCB3YXMgJHtwb3NpdGlvbmFsLmxlbmd0aH0gYXJndW1lbnQocylcXG4ke1VTQUdFfWApO1xuICAgIH1cbiAgICBsZXQgeyByZXBvUGF0aCwgc291cmNlVVJMOiBvcmlnaW5VUkwgfSA9IGF3YWl0IHJlc29sdmVLZXlzUmVwbyhwb3NpdGlvbmFsWzBdKTtcblxuICAgIGxldCByZXZvY2F0aW9ucyA9IGF3YWl0IHJlYWRSZW1vdGVSZXZvY2F0aW9ucyh7IHNvdXJjZVVSTDogb3JpZ2luVVJMIH0pO1xuICAgIGlmICghcmV2b2NhdGlvbnMubGVuZ3RoKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke3Jldm9rZVJlcG9VUkwob3JpZ2luVVJMKX0gbGlzdHMgbm8gcmV2b2NhdGlvbnMsIHNvIHRoZXJlIGlzIG5vdGhpbmcgdG8gdW5kby5gKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGxldCBkaXJlY3RvcnkgPSBwYXRoLmpvaW4ocmVwb1BhdGgsIFVOUkVWT0tFU19ESVIpO1xuICAgIGF3YWl0IGZzLm1rZGlyKGRpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgbGV0IHN0YW1wID0gbmV3IERhdGUoKS50b0lTT1N0cmluZygpLnJlcGxhY2UoL1s6Ll0vZywgXCItXCIpO1xuICAgIGxldCB1bnJldm9rZUlkID0gYCR7c3RhbXB9LXVucmV2b2tlYDtcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5qb2luKGRpcmVjdG9yeSwgYCR7dW5yZXZva2VJZH0uanNvbmApLCBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIHVucmV2b2tlSWQsXG4gICAgICAgIGNyZWF0ZWRBdDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgICAvLyBXaGF0IHRoaXMgZmlsZSBzYXlzOiBlYWNoIG9mIHRoZXNlIGtleXMgaXMgYWxsb3dlZCBmcm9tIHRoaXMgYWRkcmVzcy4gUGFpcnMsIG5vdCBrZXlzLFxuICAgICAgICAvLyBhbmQgbm90IGEgYmxhbmtldCBcImFsbG93IGV2ZXJ5dGhpbmcgYWdhaW5cIiAtIGEga2V5IGZvcmdpdmVuIGhlcmUgZm9yIG9uZSBhZGRyZXNzIGlzXG4gICAgICAgIC8vIHN0aWxsIHJldm9rZWQgdGhlIG1vbWVudCBpdCBpcyB1c2VkIGZyb20gYW5vdGhlci5cbiAgICAgICAgYWxsb3dlZDogcmV2b2NhdGlvbnMubWFwKHJldm9jYXRpb24gPT4gKHtcbiAgICAgICAgICAgIGZpbmdlcnByaW50OiByZXZvY2F0aW9uLmZpbmdlcnByaW50LFxuICAgICAgICAgICAgbWFjaGluZUlkOiByZXZvY2F0aW9uLm1hY2hpbmVJZCxcbiAgICAgICAgICAgIGlwOiByZXZvY2F0aW9uSVAocmV2b2NhdGlvbiksXG4gICAgICAgIH0pKSxcbiAgICAgICAgcmV2b2NhdGlvbnM6IHJldm9jYXRpb25zLm1hcChyZXZvY2F0aW9uID0+ICh7XG4gICAgICAgICAgICByZXZvY2F0aW9uSWQ6IHJldm9jYXRpb24ucmV2b2NhdGlvbklkLFxuICAgICAgICAgICAgZmluZ2VycHJpbnQ6IHJldm9jYXRpb24uZmluZ2VycHJpbnQsXG4gICAgICAgICAgICBtYWNoaW5lSWQ6IHJldm9jYXRpb24ubWFjaGluZUlkLFxuICAgICAgICAgICAgaXA6IHJldm9jYXRpb25JUChyZXZvY2F0aW9uKSxcbiAgICAgICAgICAgIHJldm9rZWRBdDogcmV2b2NhdGlvbi5yZXZva2VkQXQsXG4gICAgICAgICAgICByZXZva2VkQnk6IHJldm9jYXRpb24ucmV2b2tlZEJ5LFxuICAgICAgICAgICAgYXR0ZW1wdDogcmV2b2NhdGlvbi5hdHRlbXB0LFxuICAgICAgICB9KSksXG4gICAgfSwgdW5kZWZpbmVkLCA0KSArIFwiXFxuXCIpO1xuXG4gICAgLy8gTmFtZWQgdGhlIHdheSB0aGUgbm90aWZpY2F0aW9ucyBuYW1lIHRoZW0uIEEgZmluZ2VycHJpbnQgaXMgbm90IGluIGF1dGhvcml6ZWRfa2V5cyBhbmRcbiAgICAvLyBjYW5ub3QgYmUgd29ya2VkIG91dCBieSBleWUsIHNvIG9uIGl0cyBvd24gaXQgdGVsbHMgd2hvZXZlciBpcyByZWFkaW5nIHRoaXMgbm90aGluZyBhYm91dFxuICAgIC8vIHdoaWNoIG9mIHRoZWlyIGtleXMgaXMgYmVpbmcgdGFsa2VkIGFib3V0LlxuICAgIGxldCBrZXlzQnlGaW5nZXJwcmludCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgZm9yIChsZXQga2V5IG9mIGF3YWl0IHJlYWRSZXBvS2V5cyhyZXBvUGF0aCkuY2F0Y2goKCkgPT4gW10gYXMgc3RyaW5nW10pKSB7XG4gICAgICAgIGtleXNCeUZpbmdlcnByaW50LnNldChrZXlGaW5nZXJwcmludChrZXkpLCBrZXkpO1xuICAgIH1cbiAgICBsZXQgZGVzY3JpYmVLZXkgPSAocmV2b2NhdGlvbjogUmV2b2NhdGlvbikgPT4ge1xuICAgICAgICBsZXQga2V5ID0ga2V5c0J5RmluZ2VycHJpbnQuZ2V0KHJldm9jYXRpb24uZmluZ2VycHJpbnQgfHwgXCJcIikgfHwgcmV2b2NhdGlvbi5rZXkgfHwgXCJcIjtcbiAgICAgICAgcmV0dXJuIGtleSAmJiBzdW1tYXJpemVLZXkoa2V5KSB8fCBgYSBrZXkgbm8gbG9uZ2VyIGluIHRoaXMgcmVwbyAoJHtyZXZvY2F0aW9uLmZpbmdlcnByaW50fSlgO1xuICAgIH07XG5cbiAgICBsZXQgYWRkcmVzc2VzQnlJZGVudGl0eSA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgICBmb3IgKGxldCByZXZvY2F0aW9uIG9mIHJldm9jYXRpb25zKSB7XG4gICAgICAgIGxldCBpcCA9IHJldm9jYXRpb25JUChyZXZvY2F0aW9uKTtcbiAgICAgICAgbGV0IGlkZW50aXR5ID0gcmV2b2NhdGlvbklkZW50aXR5KHJldm9jYXRpb24pO1xuICAgICAgICBsZXQgZXhpc3RpbmcgPSBhZGRyZXNzZXNCeUlkZW50aXR5LmdldChpZGVudGl0eSkgfHwgW107XG4gICAgICAgIGlmIChpcCAmJiAhZXhpc3RpbmcuaW5jbHVkZXMoaXApKSB7XG4gICAgICAgICAgICBleGlzdGluZy5wdXNoKGlwKTtcbiAgICAgICAgfVxuICAgICAgICBhZGRyZXNzZXNCeUlkZW50aXR5LnNldChpZGVudGl0eSwgZXhpc3RpbmcpO1xuICAgIH1cblxuICAgIC8vIENhbmNlbGxpbmcgdGhlIHJldm9jYXRpb24gb24gaXRzIG93biB3b3VsZCBsZWF2ZSBzc2hkIHJlZnVzaW5nIHRoYXQgYWRkcmVzcywgYW5kIHRoZSBtYWNoaW5lc1xuICAgIC8vIHJldm9raW5nIGFsbCBvdmVyIGFnYWluLCBzbyB0aGUgYWRkcmVzc2VzIGdvIGludG8gdGhlIGtleSdzIGZyb209IGxpc3QgYW5kIGludG8gdGhlIG1hY2hpbmUnc1xuICAgIC8vIG93biBmaWxlIGhlcmUuIFdlIGFyZSBpbiB0aGUgcmVwbyB0aGF0IG93bnMgYm90aCwgc28gdGhlcmUgaXMgbm90aGluZyB0byBoYW5kIGJhY2sgdG8gd2hvZXZlclxuICAgIC8vIHJhbiB0aGlzLlxuICAgIGxldCBhZGRlZCA9IGF3YWl0IGFsbG93QWRkcmVzc2VzSW5SZXBvKHsgcmVwb1BhdGgsIGFkZHJlc3Nlc0J5RmluZ2VycHJpbnQ6IGFkZHJlc3Nlc0J5SWRlbnRpdHkgfSk7XG4gICAgbGV0IGFkZGVkRm9yTWFjaGluZXMgPSBhd2FpdCBhbGxvd0FkZHJlc3Nlc0Zvck1hY2hpbmVzKHsgcmVwb1BhdGgsIHJldm9jYXRpb25zIH0pO1xuXG4gICAgY29uc29sZS5sb2coXCJcIik7XG4gICAgZm9yIChsZXQgW2lkZW50aXR5LCBhZGRyZXNzZXNdIG9mIGFkZHJlc3Nlc0J5SWRlbnRpdHkpIHtcbiAgICAgICAgbGV0IGVudHJpZXMgPSByZXZvY2F0aW9ucy5maWx0ZXIoZW50cnkgPT4gcmV2b2NhdGlvbklkZW50aXR5KGVudHJ5KSA9PT0gaWRlbnRpdHkpO1xuICAgICAgICBsZXQgbWFjaGluZUlkID0gZW50cmllc1swXS5tYWNoaW5lSWQ7XG4gICAgICAgIGNvbnNvbGUubG9nKGBVbmZyZWV6aW5nICR7bWFjaGluZUlkICYmIGBtYWNoaW5lICR7bWFjaGluZUlkfWAgfHwgZGVzY3JpYmVLZXkoZW50cmllc1swXSl9YCk7XG4gICAgICAgIGNvbnNvbGUubG9nKGBBbGxvd2luZyBJUCAke2FkZHJlc3Nlcy5qb2luKFwiLCBcIikgfHwgXCIobm8gYWRkcmVzcyByZWNvcmRlZClcIn1gKTtcbiAgICAgICAgbGV0IGFkZGVkSGVyZSA9IG1hY2hpbmVJZCAmJiBhZGRlZEZvck1hY2hpbmVzLmdldChtYWNoaW5lSWQpIHx8IGFkZGVkLmdldChpZGVudGl0eSkgfHwgW107XG4gICAgICAgIGlmIChhZGRlZEhlcmUubGVuZ3RoKSB7XG4gICAgICAgICAgICBsZXQgd2hlcmUgPSBtYWNoaW5lSWQgJiYgYG1hY2hpbmVzLyR7bWFjaGluZUlkfS5qc29uYCB8fCBgdGhhdCBrZXkncyBmcm9tPSBsaXN0IGluIGF1dGhvcml6ZWRfa2V5c2A7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgICBhZGRlZCB0byAke3doZXJlfTogJHthZGRlZEhlcmUuam9pbihcIiwgXCIpfWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYCAgYWxyZWFkeSBhbGxvd2VkIGZyb20gJHthZGRyZXNzZXMuam9pbihcIiwgXCIpIHx8IFwiZXZlcnl3aGVyZVwifWApO1xuICAgICAgICB9XG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgIGAgIGZyb3plbiBieSAke2VudHJ5LnJldm9rZWRCeSB8fCBcIj9cIn0gJHtlbnRyeS5yZXZva2VkQXQgfHwgXCJhdCBhbiB1bnJlY29yZGVkIHRpbWVcIn1gXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnNvbGUubG9nKFwiXCIpO1xuICAgIH1cbiAgICBjb25zb2xlLmxvZyhgRXZlcnkgb3RoZXIgYWRkcmVzcyBzdGF5cyBmcm96ZW4sIGFuZCBhbnkgb2YgdGhlc2UgdXNlZCBmcm9tIGFueXdoZXJlIGVsc2UgaXNgKTtcbiAgICBjb25zb2xlLmxvZyhgZnJvemVuIGFnYWluLmApO1xuXG4gICAgLy8gU2lnbmVkIGhlcmUgcmF0aGVyIHRoYW4gbGVmdCBhcyBhIHN0ZXAgdG8gcmVtZW1iZXIuIEFuIHVucmV2b2tlIG5vYm9keSBzaWduZWQgZG9lcyBub3RoaW5nIGF0XG4gICAgLy8gYWxsLCBhbmQgdGhlIHJlcG8gd291bGQgc2l0IHRoZXJlIGxvb2tpbmcgZG9uZSB3aGlsZSBldmVyeSBtYWNoaW5lIGlnbm9yZWQgaXQuXG4gICAgYXdhaXQgc2lnblJlcG8oeyByZXBvUGF0aCB9KTtcblxuICAgIGlmICghcHVzaFRvR2l0KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBcXG5Db21taXQgYW5kIHB1c2ggaXQsIGFuZCB0aG9zZSBrZXlzIHdvcmsgYWdhaW4gYXMgZWFjaCBtYWNoaW5lIHBpY2tzIGl0IHVwOmApO1xuICAgICAgICBjb25zb2xlLmxvZyhgXFxgXFxgXFxgXFxuZ2l0IGFkZCAtQVxcbmdpdCBjb21taXQgLW0gXCIke0NPTU1JVF9NRVNTQUdFfVwiXFxuZ2l0IHB1c2hcXG5cXGBcXGBcXGBgKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgYWRkIC1BYCwgeyBjd2Q6IHJlcG9QYXRoIH0pO1xuICAgIGF3YWl0IHJ1blByb21pc2UoYGdpdCBjb21taXQgLW0gXCIke0NPTU1JVF9NRVNTQUdFfVwiYCwgeyBjd2Q6IHJlcG9QYXRoIH0pO1xuICAgIGF3YWl0IHJ1blByb21pc2UoYGdpdCBwdXNoYCwgeyBjd2Q6IHJlcG9QYXRoIH0pO1xuICAgIGNvbnNvbGUubG9nKGBcXG5Db21taXR0ZWQgYW5kIHB1c2hlZC4gVGhvc2Uga2V5cyB3b3JrIGFnYWluIGFzIGVhY2ggbWFjaGluZSBwaWNrcyBpdCB1cC5gKTtcbn1cbiJdfQ==
282
+ /* _JS_SOURCE_HASH = "b373f6ddbf1cf2e062379c9bad20cb62583833a5a820a5b5e0b2db8a6f27c602"; */
@@ -0,0 +1,111 @@
1
+ import fs from "fs/promises";
2
+ import os from "os";
3
+ import path from "path";
4
+ import { CONFIG_PATH } from "./daemon/paths";
5
+ import { readRepoKeys } from "./authorizedKeys";
6
+ import { sourceRepoPath } from "./sources";
7
+ import { expandHome } from "../helpers/paths";
8
+ import { spawnPromise } from "../helpers/spawn";
9
+
10
+ // The one place that answers "which keys repo". Everything that reads or writes one comes here:
11
+ // signing, unrevoking, machine trust, and adding a machine. They were each working it out their
12
+ // own way, which is how signfiles ended up signing whatever repo you happened to be standing in.
13
+ //
14
+ // Where a Windows machine is expected to keep it, relative to the working directory. There is no
15
+ // daemon there and no /etc, so a sibling checkout is the convention.
16
+ const WINDOWS_REPO_PATH = "../authorized_keys";
17
+
18
+ async function pathExists(filePath: string) {
19
+ try {
20
+ await fs.access(filePath);
21
+ return true;
22
+ } catch (e) {
23
+ return false;
24
+ }
25
+ }
26
+
27
+ /** A git checkout that actually holds keys. Both halves matter: a repo with no authorized_keys is
28
+ some other repo, and a directory that is not a checkout has nothing to push. */
29
+ async function isKeysRepo(repoPath: string) {
30
+ if (!await pathExists(path.join(repoPath, ".git"))) {
31
+ return false;
32
+ }
33
+ try {
34
+ await readRepoKeys(repoPath);
35
+ return true;
36
+ } catch (e) {
37
+ return false;
38
+ }
39
+ }
40
+
41
+ /** The repo the working directory is inside, or "" when it is not inside one. */
42
+ async function repoOfCurrentDirectory() {
43
+ // Read for its value, so stdout has to be on its own. runPromise joins it with stderr, and a
44
+ // git warning glued to the front of this becomes a directory that does not exist.
45
+ let topLevel = await spawnPromise({ command: "git", args: ["rev-parse", "--show-toplevel"] });
46
+ return topLevel.status === 0 && topLevel.stdout.trim() || "";
47
+ }
48
+
49
+ /** Where this machine's own keys repo is, when the working directory is not one.
50
+
51
+ On a host that is the checkout the daemon keeps up to date. On Windows there is no daemon, so
52
+ it is the sibling directory. */
53
+ async function configuredRepo() {
54
+ if (os.platform() === "win32") {
55
+ return path.resolve(WINDOWS_REPO_PATH);
56
+ }
57
+ let config = await fs.readFile(CONFIG_PATH, "utf8").catch(() => "");
58
+ let sourceURL = config && (JSON.parse(config).repoSources || [])[0] || "";
59
+ return sourceURL && sourceRepoPath(sourceURL) || "";
60
+ }
61
+
62
+ async function originOf(repoPath: string) {
63
+ let origin = await spawnPromise({ command: "git", args: ["remote", "get-url", "origin"], cwd: repoPath });
64
+ let url = origin.stdout.trim();
65
+ if (origin.status !== 0 || !url) {
66
+ throw new Error(`Expected ${repoPath} to have an origin remote, it has none`);
67
+ }
68
+ return url;
69
+ }
70
+
71
+ /** The keys repo to act on.
72
+
73
+ A named one if there is one, otherwise the repo the command is being run in if that repo holds
74
+ keys, otherwise this machine's own. Running in some other repo therefore reaches the keys repo
75
+ rather than acting on whatever happened to be around - signing sliftutils because that is where
76
+ the terminal was is never what anybody meant. */
77
+ export async function resolveKeysRepo(named?: string): Promise<{ repoPath: string; sourceURL: string }> {
78
+ let tried: string[] = [];
79
+
80
+ let candidates: string[] = [];
81
+ if (named) {
82
+ candidates.push(expandHome(named));
83
+ } else {
84
+ let current = await repoOfCurrentDirectory();
85
+ if (current) {
86
+ candidates.push(current);
87
+ }
88
+ let configured = await configuredRepo();
89
+ if (configured && configured !== current) {
90
+ candidates.push(configured);
91
+ }
92
+ }
93
+
94
+ for (let repoPath of candidates) {
95
+ if (await isKeysRepo(repoPath)) {
96
+ return { repoPath, sourceURL: await originOf(repoPath) };
97
+ }
98
+ tried.push(repoPath);
99
+ }
100
+
101
+ throw new Error(
102
+ `Expected a git repo holding authorized_keys, found none.\n`
103
+ + `Looked in:\n ${tried.join("\n ") || "(nowhere - this is not a git repo)"}\n`
104
+ + (os.platform() === "win32"
105
+ ? `On Windows the repo is read from ${path.resolve(WINDOWS_REPO_PATH)}, so clone it there:\n`
106
+ + ` git clone <your authorized_keys repo> ${path.resolve(WINDOWS_REPO_PATH)}`
107
+ : `Set this machine up, or run this from inside a keys repo:\n`
108
+ + ` yarn setupnotify <discord-webhook-url>\n`
109
+ + ` yarn securessh add <repo-private-key> <repo-url>`)
110
+ );
111
+ }
@@ -7,6 +7,7 @@ import { findSourceKey, KEYS_DIR_NAME, sourceKeyPath, sourceName, sourceRepoPath
7
7
  import { deriveRevokeKey, REVOKE_KEY_LABEL, revokeRepoURL } from "./revokeSource";
8
8
  import { legacySourceKeyPath } from "./sources";
9
9
  import { revokedKeysInRepo } from "./unrevoke";
10
+ import { resolveKeysRepo } from "./keysRepo";
10
11
  import { expandHome } from "../helpers/paths";
11
12
  import { spawnPromise } from "../helpers/spawn";
12
13
  import { describeHost, readRemoteFile, remoteCommandExists, runOverSSH, SUDO_PREAMBLE, THIS_MACHINE, writeRemoteFile } from "../helpers/remoteSSH";
@@ -155,38 +156,15 @@ async function cloneRepoForInspection(config: { repoURL: string; keyPath: string
155
156
  return repoPath;
156
157
  }
157
158
 
158
- /** With no repo url given, the repo we are standing in is used. It has to actually hold keys
159
- before we hand it to a host, so a stray working directory cannot be deployed by accident. */
159
+ /** With no repo url given, the keys repo this machine resolves to is used - the one we are
160
+ standing in when that holds keys, and this machine's own otherwise. */
160
161
  async function resolveRepoURL(passedURL: string | undefined) {
161
162
  if (passedURL) {
162
163
  return normalizeRepoURL(passedURL);
163
164
  }
164
- let topLevel = await runLocal({ command: "git", args: ["rev-parse", "--show-toplevel"], allowFailure: true });
165
- if (topLevel.status !== 0) {
166
- throw new Error(`Expected a repo url, or the current directory to be inside a git repo, it is not.\n${USAGE}`);
167
- }
168
- let repoPath = topLevel.stdout.trim();
169
- try {
170
- await readRepoKeys(repoPath);
171
- } catch (e) {
172
- throw new Error(
173
- `Expected a repo url, or the current repo (${repoPath}) to hold keys, it does not.\n${e}\n${USAGE}`
174
- );
175
- }
176
- let origin = await runLocal({
177
- command: "git",
178
- args: ["remote", "get-url", "origin"],
179
- cwd: repoPath,
180
- allowFailure: true,
181
- });
182
- if (origin.status !== 0 || !origin.stdout.trim()) {
183
- throw new Error(
184
- `Expected the current repo (${repoPath}) to have an origin remote, it has none.`
185
- + ` The host clones the source itself, so a local path is no use to it.`
186
- );
187
- }
188
- let repoURL = normalizeRepoURL(origin.stdout.trim());
189
- console.log(`No repo url given, using the current repo: ${repoURL}`);
165
+ let { repoPath, sourceURL } = await resolveKeysRepo();
166
+ let repoURL = normalizeRepoURL(sourceURL);
167
+ console.log(`No repo url given, using ${repoPath}: ${repoURL}`);
190
168
  return repoURL;
191
169
  }
192
170
 
@@ -638,6 +616,21 @@ function parseArgs(argv: string[]) {
638
616
  host = positional[0];
639
617
  positional = positional.slice(1);
640
618
  }
619
+
620
+ // How many arguments each verb takes, checked here rather than where the verb is acted on, so
621
+ // that a command which was typed wrong says so before anything else is complained about.
622
+ if (verb === "list" && positional.length) {
623
+ throw new Error(`Expected nothing after list, was ${positional.length} argument(s)\n${USAGE}`);
624
+ }
625
+ if (verb === "update" && positional.length) {
626
+ throw new Error(`Expected nothing after update, was ${positional.length} argument(s)\n${USAGE}`);
627
+ }
628
+ if (verb === "add" && (!positional.length || positional.length > 2)) {
629
+ throw new Error(`Expected a private key and optionally a repo url, was ${positional.length} argument(s)\n${USAGE}`);
630
+ }
631
+ if (verb === "remove" && positional.length > 1) {
632
+ throw new Error(`Expected at most a repo url to remove, was ${positional.length} argument(s)\n${USAGE}`);
633
+ }
641
634
  return { verb, host, rest: positional };
642
635
  }
643
636
 
@@ -655,29 +648,26 @@ function requireRoot() {
655
648
  }
656
649
 
657
650
  export async function main() {
658
- requireRoot();
651
+ // What was typed is checked before anything about this machine is. A command that does not
652
+ // make sense is worth saying so about whoever is running it, and being told to find sudo only
653
+ // to then be told the arguments were wrong is two trips for one mistake.
659
654
  let { verb, host, rest } = parseArgs(process.argv.slice(2));
655
+ // With a host, everything root-owned happens on that host through $SUDO over ssh, so being root here proves nothing and would block running this from a workstation.
656
+ if (host === THIS_MACHINE) {
657
+ requireRoot();
658
+ }
660
659
 
661
660
  if (verb === "list") {
662
661
  await listSources(host);
663
662
  return;
664
663
  }
665
664
  if (verb === "update") {
666
- if (rest.length) {
667
- throw new Error(`Expected nothing after update, was ${rest.length} argument(s)\n${USAGE}`);
668
- }
669
665
  await updateDaemon(host);
670
666
  return;
671
667
  }
672
668
  if (verb === "add") {
673
- if (!rest.length || rest.length > 2) {
674
- throw new Error(`Expected a private key and optionally a repo url, was ${rest.length} argument(s)\n${USAGE}`);
675
- }
676
669
  await addSource({ host, keyPath: expandHome(rest[0]), repoURL: await resolveRepoURL(rest[1]) });
677
670
  return;
678
671
  }
679
- if (rest.length > 1) {
680
- throw new Error(`Expected at most a repo url to remove, was ${rest.length} argument(s)\n${USAGE}`);
681
- }
682
672
  await removeSource({ host, repoURL: await resolveRepoURL(rest[0]) });
683
673
  }