sliftutils 1.7.136 → 1.7.138

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 (38) hide show
  1. package/bin/printmachineid.js +5 -0
  2. package/examplestorage/browser.tsx +2 -2
  3. package/index.d.ts +10 -4
  4. package/misc/dist/strings.ts.cache +2 -2
  5. package/misc/https/certs.d.ts +6 -1
  6. package/misc/https/certs.ts +11 -2
  7. package/misc/https/dist/certs.ts.cache +14 -5
  8. package/misc/https/dist/persistentLocalStorage.ts.cache +14 -4
  9. package/misc/https/persistentLocalStorage.d.ts +1 -0
  10. package/misc/https/persistentLocalStorage.ts +10 -0
  11. package/package.json +5 -3
  12. package/security/authorizedKeys/daemon/daemon.ts +4 -3
  13. package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
  14. package/security/authorizedKeys/daemon/dist/trust.ts.cache +126 -4
  15. package/security/authorizedKeys/daemon/revocation.d.ts +4 -7
  16. package/security/authorizedKeys/daemon/revocation.ts +0 -0
  17. package/security/authorizedKeys/daemon/trust.d.ts +12 -1
  18. package/security/authorizedKeys/daemon/trust.ts +124 -1
  19. package/security/authorizedKeys/dist/unrevoke.ts.cache +5 -186
  20. package/security/authorizedKeys/dist/unrevokeCli.ts.cache +195 -0
  21. package/security/machines/dist/machines.ts.cache +20 -68
  22. package/security/machines/dist/printMachineId.ts.cache +21 -0
  23. package/security/machines/identity2.ts +94 -6
  24. package/security/machines/machines.ts +27 -76
  25. package/security/machines/printMachineId.ts +19 -0
  26. package/security/signedFiles/dist/signFiles.ts.cache +16 -52
  27. package/storage/remoteStorage/ArchivesRemote.d.ts +1 -1
  28. package/storage/remoteStorage/ArchivesRemote.ts +14 -8
  29. package/storage/remoteStorage/accessPage.tsx +7 -123
  30. package/storage/remoteStorage/createArchives.d.ts +1 -1
  31. package/storage/remoteStorage/createArchives.ts +1 -1
  32. package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +14 -7
  33. package/storage/remoteStorage/dist/createArchives.ts.cache +2 -2
  34. package/storage/remoteStorage/dist/sourceWrapper.ts.cache +3 -3
  35. package/storage/remoteStorage/dist/storageController.ts.cache +8 -7
  36. package/storage/remoteStorage/sourceWrapper.ts +1 -1
  37. package/storage/remoteStorage/storageController.d.ts +1 -1
  38. package/storage/remoteStorage/storageController.ts +10 -10
@@ -3,18 +3,65 @@ 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.readSignedRepo = exports.SignedRepoError = exports.UNSIGNED = void 0;
6
+ //exports.readSignedRepo = exports.SignedRepoError = exports.noteRevocation = exports.isPairUnrevoked = exports.isPairRevoked = exports.isIdentityFrozen = exports.UNSIGNED = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  const promises_1 = __importDefault(require("fs/promises"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const manifest_1 = require("../../signedFiles/manifest");
11
11
  const sshsig_1 = require("../../signedFiles/sshsig");
12
+ const authorizedKeys_1 = require("../authorizedKeys");
13
+ const revokeSource_1 = require("../revokeSource");
12
14
  // A source that has never been signed reads as this, so losing a signature counts as a change of
13
15
  // signer rather than as something to wave through.
14
16
  exports.UNSIGNED = "";
15
17
  // What fixes both of the signature problems we report, so the message can say so rather than
16
18
  // leaving someone to work it out.
17
19
  const SIGN_COMMAND = "yarn signfiles git";
20
+ const REVOCATIONS_DIR = "revocations";
21
+ const UNREVOKES_DIR = "unrevoked";
22
+ // Every revocation this process has ever seen, keyed by revocation id. Once absorbed a revocation
23
+ // never leaves, even if its file disappears from the revoke repo - the key that writes revocations
24
+ // is on every server, so whoever stole one could otherwise erase the record that shut them out.
25
+ // Restarting the process is the way back from a revocation that should not have happened.
26
+ let absorbedRevocations = new Map();
27
+ // The pairs the signed unrevokes allow, and the legacy revocation ids they name. Rebuilt on every
28
+ // read, since unrevokes are signed content and removing one must take effect.
29
+ let unrevokedPairs = new Set();
30
+ let unrevokedIds = new Set();
31
+ /** Whether an identity - a key fingerprint or a machine id - has a revocation nothing has undone.
32
+ The one meaning of "frozen", used both when stripping repo content and when explaining why. */
33
+ function isIdentityFrozen(identity) {
34
+ for (let [revocationId, revocation] of absorbedRevocations) {
35
+ if (revocation.identity !== identity) {
36
+ continue;
37
+ }
38
+ if (unrevokedIds.has(revocationId) || unrevokedPairs.has(`${identity} ${revocation.ip}`)) {
39
+ continue;
40
+ }
41
+ return true;
42
+ }
43
+ return false;
44
+ }
45
+ exports.isIdentityFrozen = isIdentityFrozen;
46
+ function isPairRevoked(identity, ip) {
47
+ for (let [revocationId, revocation] of absorbedRevocations) {
48
+ if (revocation.identity === identity && revocation.ip === ip && !unrevokedIds.has(revocationId)) {
49
+ return true;
50
+ }
51
+ }
52
+ return false;
53
+ }
54
+ exports.isPairRevoked = isPairRevoked;
55
+ function isPairUnrevoked(identity, ip) {
56
+ return unrevokedPairs.has(`${identity} ${ip}`);
57
+ }
58
+ exports.isPairUnrevoked = isPairUnrevoked;
59
+ /** For whoever just wrote a revocation, so it holds here immediately rather than on the next
60
+ absorb. Sticky like the rest. */
61
+ function noteRevocation(revocationId, identity, ip) {
62
+ absorbedRevocations.set(revocationId, { identity, ip });
63
+ }
64
+ exports.noteRevocation = noteRevocation;
18
65
  /** A repo that cannot be trusted, with the message ready for whoever asked. Not every caller
19
66
  treats these the same - a source keeps its last keys, a machine list is just refused - so the
20
67
  kind is carried rather than acted on here. */
@@ -35,7 +82,9 @@ exports.SignedRepoError = SignedRepoError;
35
82
  without re-signing - either way the caller keeps whatever it last accepted rather than believing
36
83
  a repo that no longer matches what was signed. A file not in the manifest is just unsigned, so
37
84
  it is left out and warned about rather than treated as tampering. */
38
- async function readSignedRepo(repoPath) {
85
+ async function readSignedRepo(config) {
86
+ var _a;
87
+ let { repoPath, sourceURL } = config;
39
88
  let manifestBytes = await promises_1.default.readFile(path_1.default.join(repoPath, manifest_1.MANIFEST_NAME)).catch(() => undefined);
40
89
  let signatureBytes = await promises_1.default.readFile(path_1.default.join(repoPath, manifest_1.SIGNATURE_NAME)).catch(() => undefined);
41
90
  let manifestHash = manifestBytes && crypto_1.default.createHash("sha256").update(manifestBytes).digest("hex") || "";
@@ -108,8 +157,81 @@ async function readSignedRepo(repoPath) {
108
157
  throw stale(`${path_1.default.join(repoPath, filePath)} is signed for but missing`);
109
158
  }
110
159
  }
160
+ // Absorb the revoke repo's files into the sticky map. Once seen a revocation never leaves it,
161
+ // even if its file disappears - the key that writes revocations is on every server, so whoever
162
+ // stole one could otherwise erase the record that shut them out.
163
+ let revocationsDirectory = path_1.default.join((0, revokeSource_1.revokeRepoPath)(sourceURL), REVOCATIONS_DIR);
164
+ for (let name of (await promises_1.default.readdir(revocationsDirectory).catch(() => [])).sort()) {
165
+ if (!name.endsWith(".json")) {
166
+ continue;
167
+ }
168
+ try {
169
+ let parsed = JSON.parse(await promises_1.default.readFile(path_1.default.join(revocationsDirectory, name), "utf8"));
170
+ let identity = parsed.fingerprint || parsed.machineId;
171
+ if (!identity) {
172
+ continue;
173
+ }
174
+ let revocationId = parsed.revocationId || name.replace(/\.json$/, "");
175
+ if (!absorbedRevocations.has(revocationId)) {
176
+ absorbedRevocations.set(revocationId, { identity, ip: parsed.ip || ((_a = parsed.attempt) === null || _a === void 0 ? void 0 : _a.ip) || "" });
177
+ }
178
+ }
179
+ catch (e) {
180
+ console.log(`Ignoring unreadable revocation ${path_1.default.join(revocationsDirectory, name)}. ${e}`);
181
+ }
182
+ }
183
+ // Rebuild the unrevokes from the signed files just read. Unrevokes are signed content, so
184
+ // removing one must take effect, unlike the sticky revocations.
185
+ unrevokedPairs = new Set();
186
+ unrevokedIds = new Set();
187
+ for (let [filePath, contents] of files) {
188
+ if (!filePath.startsWith(`${UNREVOKES_DIR}/`) || !filePath.endsWith(".json")) {
189
+ continue;
190
+ }
191
+ try {
192
+ let parsed = JSON.parse(contents.toString("utf8"));
193
+ for (let allowed of parsed.allowed || []) {
194
+ let identity = allowed.fingerprint || allowed.machineId;
195
+ if (identity && allowed.ip) {
196
+ unrevokedPairs.add(`${identity} ${allowed.ip}`);
197
+ }
198
+ }
199
+ for (let revocationId of parsed.revocationIds || []) {
200
+ unrevokedIds.add(revocationId);
201
+ }
202
+ }
203
+ catch (e) {
204
+ console.log(`Ignoring unreadable unrevoke ${filePath}. ${e}`);
205
+ }
206
+ }
207
+ // Drop everything frozen: revoked keys out of authorized_keys and top level .pub files, and
208
+ // frozen machines' files out of machines/. What comes back is what this machine actually
209
+ // trusts, so no caller can read the list and forget the revocations.
210
+ for (let [filePath, contents] of [...files]) {
211
+ if (filePath === "authorized_keys" || (filePath.endsWith(".pub") && !filePath.includes("/"))) {
212
+ let lines = contents.toString("utf8").split("\n");
213
+ let kept = lines.filter(line => {
214
+ let fingerprint = (0, authorizedKeys_1.keyFingerprint)(line);
215
+ if (fingerprint && isIdentityFrozen(fingerprint)) {
216
+ console.log(`Dropping revoked key ${fingerprint} from ${path_1.default.join(repoPath, filePath)}`);
217
+ return false;
218
+ }
219
+ return true;
220
+ });
221
+ if (kept.length !== lines.length) {
222
+ files.set(filePath, Buffer.from(kept.join("\n")));
223
+ }
224
+ }
225
+ if (filePath.startsWith("machines/") && filePath.endsWith(".json")) {
226
+ let machineId = filePath.slice("machines/".length, -".json".length);
227
+ if (isIdentityFrozen(machineId)) {
228
+ console.log(`Dropping frozen machine ${machineId} from ${path_1.default.join(repoPath, filePath)}`);
229
+ files.delete(filePath);
230
+ }
231
+ }
232
+ }
111
233
  return { signer, manifestHash, signatureHash, files };
112
234
  }
113
235
  exports.readSignedRepo = readSignedRepo;
114
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJ1c3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0cnVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUN4Qix5REFBNkc7QUFDN0cscURBQXdEO0FBRXhELGlHQUFpRztBQUNqRyxtREFBbUQ7QUFDdEMsUUFBQSxRQUFRLEdBQUcsRUFBRSxDQUFDO0FBQzNCLDZGQUE2RjtBQUM3RixrQ0FBa0M7QUFDbEMsTUFBTSxZQUFZLEdBQUcsb0JBQW9CLENBQUM7QUFFMUM7O2lEQUVpRDtBQUNqRCxNQUFhLGVBQWdCLFNBQVEsS0FBSztJQUN0QyxZQUFtQixPQUFlLEVBQVMsUUFBZ0IsRUFBUyxJQUFZO1FBQzVFLEtBQUssQ0FBQyxHQUFHLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRGYsWUFBTyxHQUFQLE9BQU8sQ0FBUTtRQUFTLGFBQVEsR0FBUixRQUFRLENBQVE7UUFBUyxTQUFJLEdBQUosSUFBSSxDQUFRO0lBRWhGLENBQUM7Q0FDSjtBQUpELDBDQUlDO0FBRUQ7Ozs7Ozs7d0VBT3dFO0FBQ2pFLEtBQUssVUFBVSxjQUFjLENBQUMsUUFBZ0I7SUFNakQsSUFBSSxhQUFhLEdBQUcsTUFBTSxrQkFBRSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSx3QkFBYSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDakcsSUFBSSxjQUFjLEdBQUcsTUFBTSxrQkFBRSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSx5QkFBYyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkcsSUFBSSxZQUFZLEdBQUcsYUFBYSxJQUFJLGdCQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxD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QUMsSUFBSSxJQUFJLElBQUksS0FBSyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEUsTUFBTSxLQUFLLENBQUMsR0FBRyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBQ0QsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUNELEtBQUssSUFBSSxRQUFRLElBQUksTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUN2QixNQUFNLEtBQUssQ0FBQyxHQUFHLGNBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO1FBQzlFLENBQUM7SUFDTCxDQUFDO0lBRUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxDQUFDO0FBQzFELENBQUM7QUE5RkQsd0NBOEZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgTUFOSUZFU1RfTkFNRSwgbm9ybWFsaXplQ29udGVudCwgU0lHTl9OQU1FU1BBQ0UsIFNJR05BVFVSRV9OQU1FIH0gZnJvbSBcIi4uLy4uL3NpZ25lZEZpbGVzL21hbmlmZXN0XCI7XG5pbXBvcnQgeyB2ZXJpZnlTU0hTSUcgfSBmcm9tIFwiLi4vLi4vc2lnbmVkRmlsZXMvc3Noc2lnXCI7XG5cbi8vIEEgc291cmNlIHRoYXQgaGFzIG5ldmVyIGJlZW4gc2lnbmVkIHJlYWRzIGFzIHRoaXMsIHNvIGxvc2luZyBhIHNpZ25hdHVyZSBjb3VudHMgYXMgYSBjaGFuZ2Ugb2Zcbi8vIHNpZ25lciByYXRoZXIgdGhhbiBhcyBzb21ldGhpbmcgdG8gd2F2ZSB0aHJvdWdoLlxuZXhwb3J0IGNvbnN0IFVOU0lHTkVEID0gXCJcIjtcbi8vIFdoYXQgZml4ZXMgYm90aCBvZiB0aGUgc2lnbmF0dXJlIHByb2JsZW1zIHdlIHJlcG9ydCwgc28gdGhlIG1lc3NhZ2UgY2FuIHNheSBzbyByYXRoZXIgdGhhblxuLy8gbGVhdmluZyBzb21lb25lIHRvIHdvcmsgaXQgb3V0LlxuY29uc3QgU0lHTl9DT01NQU5EID0gXCJ5YXJuIHNpZ25maWxlcyBnaXRcIjtcblxuLyoqIEEgcmVwbyB0aGF0IGNhbm5vdCBiZSB0cnVzdGVkLCB3aXRoIHRoZSBtZXNzYWdlIHJlYWR5IGZvciB3aG9ldmVyIGFza2VkLiBOb3QgZXZlcnkgY2FsbGVyXG4gICAgdHJlYXRzIHRoZXNlIHRoZSBzYW1lIC0gYSBzb3VyY2Uga2VlcHMgaXRzIGxhc3Qga2V5cywgYSBtYWNoaW5lIGxpc3QgaXMganVzdCByZWZ1c2VkIC0gc28gdGhlXG4gICAga2luZCBpcyBjYXJyaWVkIHJhdGhlciB0aGFuIGFjdGVkIG9uIGhlcmUuICovXG5leHBvcnQgY2xhc3MgU2lnbmVkUmVwb0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuICAgIGNvbnN0cnVjdG9yKHB1YmxpYyBwcm9ibGVtOiBzdHJpbmcsIHB1YmxpYyBoZWFkbGluZTogc3RyaW5nLCBwdWJsaWMgYm9keTogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKGAke2hlYWRsaW5lfS4gJHtib2R5fWApO1xuICAgIH1cbn1cblxuLyoqIEV2ZXJ5dGhpbmcgYSBzaWduZWQgY2hlY2tvdXQgdm91Y2hlcyBmb3IsIGluIG9uZSBjYWxsOiB3aG8gc2lnbmVkIGl0LCBhbmQgdGhlIGNvbnRlbnRzIG9mIGV2ZXJ5XG4gICAgZmlsZSB0aGUgc2lnbmF0dXJlIGFjdHVhbGx5IGNvdmVycy5cblxuICAgIFVOU0lHTkVEIHdpdGggbm8gZmlsZXMgd2hlbiB0aGVyZSBpcyBubyBzaWduYXR1cmUgYXQgYWxsLiBUaHJvd3MgYSBTaWduZWRSZXBvRXJyb3Igd2hlbiBhXG4gICAgc2lnbmF0dXJlIGlzIHByZXNlbnQgYnV0IGRvZXMgbm90IGhvbGQgdXAsIG9yIHdoZW4gYSBmaWxlIGl0IHNpZ25lZCBmb3Igd2FzIGNoYW5nZWQgb3IgcmVtb3ZlZFxuICAgIHdpdGhvdXQgcmUtc2lnbmluZyAtIGVpdGhlciB3YXkgdGhlIGNhbGxlciBrZWVwcyB3aGF0ZXZlciBpdCBsYXN0IGFjY2VwdGVkIHJhdGhlciB0aGFuIGJlbGlldmluZ1xuICAgIGEgcmVwbyB0aGF0IG5vIGxvbmdlciBtYXRjaGVzIHdoYXQgd2FzIHNpZ25lZC4gQSBmaWxlIG5vdCBpbiB0aGUgbWFuaWZlc3QgaXMganVzdCB1bnNpZ25lZCwgc29cbiAgICBpdCBpcyBsZWZ0IG91dCBhbmQgd2FybmVkIGFib3V0IHJhdGhlciB0aGFuIHRyZWF0ZWQgYXMgdGFtcGVyaW5nLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRTaWduZWRSZXBvKHJlcG9QYXRoOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgICBzaWduZXI6IHN0cmluZztcbiAgICBtYW5pZmVzdEhhc2g6IHN0cmluZztcbiAgICBzaWduYXR1cmVIYXNoOiBzdHJpbmc7XG4gICAgZmlsZXM6IE1hcDxzdHJpbmcsIEJ1ZmZlcj47XG59PiB7XG4gICAgbGV0IG1hbmlmZXN0Qnl0ZXMgPSBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4ocmVwb1BhdGgsIE1BTklGRVNUX05BTUUpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGxldCBzaWduYXR1cmVCeXRlcyA9IGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgU0lHTkFUVVJFX05BTUUpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGxldCBtYW5pZmVzdEhhc2ggPSBtYW5pZmVzdEJ5dGVzICYmIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShtYW5pZmVzdEJ5dGVzKS5kaWdlc3QoXCJoZXhcIikgfHwgXCJcIjtcbiAgICBsZXQgc2lnbmF0dXJlSGFzaCA9IHNpZ25hdHVyZUJ5dGVzICYmIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShzaWduYXR1cmVCeXRlcykuZGlnZXN0KFwiaGV4XCIpIHx8IFwiXCI7XG5cbiAgICBpZiAoIW1hbmlmZXN0Qnl0ZXMgJiYgIXNpZ25hdHVyZUJ5dGVzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke3JlcG9QYXRofSBpcyBub3Qgc2lnbmVkLCBpZ25vcmluZyBhbGwgb2YgaXRzIGZpbGVzYCk7XG4gICAgICAgIHJldHVybiB7IHNpZ25lcjogVU5TSUdORUQsIG1hbmlmZXN0SGFzaCwgc2lnbmF0dXJlSGFzaCwgZmlsZXM6IG5ldyBNYXAoKSB9O1xuICAgIH1cblxuICAgIGxldCBicm9rZW4gPSAoZGV0YWlsOiBzdHJpbmcpID0+IG5ldyBTaWduZWRSZXBvRXJyb3IoXG4gICAgICAgIFwiY29ycnVwdFwiLFxuICAgICAgICBgS0VZIFJFUE8gU0lHTkFUVVJFIElTIEJST0tFTmAsXG4gICAgICAgIGBUaGUgc2lnbmF0dXJlIG9uICR7cmVwb1BhdGh9IGRvZXMgbm90IGNoZWNrIG91dCwgc28gZXZlcnl0aGluZyBpbiBpdCBpcyBiZWluZyBpZ25vcmVkIGFuZGBcbiAgICAgICAgKyBgIHRoaXMgbWFjaGluZSBrZWVwcyB1c2luZyB3aGF0IGl0IGxhc3QgYWNjZXB0ZWQuXFxuXFxuJHtkZXRhaWx9YFxuICAgICAgICArIGBcXG5cXG5UbyByZXBsYWNlIHRoZSBzaWduYXR1cmUsIHJ1biBpbiB0aGF0IHJlcG86XFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYFxuICAgICk7XG4gICAgaWYgKCFtYW5pZmVzdEJ5dGVzIHx8ICFzaWduYXR1cmVCeXRlcykge1xuICAgICAgICB0aHJvdyBicm9rZW4oYE9ubHkgb25lIG9mICR7TUFOSUZFU1RfTkFNRX0gYW5kICR7U0lHTkFUVVJFX05BTUV9IGlzIHByZXNlbnQuYCk7XG4gICAgfVxuXG4gICAgbGV0IHNpZ25lcjogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICAgIC8vIFRoZSBzaWduYXR1cmUgY292ZXJzIHRoZSBub3JtYWxpc2VkIGJ5dGVzLCBzbyBhIGNoZWNrb3V0IHRoYXQgYXJyaXZlZCB3aXRoIENSTEYgc3RpbGxcbiAgICAgICAgLy8gdmVyaWZpZXMgcmF0aGVyIHRoYW4gbG9va2luZyBsaWtlIHRhbXBlcmluZy5cbiAgICAgICAgc2lnbmVyID0gdmVyaWZ5U1NIU0lHKHtcbiAgICAgICAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlQnl0ZXMudG9TdHJpbmcoXCJ1dGY4XCIpLFxuICAgICAgICAgICAgbWVzc2FnZTogbm9ybWFsaXplQ29udGVudChtYW5pZmVzdEJ5dGVzKSxcbiAgICAgICAgICAgIG5hbWVzcGFjZTogU0lHTl9OQU1FU1BBQ0UsXG4gICAgICAgIH0pLnB1YmxpY0tleTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IGJyb2tlbihgJHtlfWApO1xuICAgIH1cblxuICAgIGxldCBzdGFsZSA9IChkZXRhaWw6IHN0cmluZykgPT4gbmV3IFNpZ25lZFJlcG9FcnJvcihcbiAgICAgICAgXCJzdGFsZVwiLFxuICAgICAgICBgS0VZIFJFUE8gQ0hBTkdFRCBXSVRIT1VUIEJFSU5HIFNJR05FRGAsXG4gICAgICAgIGAke2RldGFpbH0sIHNvIHRoZSByZXBvIGlzIGJlaW5nIGlnbm9yZWQgYW5kIHRoaXMgbWFjaGluZSBrZWVwcyB1c2luZyB3aGF0IGl0IGxhc3QgYWNjZXB0ZWQuYFxuICAgICAgICArIGBcXG5cXG5UbyBtYWtlIHRoZSBjaGFuZ2UgdGFrZSBlZmZlY3QsIHJ1biBpbiB0aGF0IHJlcG86XFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYFxuICAgICk7XG5cbiAgICAvLyBFdmVyeSBmaWxlIG9uIGRpc2ssIG90aGVyIHRoYW4gZ2l0J3Mgb3duIGRpcmVjdG9yeSBhbmQgdGhlIHR3byBzaWduYXR1cmUgZmlsZXMsIHdoaWNoIGNhbm5vdFxuICAgIC8vIGRlc2NyaWJlIHRoZW1zZWx2ZXMuXG4gICAgbGV0IGxpc3RDaGVja291dEZpbGVzID0gYXN5bmMgKHByZWZpeD86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+ID0+IHtcbiAgICAgICAgbGV0IGZvdW5kOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBlbnRyeSBvZiBhd2FpdCBmcy5yZWFkZGlyKHBhdGguam9pbihyZXBvUGF0aCwgcHJlZml4IHx8IFwiXCIpLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHtcbiAgICAgICAgICAgIGxldCByZWxhdGl2ZVBhdGggPSBwcmVmaXggJiYgYCR7cHJlZml4fS8ke2VudHJ5Lm5hbWV9YCB8fCBlbnRyeS5uYW1lO1xuICAgICAgICAgICAgaWYgKGVudHJ5Lm5hbWUgPT09IFwiLmdpdFwiKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghcHJlZml4ICYmIChlbnRyeS5uYW1lID09PSBNQU5JRkVTVF9OQU1FIHx8IGVudHJ5Lm5hbWUgPT09IFNJR05BVFVSRV9OQU1FKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgICAgIGZvdW5kLnB1c2goLi4uYXdhaXQgbGlzdENoZWNrb3V0RmlsZXMocmVsYXRpdmVQYXRoKSk7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3VuZC5wdXNoKHJlbGF0aXZlUGF0aCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZvdW5kLnNvcnQoKTtcbiAgICB9O1xuXG4gICAgbGV0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShtYW5pZmVzdEJ5dGVzLnRvU3RyaW5nKFwidXRmOFwiKSk7XG4gICAgbGV0IGxpc3RlZCA9IG5ldyBNYXA8c3RyaW5nLCB7IHNpemU6IG51bWJlcjsgc2hhMjU2OiBzdHJpbmcgfT4oXG4gICAgICAgIChtYW5pZmVzdC5maWxlcyB8fCBbXSkubWFwKChmaWxlOiB7IHBhdGg6IHN0cmluZzsgc2l6ZTogbnVtYmVyOyBzaGEyNTY6IHN0cmluZyB9KSA9PiBbZmlsZS5wYXRoLCBmaWxlXSlcbiAgICApO1xuXG4gICAgbGV0IGZpbGVzID0gbmV3IE1hcDxzdHJpbmcsIEJ1ZmZlcj4oKTtcbiAgICBmb3IgKGxldCBmaWxlUGF0aCBvZiBhd2FpdCBsaXN0Q2hlY2tvdXRGaWxlcygpKSB7XG4gICAgICAgIGxldCBleHBlY3RlZCA9IGxpc3RlZC5nZXQoZmlsZVBhdGgpO1xuICAgICAgICAvLyBBIGZpbGUgdGhlIHNpZ25hdHVyZSBuZXZlciBtZW50aW9uZWQgaXMgbm90IHRhbXBlcmluZywgaXQgaXMganVzdCB1bnNpZ25lZCAtIGxlZnQgb3V0XG4gICAgICAgIC8vIHJhdGhlciB0aGFuIHRydXN0ZWQuIEFuIGV4dHJhIGZpbGUgaW4gYSB3b3JraW5nIHRyZWUgaXMgb3JkaW5hcnksIHNvIGl0IGlzIG9ubHkgYSBub3RlLlxuICAgICAgICBpZiAoIWV4cGVjdGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgSWdub3JpbmcgJHtwYXRoLmpvaW4ocmVwb1BhdGgsIGZpbGVQYXRoKX0sIGl0IGlzIG5vdCBpbiB0aGUgc2lnbmVkIG1hbmlmZXN0YCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgY29udGVudHMgPSBub3JtYWxpemVDb250ZW50KGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpKSk7XG4gICAgICAgIGxldCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGNvbnRlbnRzKS5kaWdlc3QoXCJoZXhcIik7XG4gICAgICAgIC8vIEEgZmlsZSB0aGUgbWFuaWZlc3QgRE9FUyBuYW1lLCBidXQgd2hvc2UgY29udGVudCBubyBsb25nZXIgbWF0Y2hlcywgaXMgYSBzaWduZWQgZmlsZVxuICAgICAgICAvLyBjaGFuZ2VkIHdpdGhvdXQgcmUtc2lnbmluZyAtIHRoZSByZXBvIGJlaW5nIGVkaXRlZCBvdXQgZnJvbSB1bmRlciBpdHMgc2lnbmF0dXJlLlxuICAgICAgICBpZiAoY29udGVudHMubGVuZ3RoICE9PSBleHBlY3RlZC5zaXplIHx8IGhhc2ggIT09IGV4cGVjdGVkLnNoYTI1Nikge1xuICAgICAgICAgICAgdGhyb3cgc3RhbGUoYCR7cGF0aC5qb2luKHJlcG9QYXRoLCBmaWxlUGF0aCl9IHdhcyBjaGFuZ2VkIGFmdGVyIGl0IHdhcyBzaWduZWRgKTtcbiAgICAgICAgfVxuICAgICAgICBmaWxlcy5zZXQoZmlsZVBhdGgsIGNvbnRlbnRzKTtcbiAgICB9XG4gICAgZm9yIChsZXQgZmlsZVBhdGggb2YgbGlzdGVkLmtleXMoKSkge1xuICAgICAgICBpZiAoIWZpbGVzLmhhcyhmaWxlUGF0aCkpIHtcbiAgICAgICAgICAgIHRocm93IHN0YWxlKGAke3BhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpfSBpcyBzaWduZWQgZm9yIGJ1dCBtaXNzaW5nYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4geyBzaWduZXIsIG1hbmlmZXN0SGFzaCwgc2lnbmF0dXJlSGFzaCwgZmlsZXMgfTtcbn1cbiJdfQ==
115
- /* _JS_SOURCE_HASH = "7efe11ad80e1fd0da4255a229551a7973443a58b48163d836cf32e330cced446"; */
236
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJ1c3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0cnVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUN4Qix5REFBNkc7QUFDN0cscURBQXdEO0FBQ3hELHNEQUFtRDtBQUNuRCxrREFBaUQ7QUFFakQsaUdBQWlHO0FBQ2pHLG1EQUFtRDtBQUN0QyxRQUFBLFFBQVEsR0FBRyxFQUFFLENBQUM7QUFDM0IsNkZBQTZGO0FBQzdGLGtDQUFrQztBQUNsQyxNQUFNLFlBQVksR0FBRyxvQkFBb0IsQ0FBQztBQUMxQyxNQUFNLGVBQWUsR0FBRyxhQUFhLENBQUM7QUFDdEMsTUFBTSxhQUFhLEdBQUcsV0FBVyxDQUFDO0FBRWxDLGtHQUFrRztBQUNsRyxtR0FBbUc7QUFDbkcsZ0dBQWdHO0FBQ2hHLDBGQUEwRjtBQUMxRixJQUFJLG1CQUFtQixHQUFHLElBQUksR0FBRyxFQUE0QyxDQUFDO0FBQzlFLGtHQUFrRztBQUNsRyw4RUFBOEU7QUFDOUUsSUFBSSxjQUFjLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztBQUN2QyxJQUFJLFlBQVksR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0FBRXJDO2tHQUNrRztBQUNsRyxTQUFnQixnQkFBZ0IsQ0FBQyxRQUFnQjtJQUM3QyxLQUFLLElBQUksQ0FBQyxZQUFZLEVBQUUsVUFBVSxDQUFDLElBQUksbUJBQW1CLEVBQUUsQ0FBQztRQUN6RCxJQUFJLFVBQVUsQ0FBQyxRQUFRLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDbkMsU0FBUztRQUNiLENBQUM7UUFDRCxJQUFJLFlBQVksQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsSUFBSSxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3ZGLFNBQVM7UUFDYixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7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LFFBQVEsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ2pFLElBQUksU0FBUyxHQUFHLFFBQVEsQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNwRSxJQUFJLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7Z0JBQzlCLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLFNBQVMsU0FBUyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQzFGLEtBQUssQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDM0IsQ0FBQztRQUNMLENBQUM7SUFDTCxDQUFDO0lBRUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxDQUFDO0FBQzFELENBQUM7QUF6S0Qsd0NBeUtDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgTUFOSUZFU1RfTkFNRSwgbm9ybWFsaXplQ29udGVudCwgU0lHTl9OQU1FU1BBQ0UsIFNJR05BVFVSRV9OQU1FIH0gZnJvbSBcIi4uLy4uL3NpZ25lZEZpbGVzL21hbmlmZXN0XCI7XG5pbXBvcnQgeyB2ZXJpZnlTU0hTSUcgfSBmcm9tIFwiLi4vLi4vc2lnbmVkRmlsZXMvc3Noc2lnXCI7XG5pbXBvcnQgeyBrZXlGaW5nZXJwcmludCB9IGZyb20gXCIuLi9hdXRob3JpemVkS2V5c1wiO1xuaW1wb3J0IHsgcmV2b2tlUmVwb1BhdGggfSBmcm9tIFwiLi4vcmV2b2tlU291cmNlXCI7XG5cbi8vIEEgc291cmNlIHRoYXQgaGFzIG5ldmVyIGJlZW4gc2lnbmVkIHJlYWRzIGFzIHRoaXMsIHNvIGxvc2luZyBhIHNpZ25hdHVyZSBjb3VudHMgYXMgYSBjaGFuZ2Ugb2Zcbi8vIHNpZ25lciByYXRoZXIgdGhhbiBhcyBzb21ldGhpbmcgdG8gd2F2ZSB0aHJvdWdoLlxuZXhwb3J0IGNvbnN0IFVOU0lHTkVEID0gXCJcIjtcbi8vIFdoYXQgZml4ZXMgYm90aCBvZiB0aGUgc2lnbmF0dXJlIHByb2JsZW1zIHdlIHJlcG9ydCwgc28gdGhlIG1lc3NhZ2UgY2FuIHNheSBzbyByYXRoZXIgdGhhblxuLy8gbGVhdmluZyBzb21lb25lIHRvIHdvcmsgaXQgb3V0LlxuY29uc3QgU0lHTl9DT01NQU5EID0gXCJ5YXJuIHNpZ25maWxlcyBnaXRcIjtcbmNvbnN0IFJFVk9DQVRJT05TX0RJUiA9IFwicmV2b2NhdGlvbnNcIjtcbmNvbnN0IFVOUkVWT0tFU19ESVIgPSBcInVucmV2b2tlZFwiO1xuXG4vLyBFdmVyeSByZXZvY2F0aW9uIHRoaXMgcHJvY2VzcyBoYXMgZXZlciBzZWVuLCBrZXllZCBieSByZXZvY2F0aW9uIGlkLiBPbmNlIGFic29yYmVkIGEgcmV2b2NhdGlvblxuLy8gbmV2ZXIgbGVhdmVzLCBldmVuIGlmIGl0cyBmaWxlIGRpc2FwcGVhcnMgZnJvbSB0aGUgcmV2b2tlIHJlcG8gLSB0aGUga2V5IHRoYXQgd3JpdGVzIHJldm9jYXRpb25zXG4vLyBpcyBvbiBldmVyeSBzZXJ2ZXIsIHNvIHdob2V2ZXIgc3RvbGUgb25lIGNvdWxkIG90aGVyd2lzZSBlcmFzZSB0aGUgcmVjb3JkIHRoYXQgc2h1dCB0aGVtIG91dC5cbi8vIFJlc3RhcnRpbmcgdGhlIHByb2Nlc3MgaXMgdGhlIHdheSBiYWNrIGZyb20gYSByZXZvY2F0aW9uIHRoYXQgc2hvdWxkIG5vdCBoYXZlIGhhcHBlbmVkLlxubGV0IGFic29yYmVkUmV2b2NhdGlvbnMgPSBuZXcgTWFwPHN0cmluZywgeyBpZGVudGl0eTogc3RyaW5nOyBpcDogc3RyaW5nIH0+KCk7XG4vLyBUaGUgcGFpcnMgdGhlIHNpZ25lZCB1bnJldm9rZXMgYWxsb3csIGFuZCB0aGUgbGVnYWN5IHJldm9jYXRpb24gaWRzIHRoZXkgbmFtZS4gUmVidWlsdCBvbiBldmVyeVxuLy8gcmVhZCwgc2luY2UgdW5yZXZva2VzIGFyZSBzaWduZWQgY29udGVudCBhbmQgcmVtb3Zpbmcgb25lIG11c3QgdGFrZSBlZmZlY3QuXG5sZXQgdW5yZXZva2VkUGFpcnMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbmxldCB1bnJldm9rZWRJZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuLyoqIFdoZXRoZXIgYW4gaWRlbnRpdHkgLSBhIGtleSBmaW5nZXJwcmludCBvciBhIG1hY2hpbmUgaWQgLSBoYXMgYSByZXZvY2F0aW9uIG5vdGhpbmcgaGFzIHVuZG9uZS5cbiAgICBUaGUgb25lIG1lYW5pbmcgb2YgXCJmcm96ZW5cIiwgdXNlZCBib3RoIHdoZW4gc3RyaXBwaW5nIHJlcG8gY29udGVudCBhbmQgd2hlbiBleHBsYWluaW5nIHdoeS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0lkZW50aXR5RnJvemVuKGlkZW50aXR5OiBzdHJpbmcpIHtcbiAgICBmb3IgKGxldCBbcmV2b2NhdGlvbklkLCByZXZvY2F0aW9uXSBvZiBhYnNvcmJlZFJldm9jYXRpb25zKSB7XG4gICAgICAgIGlmIChyZXZvY2F0aW9uLmlkZW50aXR5ICE9PSBpZGVudGl0eSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVucmV2b2tlZElkcy5oYXMocmV2b2NhdGlvbklkKSB8fCB1bnJldm9rZWRQYWlycy5oYXMoYCR7aWRlbnRpdHl9ICR7cmV2b2NhdGlvbi5pcH1gKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzUGFpclJldm9rZWQoaWRlbnRpdHk6IHN0cmluZywgaXA6IHN0cmluZykge1xuICAgIGZvciAobGV0IFtyZXZvY2F0aW9uSWQsIHJldm9jYXRpb25dIG9mIGFic29yYmVkUmV2b2NhdGlvbnMpIHtcbiAgICAgICAgaWYgKHJldm9jYXRpb24uaWRlbnRpdHkgPT09IGlkZW50aXR5ICYmIHJldm9jYXRpb24uaXAgPT09IGlwICYmICF1bnJldm9rZWRJZHMuaGFzKHJldm9jYXRpb25JZCkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGlzUGFpclVucmV2b2tlZChpZGVudGl0eTogc3RyaW5nLCBpcDogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHVucmV2b2tlZFBhaXJzLmhhcyhgJHtpZGVudGl0eX0gJHtpcH1gKTtcbn1cblxuLyoqIEZvciB3aG9ldmVyIGp1c3Qgd3JvdGUgYSByZXZvY2F0aW9uLCBzbyBpdCBob2xkcyBoZXJlIGltbWVkaWF0ZWx5IHJhdGhlciB0aGFuIG9uIHRoZSBuZXh0XG4gICAgYWJzb3JiLiBTdGlja3kgbGlrZSB0aGUgcmVzdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3RlUmV2b2NhdGlvbihyZXZvY2F0aW9uSWQ6IHN0cmluZywgaWRlbnRpdHk6IHN0cmluZywgaXA6IHN0cmluZykge1xuICAgIGFic29yYmVkUmV2b2NhdGlvbnMuc2V0KHJldm9jYXRpb25JZCwgeyBpZGVudGl0eSwgaXAgfSk7XG59XG5cbi8qKiBBIHJlcG8gdGhhdCBjYW5ub3QgYmUgdHJ1c3RlZCwgd2l0aCB0aGUgbWVzc2FnZSByZWFkeSBmb3Igd2hvZXZlciBhc2tlZC4gTm90IGV2ZXJ5IGNhbGxlclxuICAgIHRyZWF0cyB0aGVzZSB0aGUgc2FtZSAtIGEgc291cmNlIGtlZXBzIGl0cyBsYXN0IGtleXMsIGEgbWFjaGluZSBsaXN0IGlzIGp1c3QgcmVmdXNlZCAtIHNvIHRoZVxuICAgIGtpbmQgaXMgY2FycmllZCByYXRoZXIgdGhhbiBhY3RlZCBvbiBoZXJlLiAqL1xuZXhwb3J0IGNsYXNzIFNpZ25lZFJlcG9FcnJvciBleHRlbmRzIEVycm9yIHtcbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgcHJvYmxlbTogc3RyaW5nLCBwdWJsaWMgaGVhZGxpbmU6IHN0cmluZywgcHVibGljIGJvZHk6IHN0cmluZykge1xuICAgICAgICBzdXBlcihgJHtoZWFkbGluZX0uICR7Ym9keX1gKTtcbiAgICB9XG59XG5cbi8qKiBFdmVyeXRoaW5nIGEgc2lnbmVkIGNoZWNrb3V0IHZvdWNoZXMgZm9yLCBpbiBvbmUgY2FsbDogd2hvIHNpZ25lZCBpdCwgYW5kIHRoZSBjb250ZW50cyBvZiBldmVyeVxuICAgIGZpbGUgdGhlIHNpZ25hdHVyZSBhY3R1YWxseSBjb3ZlcnMuXG5cbiAgICBVTlNJR05FRCB3aXRoIG5vIGZpbGVzIHdoZW4gdGhlcmUgaXMgbm8gc2lnbmF0dXJlIGF0IGFsbC4gVGhyb3dzIGEgU2lnbmVkUmVwb0Vycm9yIHdoZW4gYVxuICAgIHNpZ25hdHVyZSBpcyBwcmVzZW50IGJ1dCBkb2VzIG5vdCBob2xkIHVwLCBvciB3aGVuIGEgZmlsZSBpdCBzaWduZWQgZm9yIHdhcyBjaGFuZ2VkIG9yIHJlbW92ZWRcbiAgICB3aXRob3V0IHJlLXNpZ25pbmcgLSBlaXRoZXIgd2F5IHRoZSBjYWxsZXIga2VlcHMgd2hhdGV2ZXIgaXQgbGFzdCBhY2NlcHRlZCByYXRoZXIgdGhhbiBiZWxpZXZpbmdcbiAgICBhIHJlcG8gdGhhdCBubyBsb25nZXIgbWF0Y2hlcyB3aGF0IHdhcyBzaWduZWQuIEEgZmlsZSBub3QgaW4gdGhlIG1hbmlmZXN0IGlzIGp1c3QgdW5zaWduZWQsIHNvXG4gICAgaXQgaXMgbGVmdCBvdXQgYW5kIHdhcm5lZCBhYm91dCByYXRoZXIgdGhhbiB0cmVhdGVkIGFzIHRhbXBlcmluZy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkU2lnbmVkUmVwbyhjb25maWc6IHsgcmVwb1BhdGg6IHN0cmluZzsgc291cmNlVVJMOiBzdHJpbmcgfSk6IFByb21pc2U8e1xuICAgIHNpZ25lcjogc3RyaW5nO1xuICAgIG1hbmlmZXN0SGFzaDogc3RyaW5nO1xuICAgIHNpZ25hdHVyZUhhc2g6IHN0cmluZztcbiAgICBmaWxlczogTWFwPHN0cmluZywgQnVmZmVyPjtcbn0+IHtcbiAgICBsZXQgeyByZXBvUGF0aCwgc291cmNlVVJMIH0gPSBjb25maWc7XG4gICAgbGV0IG1hbmlmZXN0Qnl0ZXMgPSBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4ocmVwb1BhdGgsIE1BTklGRVNUX05BTUUpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGxldCBzaWduYXR1cmVCeXRlcyA9IGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgU0lHTkFUVVJFX05BTUUpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGxldCBtYW5pZmVzdEhhc2ggPSBtYW5pZmVzdEJ5dGVzICYmIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShtYW5pZmVzdEJ5dGVzKS5kaWdlc3QoXCJoZXhcIikgfHwgXCJcIjtcbiAgICBsZXQgc2lnbmF0dXJlSGFzaCA9IHNpZ25hdHVyZUJ5dGVzICYmIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShzaWduYXR1cmVCeXRlcykuZGlnZXN0KFwiaGV4XCIpIHx8IFwiXCI7XG5cbiAgICBpZiAoIW1hbmlmZXN0Qnl0ZXMgJiYgIXNpZ25hdHVyZUJ5dGVzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke3JlcG9QYXRofSBpcyBub3Qgc2lnbmVkLCBpZ25vcmluZyBhbGwgb2YgaXRzIGZpbGVzYCk7XG4gICAgICAgIHJldHVybiB7IHNpZ25lcjogVU5TSUdORUQsIG1hbmlmZXN0SGFzaCwgc2lnbmF0dXJlSGFzaCwgZmlsZXM6IG5ldyBNYXAoKSB9O1xuICAgIH1cblxuICAgIGxldCBicm9rZW4gPSAoZGV0YWlsOiBzdHJpbmcpID0+IG5ldyBTaWduZWRSZXBvRXJyb3IoXG4gICAgICAgIFwiY29ycnVwdFwiLFxuICAgICAgICBgS0VZIFJFUE8gU0lHTkFUVVJFIElTIEJST0tFTmAsXG4gICAgICAgIGBUaGUgc2lnbmF0dXJlIG9uICR7cmVwb1BhdGh9IGRvZXMgbm90IGNoZWNrIG91dCwgc28gZXZlcnl0aGluZyBpbiBpdCBpcyBiZWluZyBpZ25vcmVkIGFuZGBcbiAgICAgICAgKyBgIHRoaXMgbWFjaGluZSBrZWVwcyB1c2luZyB3aGF0IGl0IGxhc3QgYWNjZXB0ZWQuXFxuXFxuJHtkZXRhaWx9YFxuICAgICAgICArIGBcXG5cXG5UbyByZXBsYWNlIHRoZSBzaWduYXR1cmUsIHJ1biBpbiB0aGF0IHJlcG86XFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYFxuICAgICk7XG4gICAgaWYgKCFtYW5pZmVzdEJ5dGVzIHx8ICFzaWduYXR1cmVCeXRlcykge1xuICAgICAgICB0aHJvdyBicm9rZW4oYE9ubHkgb25lIG9mICR7TUFOSUZFU1RfTkFNRX0gYW5kICR7U0lHTkFUVVJFX05BTUV9IGlzIHByZXNlbnQuYCk7XG4gICAgfVxuXG4gICAgbGV0IHNpZ25lcjogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICAgIC8vIFRoZSBzaWduYXR1cmUgY292ZXJzIHRoZSBub3JtYWxpc2VkIGJ5dGVzLCBzbyBhIGNoZWNrb3V0IHRoYXQgYXJyaXZlZCB3aXRoIENSTEYgc3RpbGxcbiAgICAgICAgLy8gdmVyaWZpZXMgcmF0aGVyIHRoYW4gbG9va2luZyBsaWtlIHRhbXBlcmluZy5cbiAgICAgICAgc2lnbmVyID0gdmVyaWZ5U1NIU0lHKHtcbiAgICAgICAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlQnl0ZXMudG9TdHJpbmcoXCJ1dGY4XCIpLFxuICAgICAgICAgICAgbWVzc2FnZTogbm9ybWFsaXplQ29udGVudChtYW5pZmVzdEJ5dGVzKSxcbiAgICAgICAgICAgIG5hbWVzcGFjZTogU0lHTl9OQU1FU1BBQ0UsXG4gICAgICAgIH0pLnB1YmxpY0tleTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IGJyb2tlbihgJHtlfWApO1xuICAgIH1cblxuICAgIGxldCBzdGFsZSA9IChkZXRhaWw6IHN0cmluZykgPT4gbmV3IFNpZ25lZFJlcG9FcnJvcihcbiAgICAgICAgXCJzdGFsZVwiLFxuICAgICAgICBgS0VZIFJFUE8gQ0hBTkdFRCBXSVRIT1VUIEJFSU5HIFNJR05FRGAsXG4gICAgICAgIGAke2RldGFpbH0sIHNvIHRoZSByZXBvIGlzIGJlaW5nIGlnbm9yZWQgYW5kIHRoaXMgbWFjaGluZSBrZWVwcyB1c2luZyB3aGF0IGl0IGxhc3QgYWNjZXB0ZWQuYFxuICAgICAgICArIGBcXG5cXG5UbyBtYWtlIHRoZSBjaGFuZ2UgdGFrZSBlZmZlY3QsIHJ1biBpbiB0aGF0IHJlcG86XFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYFxuICAgICk7XG5cbiAgICAvLyBFdmVyeSBmaWxlIG9uIGRpc2ssIG90aGVyIHRoYW4gZ2l0J3Mgb3duIGRpcmVjdG9yeSBhbmQgdGhlIHR3byBzaWduYXR1cmUgZmlsZXMsIHdoaWNoIGNhbm5vdFxuICAgIC8vIGRlc2NyaWJlIHRoZW1zZWx2ZXMuXG4gICAgbGV0IGxpc3RDaGVja291dEZpbGVzID0gYXN5bmMgKHByZWZpeD86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+ID0+IHtcbiAgICAgICAgbGV0IGZvdW5kOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBlbnRyeSBvZiBhd2FpdCBmcy5yZWFkZGlyKHBhdGguam9pbihyZXBvUGF0aCwgcHJlZml4IHx8IFwiXCIpLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHtcbiAgICAgICAgICAgIGxldCByZWxhdGl2ZVBhdGggPSBwcmVmaXggJiYgYCR7cHJlZml4fS8ke2VudHJ5Lm5hbWV9YCB8fCBlbnRyeS5uYW1lO1xuICAgICAgICAgICAgaWYgKGVudHJ5Lm5hbWUgPT09IFwiLmdpdFwiKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghcHJlZml4ICYmIChlbnRyeS5uYW1lID09PSBNQU5JRkVTVF9OQU1FIHx8IGVudHJ5Lm5hbWUgPT09IFNJR05BVFVSRV9OQU1FKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgICAgIGZvdW5kLnB1c2goLi4uYXdhaXQgbGlzdENoZWNrb3V0RmlsZXMocmVsYXRpdmVQYXRoKSk7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3VuZC5wdXNoKHJlbGF0aXZlUGF0aCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZvdW5kLnNvcnQoKTtcbiAgICB9O1xuXG4gICAgbGV0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShtYW5pZmVzdEJ5dGVzLnRvU3RyaW5nKFwidXRmOFwiKSk7XG4gICAgbGV0IGxpc3RlZCA9IG5ldyBNYXA8c3RyaW5nLCB7IHNpemU6IG51bWJlcjsgc2hhMjU2OiBzdHJpbmcgfT4oXG4gICAgICAgIChtYW5pZmVzdC5maWxlcyB8fCBbXSkubWFwKChmaWxlOiB7IHBhdGg6IHN0cmluZzsgc2l6ZTogbnVtYmVyOyBzaGEyNTY6IHN0cmluZyB9KSA9PiBbZmlsZS5wYXRoLCBmaWxlXSlcbiAgICApO1xuXG4gICAgbGV0IGZpbGVzID0gbmV3IE1hcDxzdHJpbmcsIEJ1ZmZlcj4oKTtcbiAgICBmb3IgKGxldCBmaWxlUGF0aCBvZiBhd2FpdCBsaXN0Q2hlY2tvdXRGaWxlcygpKSB7XG4gICAgICAgIGxldCBleHBlY3RlZCA9IGxpc3RlZC5nZXQoZmlsZVBhdGgpO1xuICAgICAgICAvLyBBIGZpbGUgdGhlIHNpZ25hdHVyZSBuZXZlciBtZW50aW9uZWQgaXMgbm90IHRhbXBlcmluZywgaXQgaXMganVzdCB1bnNpZ25lZCAtIGxlZnQgb3V0XG4gICAgICAgIC8vIHJhdGhlciB0aGFuIHRydXN0ZWQuIEFuIGV4dHJhIGZpbGUgaW4gYSB3b3JraW5nIHRyZWUgaXMgb3JkaW5hcnksIHNvIGl0IGlzIG9ubHkgYSBub3RlLlxuICAgICAgICBpZiAoIWV4cGVjdGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgSWdub3JpbmcgJHtwYXRoLmpvaW4ocmVwb1BhdGgsIGZpbGVQYXRoKX0sIGl0IGlzIG5vdCBpbiB0aGUgc2lnbmVkIG1hbmlmZXN0YCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgY29udGVudHMgPSBub3JtYWxpemVDb250ZW50KGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpKSk7XG4gICAgICAgIGxldCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGNvbnRlbnRzKS5kaWdlc3QoXCJoZXhcIik7XG4gICAgICAgIC8vIEEgZmlsZSB0aGUgbWFuaWZlc3QgRE9FUyBuYW1lLCBidXQgd2hvc2UgY29udGVudCBubyBsb25nZXIgbWF0Y2hlcywgaXMgYSBzaWduZWQgZmlsZVxuICAgICAgICAvLyBjaGFuZ2VkIHdpdGhvdXQgcmUtc2lnbmluZyAtIHRoZSByZXBvIGJlaW5nIGVkaXRlZCBvdXQgZnJvbSB1bmRlciBpdHMgc2lnbmF0dXJlLlxuICAgICAgICBpZiAoY29udGVudHMubGVuZ3RoICE9PSBleHBlY3RlZC5zaXplIHx8IGhhc2ggIT09IGV4cGVjdGVkLnNoYTI1Nikge1xuICAgICAgICAgICAgdGhyb3cgc3RhbGUoYCR7cGF0aC5qb2luKHJlcG9QYXRoLCBmaWxlUGF0aCl9IHdhcyBjaGFuZ2VkIGFmdGVyIGl0IHdhcyBzaWduZWRgKTtcbiAgICAgICAgfVxuICAgICAgICBmaWxlcy5zZXQoZmlsZVBhdGgsIGNvbnRlbnRzKTtcbiAgICB9XG4gICAgZm9yIChsZXQgZmlsZVBhdGggb2YgbGlzdGVkLmtleXMoKSkge1xuICAgICAgICBpZiAoIWZpbGVzLmhhcyhmaWxlUGF0aCkpIHtcbiAgICAgICAgICAgIHRocm93IHN0YWxlKGAke3BhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpfSBpcyBzaWduZWQgZm9yIGJ1dCBtaXNzaW5nYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBBYnNvcmIgdGhlIHJldm9rZSByZXBvJ3MgZmlsZXMgaW50byB0aGUgc3RpY2t5IG1hcC4gT25jZSBzZWVuIGEgcmV2b2NhdGlvbiBuZXZlciBsZWF2ZXMgaXQsXG4gICAgLy8gZXZlbiBpZiBpdHMgZmlsZSBkaXNhcHBlYXJzIC0gdGhlIGtleSB0aGF0IHdyaXRlcyByZXZvY2F0aW9ucyBpcyBvbiBldmVyeSBzZXJ2ZXIsIHNvIHdob2V2ZXJcbiAgICAvLyBzdG9sZSBvbmUgY291bGQgb3RoZXJ3aXNlIGVyYXNlIHRoZSByZWNvcmQgdGhhdCBzaHV0IHRoZW0gb3V0LlxuICAgIGxldCByZXZvY2F0aW9uc0RpcmVjdG9yeSA9IHBhdGguam9pbihyZXZva2VSZXBvUGF0aChzb3VyY2VVUkwpLCBSRVZPQ0FUSU9OU19ESVIpO1xuICAgIGZvciAobGV0IG5hbWUgb2YgKGF3YWl0IGZzLnJlYWRkaXIocmV2b2NhdGlvbnNEaXJlY3RvcnkpLmNhdGNoKCgpID0+IFtdIGFzIHN0cmluZ1tdKSkuc29ydCgpKSB7XG4gICAgICAgIGlmICghbmFtZS5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbGV0IHBhcnNlZCA9IEpTT04ucGFyc2UoYXdhaXQgZnMucmVhZEZpbGUocGF0aC5qb2luKHJldm9jYXRpb25zRGlyZWN0b3J5LCBuYW1lKSwgXCJ1dGY4XCIpKTtcbiAgICAgICAgICAgIGxldCBpZGVudGl0eSA9IHBhcnNlZC5maW5nZXJwcmludCB8fCBwYXJzZWQubWFjaGluZUlkO1xuICAgICAgICAgICAgaWYgKCFpZGVudGl0eSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHJldm9jYXRpb25JZCA9IHBhcnNlZC5yZXZvY2F0aW9uSWQgfHwgbmFtZS5yZXBsYWNlKC9cXC5qc29uJC8sIFwiXCIpO1xuICAgICAgICAgICAgaWYgKCFhYnNvcmJlZFJldm9jYXRpb25zLmhhcyhyZXZvY2F0aW9uSWQpKSB7XG4gICAgICAgICAgICAgICAgYWJzb3JiZWRSZXZvY2F0aW9ucy5zZXQocmV2b2NhdGlvbklkLCB7IGlkZW50aXR5LCBpcDogcGFyc2VkLmlwIHx8IHBhcnNlZC5hdHRlbXB0Py5pcCB8fCBcIlwiIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgSWdub3JpbmcgdW5yZWFkYWJsZSByZXZvY2F0aW9uICR7cGF0aC5qb2luKHJldm9jYXRpb25zRGlyZWN0b3J5LCBuYW1lKX0uICR7ZX1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlYnVpbGQgdGhlIHVucmV2b2tlcyBmcm9tIHRoZSBzaWduZWQgZmlsZXMganVzdCByZWFkLiBVbnJldm9rZXMgYXJlIHNpZ25lZCBjb250ZW50LCBzb1xuICAgIC8vIHJlbW92aW5nIG9uZSBtdXN0IHRha2UgZWZmZWN0LCB1bmxpa2UgdGhlIHN0aWNreSByZXZvY2F0aW9ucy5cbiAgICB1bnJldm9rZWRQYWlycyA9IG5ldyBTZXQoKTtcbiAgICB1bnJldm9rZWRJZHMgPSBuZXcgU2V0KCk7XG4gICAgZm9yIChsZXQgW2ZpbGVQYXRoLCBjb250ZW50c10gb2YgZmlsZXMpIHtcbiAgICAgICAgaWYgKCFmaWxlUGF0aC5zdGFydHNXaXRoKGAke1VOUkVWT0tFU19ESVJ9L2ApIHx8ICFmaWxlUGF0aC5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgbGV0IHBhcnNlZCA9IEpTT04ucGFyc2UoY29udGVudHMudG9TdHJpbmcoXCJ1dGY4XCIpKTtcbiAgICAgICAgICAgIGZvciAobGV0IGFsbG93ZWQgb2YgcGFyc2VkLmFsbG93ZWQgfHwgW10pIHtcbiAgICAgICAgICAgICAgICBsZXQgaWRlbnRpdHkgPSBhbGxvd2VkLmZpbmdlcnByaW50IHx8IGFsbG93ZWQubWFjaGluZUlkO1xuICAgICAgICAgICAgICAgIGlmIChpZGVudGl0eSAmJiBhbGxvd2VkLmlwKSB7XG4gICAgICAgICAgICAgICAgICAgIHVucmV2b2tlZFBhaXJzLmFkZChgJHtpZGVudGl0eX0gJHthbGxvd2VkLmlwfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGZvciAobGV0IHJldm9jYXRpb25JZCBvZiBwYXJzZWQucmV2b2NhdGlvbklkcyB8fCBbXSkge1xuICAgICAgICAgICAgICAgIHVucmV2b2tlZElkcy5hZGQocmV2b2NhdGlvbklkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYElnbm9yaW5nIHVucmVhZGFibGUgdW5yZXZva2UgJHtmaWxlUGF0aH0uICR7ZX1gKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8vIERyb3AgZXZlcnl0aGluZyBmcm96ZW46IHJldm9rZWQga2V5cyBvdXQgb2YgYXV0aG9yaXplZF9rZXlzIGFuZCB0b3AgbGV2ZWwgLnB1YiBmaWxlcywgYW5kXG4gICAgLy8gZnJvemVuIG1hY2hpbmVzJyBmaWxlcyBvdXQgb2YgbWFjaGluZXMvLiBXaGF0IGNvbWVzIGJhY2sgaXMgd2hhdCB0aGlzIG1hY2hpbmUgYWN0dWFsbHlcbiAgICAvLyB0cnVzdHMsIHNvIG5vIGNhbGxlciBjYW4gcmVhZCB0aGUgbGlzdCBhbmQgZm9yZ2V0IHRoZSByZXZvY2F0aW9ucy5cbiAgICBmb3IgKGxldCBbZmlsZVBhdGgsIGNvbnRlbnRzXSBvZiBbLi4uZmlsZXNdKSB7XG4gICAgICAgIGlmIChmaWxlUGF0aCA9PT0gXCJhdXRob3JpemVkX2tleXNcIiB8fCAoZmlsZVBhdGguZW5kc1dpdGgoXCIucHViXCIpICYmICFmaWxlUGF0aC5pbmNsdWRlcyhcIi9cIikpKSB7XG4gICAgICAgICAgICBsZXQgbGluZXMgPSBjb250ZW50cy50b1N0cmluZyhcInV0ZjhcIikuc3BsaXQoXCJcXG5cIik7XG4gICAgICAgICAgICBsZXQga2VwdCA9IGxpbmVzLmZpbHRlcihsaW5lID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgZmluZ2VycHJpbnQgPSBrZXlGaW5nZXJwcmludChsaW5lKTtcbiAgICAgICAgICAgICAgICBpZiAoZmluZ2VycHJpbnQgJiYgaXNJZGVudGl0eUZyb3plbihmaW5nZXJwcmludCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coYERyb3BwaW5nIHJldm9rZWQga2V5ICR7ZmluZ2VycHJpbnR9IGZyb20gJHtwYXRoLmpvaW4ocmVwb1BhdGgsIGZpbGVQYXRoKX1gKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYgKGtlcHQubGVuZ3RoICE9PSBsaW5lcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBmaWxlcy5zZXQoZmlsZVBhdGgsIEJ1ZmZlci5mcm9tKGtlcHQuam9pbihcIlxcblwiKSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChmaWxlUGF0aC5zdGFydHNXaXRoKFwibWFjaGluZXMvXCIpICYmIGZpbGVQYXRoLmVuZHNXaXRoKFwiLmpzb25cIikpIHtcbiAgICAgICAgICAgIGxldCBtYWNoaW5lSWQgPSBmaWxlUGF0aC5zbGljZShcIm1hY2hpbmVzL1wiLmxlbmd0aCwgLVwiLmpzb25cIi5sZW5ndGgpO1xuICAgICAgICAgICAgaWYgKGlzSWRlbnRpdHlGcm96ZW4obWFjaGluZUlkKSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGBEcm9wcGluZyBmcm96ZW4gbWFjaGluZSAke21hY2hpbmVJZH0gZnJvbSAke3BhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpfWApO1xuICAgICAgICAgICAgICAgIGZpbGVzLmRlbGV0ZShmaWxlUGF0aCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4geyBzaWduZXIsIG1hbmlmZXN0SGFzaCwgc2lnbmF0dXJlSGFzaCwgZmlsZXMgfTtcbn1cbiJdfQ==
237
+ /* _JS_SOURCE_HASH = "dca3e0a9ba6326240f357f9f44b892b1cf1bf3622269921530457ceab4e3266a"; */
@@ -65,10 +65,7 @@ export declare function absorbRevocations(sourceURLs: string[]): Promise<void>;
65
65
 
66
66
  What still protects a stolen signing key is the 24 hours before a NEW signer is accepted. */
67
67
  export declare function applyUnrevokes(sourceURLs: string[]): Promise<void>;
68
- /** Every key held out of authorized_keys: one that has at least one revocation nothing has
69
- forgiven. A key forgiven for one address is an ordinary key again, and revoking it from another
70
- address puts it back in here. */
71
- export declare function revokedFingerprints(): Set<string>;
72
- /** Drops revoked keys from the merged set, and says so the first time a key actually disappears -
73
- which is the thing worth knowing, rather than the mere existence of a revocation. */
74
- export declare function removeRevokedKeys(keys: string[]): Promise<string[]>;
68
+ /** Reports each revocation the first time it actually takes a key out of this machine's file. The
69
+ dropping itself happens in readSignedRepo, which strips revoked keys before anything reads them
70
+ - this only says so, and kills whatever sessions the key was holding open. */
71
+ export declare function reportRevokedKeys(): Promise<void>;
@@ -1,6 +1,14 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
3
  export declare const UNSIGNED = "";
4
+ /** Whether an identity - a key fingerprint or a machine id - has a revocation nothing has undone.
5
+ The one meaning of "frozen", used both when stripping repo content and when explaining why. */
6
+ export declare function isIdentityFrozen(identity: string): boolean;
7
+ export declare function isPairRevoked(identity: string, ip: string): boolean;
8
+ export declare function isPairUnrevoked(identity: string, ip: string): boolean;
9
+ /** For whoever just wrote a revocation, so it holds here immediately rather than on the next
10
+ absorb. Sticky like the rest. */
11
+ export declare function noteRevocation(revocationId: string, identity: string, ip: string): void;
4
12
  /** A repo that cannot be trusted, with the message ready for whoever asked. Not every caller
5
13
  treats these the same - a source keeps its last keys, a machine list is just refused - so the
6
14
  kind is carried rather than acted on here. */
@@ -18,7 +26,10 @@ export declare class SignedRepoError extends Error {
18
26
  without re-signing - either way the caller keeps whatever it last accepted rather than believing
19
27
  a repo that no longer matches what was signed. A file not in the manifest is just unsigned, so
20
28
  it is left out and warned about rather than treated as tampering. */
21
- export declare function readSignedRepo(repoPath: string): Promise<{
29
+ export declare function readSignedRepo(config: {
30
+ repoPath: string;
31
+ sourceURL: string;
32
+ }): Promise<{
22
33
  signer: string;
23
34
  manifestHash: string;
24
35
  signatureHash: string;
@@ -3,6 +3,8 @@ import fs from "fs/promises";
3
3
  import path from "path";
4
4
  import { MANIFEST_NAME, normalizeContent, SIGN_NAMESPACE, SIGNATURE_NAME } from "../../signedFiles/manifest";
5
5
  import { verifySSHSIG } from "../../signedFiles/sshsig";
6
+ import { keyFingerprint } from "../authorizedKeys";
7
+ import { revokeRepoPath } from "../revokeSource";
6
8
 
7
9
  // A source that has never been signed reads as this, so losing a signature counts as a change of
8
10
  // signer rather than as something to wave through.
@@ -10,6 +12,52 @@ export const UNSIGNED = "";
10
12
  // What fixes both of the signature problems we report, so the message can say so rather than
11
13
  // leaving someone to work it out.
12
14
  const SIGN_COMMAND = "yarn signfiles git";
15
+ const REVOCATIONS_DIR = "revocations";
16
+ const UNREVOKES_DIR = "unrevoked";
17
+
18
+ // Every revocation this process has ever seen, keyed by revocation id. Once absorbed a revocation
19
+ // never leaves, even if its file disappears from the revoke repo - the key that writes revocations
20
+ // is on every server, so whoever stole one could otherwise erase the record that shut them out.
21
+ // Restarting the process is the way back from a revocation that should not have happened.
22
+ let absorbedRevocations = new Map<string, { identity: string; ip: string }>();
23
+ // The pairs the signed unrevokes allow, and the legacy revocation ids they name. Rebuilt on every
24
+ // read, since unrevokes are signed content and removing one must take effect.
25
+ let unrevokedPairs = new Set<string>();
26
+ let unrevokedIds = new Set<string>();
27
+
28
+ /** Whether an identity - a key fingerprint or a machine id - has a revocation nothing has undone.
29
+ The one meaning of "frozen", used both when stripping repo content and when explaining why. */
30
+ export function isIdentityFrozen(identity: string) {
31
+ for (let [revocationId, revocation] of absorbedRevocations) {
32
+ if (revocation.identity !== identity) {
33
+ continue;
34
+ }
35
+ if (unrevokedIds.has(revocationId) || unrevokedPairs.has(`${identity} ${revocation.ip}`)) {
36
+ continue;
37
+ }
38
+ return true;
39
+ }
40
+ return false;
41
+ }
42
+
43
+ export function isPairRevoked(identity: string, ip: string) {
44
+ for (let [revocationId, revocation] of absorbedRevocations) {
45
+ if (revocation.identity === identity && revocation.ip === ip && !unrevokedIds.has(revocationId)) {
46
+ return true;
47
+ }
48
+ }
49
+ return false;
50
+ }
51
+
52
+ export function isPairUnrevoked(identity: string, ip: string) {
53
+ return unrevokedPairs.has(`${identity} ${ip}`);
54
+ }
55
+
56
+ /** For whoever just wrote a revocation, so it holds here immediately rather than on the next
57
+ absorb. Sticky like the rest. */
58
+ export function noteRevocation(revocationId: string, identity: string, ip: string) {
59
+ absorbedRevocations.set(revocationId, { identity, ip });
60
+ }
13
61
 
14
62
  /** A repo that cannot be trusted, with the message ready for whoever asked. Not every caller
15
63
  treats these the same - a source keeps its last keys, a machine list is just refused - so the
@@ -28,12 +76,13 @@ export class SignedRepoError extends Error {
28
76
  without re-signing - either way the caller keeps whatever it last accepted rather than believing
29
77
  a repo that no longer matches what was signed. A file not in the manifest is just unsigned, so
30
78
  it is left out and warned about rather than treated as tampering. */
31
- export async function readSignedRepo(repoPath: string): Promise<{
79
+ export async function readSignedRepo(config: { repoPath: string; sourceURL: string }): Promise<{
32
80
  signer: string;
33
81
  manifestHash: string;
34
82
  signatureHash: string;
35
83
  files: Map<string, Buffer>;
36
84
  }> {
85
+ let { repoPath, sourceURL } = config;
37
86
  let manifestBytes = await fs.readFile(path.join(repoPath, MANIFEST_NAME)).catch(() => undefined);
38
87
  let signatureBytes = await fs.readFile(path.join(repoPath, SIGNATURE_NAME)).catch(() => undefined);
39
88
  let manifestHash = manifestBytes && crypto.createHash("sha256").update(manifestBytes).digest("hex") || "";
@@ -121,5 +170,79 @@ export async function readSignedRepo(repoPath: string): Promise<{
121
170
  }
122
171
  }
123
172
 
173
+ // Absorb the revoke repo's files into the sticky map. Once seen a revocation never leaves it,
174
+ // even if its file disappears - the key that writes revocations is on every server, so whoever
175
+ // stole one could otherwise erase the record that shut them out.
176
+ let revocationsDirectory = path.join(revokeRepoPath(sourceURL), REVOCATIONS_DIR);
177
+ for (let name of (await fs.readdir(revocationsDirectory).catch(() => [] as string[])).sort()) {
178
+ if (!name.endsWith(".json")) {
179
+ continue;
180
+ }
181
+ try {
182
+ let parsed = JSON.parse(await fs.readFile(path.join(revocationsDirectory, name), "utf8"));
183
+ let identity = parsed.fingerprint || parsed.machineId;
184
+ if (!identity) {
185
+ continue;
186
+ }
187
+ let revocationId = parsed.revocationId || name.replace(/\.json$/, "");
188
+ if (!absorbedRevocations.has(revocationId)) {
189
+ absorbedRevocations.set(revocationId, { identity, ip: parsed.ip || parsed.attempt?.ip || "" });
190
+ }
191
+ } catch (e) {
192
+ console.log(`Ignoring unreadable revocation ${path.join(revocationsDirectory, name)}. ${e}`);
193
+ }
194
+ }
195
+
196
+ // Rebuild the unrevokes from the signed files just read. Unrevokes are signed content, so
197
+ // removing one must take effect, unlike the sticky revocations.
198
+ unrevokedPairs = new Set();
199
+ unrevokedIds = new Set();
200
+ for (let [filePath, contents] of files) {
201
+ if (!filePath.startsWith(`${UNREVOKES_DIR}/`) || !filePath.endsWith(".json")) {
202
+ continue;
203
+ }
204
+ try {
205
+ let parsed = JSON.parse(contents.toString("utf8"));
206
+ for (let allowed of parsed.allowed || []) {
207
+ let identity = allowed.fingerprint || allowed.machineId;
208
+ if (identity && allowed.ip) {
209
+ unrevokedPairs.add(`${identity} ${allowed.ip}`);
210
+ }
211
+ }
212
+ for (let revocationId of parsed.revocationIds || []) {
213
+ unrevokedIds.add(revocationId);
214
+ }
215
+ } catch (e) {
216
+ console.log(`Ignoring unreadable unrevoke ${filePath}. ${e}`);
217
+ }
218
+ }
219
+
220
+ // Drop everything frozen: revoked keys out of authorized_keys and top level .pub files, and
221
+ // frozen machines' files out of machines/. What comes back is what this machine actually
222
+ // trusts, so no caller can read the list and forget the revocations.
223
+ for (let [filePath, contents] of [...files]) {
224
+ if (filePath === "authorized_keys" || (filePath.endsWith(".pub") && !filePath.includes("/"))) {
225
+ let lines = contents.toString("utf8").split("\n");
226
+ let kept = lines.filter(line => {
227
+ let fingerprint = keyFingerprint(line);
228
+ if (fingerprint && isIdentityFrozen(fingerprint)) {
229
+ console.log(`Dropping revoked key ${fingerprint} from ${path.join(repoPath, filePath)}`);
230
+ return false;
231
+ }
232
+ return true;
233
+ });
234
+ if (kept.length !== lines.length) {
235
+ files.set(filePath, Buffer.from(kept.join("\n")));
236
+ }
237
+ }
238
+ if (filePath.startsWith("machines/") && filePath.endsWith(".json")) {
239
+ let machineId = filePath.slice("machines/".length, -".json".length);
240
+ if (isIdentityFrozen(machineId)) {
241
+ console.log(`Dropping frozen machine ${machineId} from ${path.join(repoPath, filePath)}`);
242
+ files.delete(filePath);
243
+ }
244
+ }
245
+ }
246
+
124
247
  return { signer, manifestHash, signatureHash, files };
125
248
  }