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.
- package/bin/printmachineid.js +5 -0
- package/examplestorage/browser.tsx +2 -2
- package/index.d.ts +10 -4
- package/misc/dist/strings.ts.cache +2 -2
- package/misc/https/certs.d.ts +6 -1
- package/misc/https/certs.ts +11 -2
- package/misc/https/dist/certs.ts.cache +14 -5
- package/misc/https/dist/persistentLocalStorage.ts.cache +14 -4
- package/misc/https/persistentLocalStorage.d.ts +1 -0
- package/misc/https/persistentLocalStorage.ts +10 -0
- package/package.json +5 -3
- package/security/authorizedKeys/daemon/daemon.ts +4 -3
- package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
- package/security/authorizedKeys/daemon/dist/trust.ts.cache +126 -4
- package/security/authorizedKeys/daemon/revocation.d.ts +4 -7
- package/security/authorizedKeys/daemon/revocation.ts +0 -0
- package/security/authorizedKeys/daemon/trust.d.ts +12 -1
- package/security/authorizedKeys/daemon/trust.ts +124 -1
- package/security/authorizedKeys/dist/unrevoke.ts.cache +5 -186
- package/security/authorizedKeys/dist/unrevokeCli.ts.cache +195 -0
- package/security/machines/dist/machines.ts.cache +20 -68
- package/security/machines/dist/printMachineId.ts.cache +21 -0
- package/security/machines/identity2.ts +94 -6
- package/security/machines/machines.ts +27 -76
- package/security/machines/printMachineId.ts +19 -0
- package/security/signedFiles/dist/signFiles.ts.cache +16 -52
- package/storage/remoteStorage/ArchivesRemote.d.ts +1 -1
- package/storage/remoteStorage/ArchivesRemote.ts +14 -8
- package/storage/remoteStorage/accessPage.tsx +7 -123
- package/storage/remoteStorage/createArchives.d.ts +1 -1
- package/storage/remoteStorage/createArchives.ts +1 -1
- package/storage/remoteStorage/dist/ArchivesRemote.ts.cache +14 -7
- package/storage/remoteStorage/dist/createArchives.ts.cache +2 -2
- package/storage/remoteStorage/dist/sourceWrapper.ts.cache +3 -3
- package/storage/remoteStorage/dist/storageController.ts.cache +8 -7
- package/storage/remoteStorage/sourceWrapper.ts +1 -1
- package/storage/remoteStorage/storageController.d.ts +1 -1
- 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(
|
|
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 = "
|
|
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
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
export declare function
|
|
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>;
|
|
Binary file
|
|
@@ -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(
|
|
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
|
}
|