sliftutils 1.7.133 → 1.7.134
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/addmachine.js +1 -5
- package/bin/derivekey.js +2 -7
- package/bin/portsecuredaemon.js +1 -8
- package/bin/securessh.js +2 -7
- package/bin/setupnotify.js +2 -6
- package/bin/signfiles.js +2 -7
- package/bin/testnotify.js +2 -6
- package/bin/unrevoke.js +1 -5
- package/misc/dist/ownIPs.ts.cache +2 -2
- package/misc/https/dist/certs.ts.cache +12 -9
- package/misc/https/dist/persistentLocalStorage.ts.cache +10 -4
- package/package.json +1 -1
- package/security/authorizedKeys/daemon/daemon.ts +142 -7
- package/security/authorizedKeys/daemon/dist/changes.ts.cache +2 -2
- package/security/authorizedKeys/daemon/dist/git.ts.cache +26 -8
- package/security/authorizedKeys/daemon/dist/notify.ts.cache +2 -2
- package/security/authorizedKeys/daemon/dist/paths.ts.cache +2 -2
- package/security/authorizedKeys/daemon/dist/repoFiles.ts.cache +4 -6
- package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
- package/security/authorizedKeys/daemon/dist/sessions.ts.cache +2 -2
- package/security/authorizedKeys/daemon/dist/state.ts.cache +2 -2
- package/security/authorizedKeys/daemon/dist/trust.ts.cache +85 -265
- package/security/authorizedKeys/daemon/git.d.ts +8 -0
- package/security/authorizedKeys/daemon/git.ts +22 -4
- package/security/authorizedKeys/daemon/repoFiles.ts +2 -4
- package/security/authorizedKeys/daemon/trust.d.ts +25 -19
- package/security/authorizedKeys/daemon/trust.ts +91 -278
- package/security/authorizedKeys/dist/authorizedKeys.ts.cache +2 -2
- package/security/authorizedKeys/dist/keysRepo.ts.cache +2 -2
- package/security/authorizedKeys/dist/revokeSource.ts.cache +2 -2
- package/security/authorizedKeys/dist/sources.ts.cache +2 -2
- package/security/authorizedKeys/secureSSH.ts +6 -1
- package/security/authorizedKeys/unrevoke.ts +2 -198
- package/security/authorizedKeys/unrevokeCli.ts +204 -0
- package/security/helpers/dist/paths.ts.cache +2 -2
- package/security/helpers/dist/remoteSSH.ts.cache +2 -2
- package/security/helpers/dist/spawn.ts.cache +2 -2
- package/security/helpers/remoteSSH.d.ts +35 -0
- package/security/keys/deriveKey.d.ts +0 -1
- package/security/keys/deriveKey.ts +1 -56
- package/security/keys/deriveKeyCli.ts +62 -0
- package/security/keys/dist/deriveKey.ts.cache +4 -51
- package/security/keys/dist/sshKeyFile.ts.cache +5 -3
- package/security/machines/addMachine.ts +31 -61
- package/security/machines/dist/addMachine.ts.cache +72 -57
- package/security/machines/dist/machines.ts.cache +134 -55
- package/security/machines/machines.d.ts +11 -0
- package/security/machines/machines.ts +134 -57
- package/security/notifications/dist/discord.ts.cache +2 -2
- package/security/notifications/setupNotify.ts +6 -1
- package/security/notifications/testNotify.ts +6 -1
- package/security/signedFiles/dist/manifest.ts.cache +2 -2
- package/security/signedFiles/dist/sshsig.ts.cache +138 -0
- package/security/signedFiles/signFiles.ts +11 -52
- package/security/signedFiles/signFilesCli.ts +54 -0
- package/security/signedFiles/sshsig.d.ts +13 -0
- package/security/signedFiles/sshsig.ts +141 -0
- package/storage/dist/backblaze.ts.cache +10 -2
|
@@ -7,11 +7,12 @@ import { listRepoDir, readRepoFile } from "../authorizedKeys/daemon/repoFiles";
|
|
|
7
7
|
import { newRevocationId, pairKey, readRevocationFiles, readUnrevokes } from "../authorizedKeys/daemon/revocation";
|
|
8
8
|
import { runGit } from "../authorizedKeys/daemon/git";
|
|
9
9
|
import { ensureRevokeKey } from "../authorizedKeys/daemon/repoFiles";
|
|
10
|
-
import {
|
|
10
|
+
import { readSignedRepo } from "../authorizedKeys/daemon/trust";
|
|
11
11
|
import { revokeRepoPath, revokeRepoURL } from "../authorizedKeys/revokeSource";
|
|
12
12
|
import { notify } from "../authorizedKeys/daemon/notify";
|
|
13
13
|
import { areDiscordNotificationsConfigured, configureDiscordNotifications, DEFAULT_WEBHOOK_FILE_PATH } from "../notifications/discord";
|
|
14
|
-
import { getOwnMachineId } from "../../misc/https/certs";
|
|
14
|
+
import { DEV_getIdentityFilePath, generateCA, getMachineId, getOwnMachineId, IdentityStorageType } from "../../misc/https/certs";
|
|
15
|
+
import { describeHost, runOverSSH, writeRemoteFile } from "../helpers/remoteSSH";
|
|
15
16
|
import { lazy } from "socket-function/src/caching";
|
|
16
17
|
import { runInfinitePoll } from "socket-function/src/batching";
|
|
17
18
|
import { spawnPromise } from "../helpers/spawn";
|
|
@@ -34,6 +35,10 @@ const MACHINES_REFRESH_INTERVAL = 60 * 1000;
|
|
|
34
35
|
// not pay for resolving the repo on every request either.
|
|
35
36
|
const REPO_RETRY_DELAY = 15 * 1000;
|
|
36
37
|
const LOOPBACK = ["127.0.0.1", "::1", "::ffff:127.0.0.1"];
|
|
38
|
+
// The trusted machine list is re-read at most this often when a check rejects, so a caller that
|
|
39
|
+
// was just added is picked up quickly without letting a flood of rejections re-read every time.
|
|
40
|
+
const MACHINES_INVALIDATION_INTERVAL = 60 * 1000;
|
|
41
|
+
let lastMachinesInvalidation = 0;
|
|
37
42
|
|
|
38
43
|
/** One machine we are willing to talk to, and the addresses it may talk to us from. */
|
|
39
44
|
export type MachineState = {
|
|
@@ -72,13 +77,24 @@ export async function getMachines(repoPath?: string): Promise<MachineState[]> {
|
|
|
72
77
|
return [...(await readMachines(repoPath || (await keysRepo()).repoPath)).values()];
|
|
73
78
|
}
|
|
74
79
|
|
|
75
|
-
/**
|
|
76
|
-
|
|
77
|
-
|
|
80
|
+
/** The machines the signed files vouch for. Only the machine files covered by the signature are
|
|
81
|
+
read - an unsigned machines/*.json is not evidence of anything, so readSignedRepo has already
|
|
82
|
+
left it out. */
|
|
78
83
|
async function readTrustedMachines() {
|
|
79
84
|
let { repoPath } = await keysRepo();
|
|
80
|
-
await
|
|
81
|
-
|
|
85
|
+
let { files } = await readSignedRepo(repoPath);
|
|
86
|
+
let machines: MachineState[] = [];
|
|
87
|
+
for (let [filePath, contents] of files) {
|
|
88
|
+
let name = filePath.startsWith(`${MACHINES_DIR}/`) && filePath.slice(MACHINES_DIR.length + 1) || "";
|
|
89
|
+
if (!name.endsWith(".json") || name.includes("/")) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
let machine = parseMachineFile(name, contents.toString("utf8"));
|
|
93
|
+
if (machine) {
|
|
94
|
+
machines.push(machine);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return machines;
|
|
82
98
|
}
|
|
83
99
|
|
|
84
100
|
const trustedMachines = lazy(async () => {
|
|
@@ -108,6 +124,36 @@ export async function getTrustedMachines(): Promise<MachineState[]> {
|
|
|
108
124
|
return await trustedMachines();
|
|
109
125
|
}
|
|
110
126
|
|
|
127
|
+
/** The machine id of a machine reached over ssh, generating and installing an identity for it if
|
|
128
|
+
it has none under this domain. The private key ends up on that machine and nowhere else. */
|
|
129
|
+
export async function getOrCreateRemoteMachineId(host: string, domain: string): Promise<string> {
|
|
130
|
+
let fileName = path.basename(DEV_getIdentityFilePath(domain));
|
|
131
|
+
let home = (await runOverSSH({ host, script: `echo $HOME` })).stdout.trim();
|
|
132
|
+
if (!home) {
|
|
133
|
+
throw new Error(`Expected ${host} to report a home directory, it reported nothing`);
|
|
134
|
+
}
|
|
135
|
+
let contents = await runOverSSH({ host, script: `cat ${home}/${fileName} 2>/dev/null || true` });
|
|
136
|
+
if (contents.stdout.trim()) {
|
|
137
|
+
let stored = JSON.parse(contents.stdout) as IdentityStorageType;
|
|
138
|
+
return getMachineId(stored.domain, domain);
|
|
139
|
+
}
|
|
140
|
+
console.log(`${describeHost(host)} has no identity for ${domain}, generating one`);
|
|
141
|
+
let generated = generateCA(domain);
|
|
142
|
+
let stored: IdentityStorageType = {
|
|
143
|
+
domain: generated.domain,
|
|
144
|
+
certB64: generated.cert.toString("base64"),
|
|
145
|
+
keyB64: generated.key.toString("base64"),
|
|
146
|
+
};
|
|
147
|
+
await writeRemoteFile({
|
|
148
|
+
host,
|
|
149
|
+
filePath: `${home}/${fileName}`,
|
|
150
|
+
contents: JSON.stringify(stored),
|
|
151
|
+
fileMode: "600",
|
|
152
|
+
directoryMode: "700",
|
|
153
|
+
});
|
|
154
|
+
return getMachineId(generated.domain, domain);
|
|
155
|
+
}
|
|
156
|
+
|
|
111
157
|
/** Makes a checkout list exactly these machines: those named are written with the addresses given,
|
|
112
158
|
and anything not named is removed. So read them, change what you want, and write the result.
|
|
113
159
|
|
|
@@ -160,7 +206,19 @@ export async function setMachines(config: {
|
|
|
160
206
|
return written;
|
|
161
207
|
}
|
|
162
208
|
|
|
163
|
-
|
|
209
|
+
function parseMachineFile(name: string, contents: string): MachineState | undefined {
|
|
210
|
+
try {
|
|
211
|
+
let parsed = JSON.parse(contents);
|
|
212
|
+
let machineId = parsed.machineId || name.replace(/\.json$/, "");
|
|
213
|
+
return { machineId, ips: parsed.ips || [], addedAt: parsed.addedAt || "" };
|
|
214
|
+
} catch (e) {
|
|
215
|
+
console.log(`Ignoring unreadable machine file ${name}. ${e}`);
|
|
216
|
+
return undefined;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/** Every machine file on disk. For editing the repo, not for deciding trust - trust reads the
|
|
221
|
+
signed files through readTrustedMachines. */
|
|
164
222
|
async function readMachines(repoPath: string) {
|
|
165
223
|
let machines = new Map<string, MachineState>();
|
|
166
224
|
let directory = path.join(repoPath, MACHINES_DIR);
|
|
@@ -169,12 +227,9 @@ async function readMachines(repoPath: string) {
|
|
|
169
227
|
if (!name.endsWith(".json")) {
|
|
170
228
|
continue;
|
|
171
229
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
machines.set(machineId, { machineId, ips: parsed.ips || [], addedAt: parsed.addedAt || "" });
|
|
176
|
-
} catch (e) {
|
|
177
|
-
console.log(`Ignoring unreadable machine file ${name}. ${e}`);
|
|
230
|
+
let machine = parseMachineFile(name, await fs.readFile(path.join(directory, name), "utf8").catch(() => ""));
|
|
231
|
+
if (machine) {
|
|
232
|
+
machines.set(machine.machineId, machine);
|
|
178
233
|
}
|
|
179
234
|
}
|
|
180
235
|
return machines;
|
|
@@ -331,53 +386,75 @@ export async function isMachineAccepted(config: {
|
|
|
331
386
|
if (!machineId || !ip) {
|
|
332
387
|
throw new Error(`Expected a machineId and an ip, was ${JSON.stringify(machineId)} and ${JSON.stringify(ip)}`);
|
|
333
388
|
}
|
|
334
|
-
if (LOOPBACK.includes(ip) && !!domain && machineId === getOwnMachineId(domain)) {
|
|
335
|
-
return { accepted: true, reason: "" };
|
|
336
|
-
}
|
|
337
|
-
let { sourceURL } = await keysRepo();
|
|
338
|
-
// Verified before it is believed, and cached, since this is asked once per request.
|
|
339
|
-
let machine = (await getTrustedMachines()).find(entry => entry.machineId === machineId);
|
|
340
|
-
if (!machine) {
|
|
341
|
-
return { accepted: false, reason: `that machine is not trusted. ${addMachineCommand({ machineId, ip, domain })}` };
|
|
342
|
-
}
|
|
343
389
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
//
|
|
347
|
-
//
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
// Any revocation nothing has undone keeps the machine out, from everywhere, the way a revoked
|
|
352
|
-
// ssh key is out everywhere rather than only from the address it was misused from.
|
|
353
|
-
let frozenFrom = "";
|
|
354
|
-
for (let revocation of revocations) {
|
|
355
|
-
if (revocation.machineId !== machineId) {
|
|
356
|
-
continue;
|
|
390
|
+
// The whole check, plus whether it froze the machine. A rejection that froze it is final, so
|
|
391
|
+
// there is nothing to gain from looking again. Any other rejection might just be a stale view -
|
|
392
|
+
// a machine added seconds ago that our cached list has not caught up to - so it is worth one
|
|
393
|
+
// fresh look, which is what the retry below does.
|
|
394
|
+
let evaluate = async (): Promise<{ verdict: MachineVerdict; froze: boolean }> => {
|
|
395
|
+
if (LOOPBACK.includes(ip) && !!domain && machineId === getOwnMachineId(domain)) {
|
|
396
|
+
return { verdict: { accepted: true, reason: "" }, froze: false };
|
|
357
397
|
}
|
|
358
|
-
|
|
359
|
-
|
|
398
|
+
let { sourceURL } = await keysRepo();
|
|
399
|
+
// Verified before it is believed, and cached, since this is asked once per request.
|
|
400
|
+
let machine = (await getTrustedMachines()).find(entry => entry.machineId === machineId);
|
|
401
|
+
if (!machine) {
|
|
402
|
+
return { verdict: { accepted: false, reason: `that machine is not trusted. ${addMachineCommand({ machineId, ip, domain })}` }, froze: false };
|
|
360
403
|
}
|
|
361
|
-
}
|
|
362
|
-
if (frozenFrom) {
|
|
363
|
-
return {
|
|
364
|
-
accepted: false,
|
|
365
|
-
reason: `that machine is frozen, it was used from ${frozenFrom} which it is not allowed from`,
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
404
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
405
|
+
await syncRevocations(sourceURL);
|
|
406
|
+
let unrevokes = await readUnrevokes(sourceURL).catch(() => ({ pairs: new Map(), legacyIds: new Map() }));
|
|
407
|
+
// An unrevoke counts as soon as it is seen. It is signed, so writing one already takes the
|
|
408
|
+
// hardware key, and anyone holding that can sign anything at all - a wait before honouring it
|
|
409
|
+
// guards against an attacker who has no need of it.
|
|
410
|
+
let allowedAgain = (pair: string) => !!unrevokes.pairs.get(pair)?.length;
|
|
411
|
+
let revocations = await readMachineRevocations(sourceURL);
|
|
412
|
+
// Any revocation nothing has undone keeps the machine out, from everywhere, the way a revoked
|
|
413
|
+
// ssh key is out everywhere rather than only from the address it was misused from.
|
|
414
|
+
let frozenFrom = "";
|
|
415
|
+
for (let revocation of revocations) {
|
|
416
|
+
if (revocation.machineId !== machineId) {
|
|
417
|
+
continue;
|
|
418
|
+
}
|
|
419
|
+
if (!allowedAgain(pairKey({ fingerprint: revocation.machineId, ip: revocation.ip }))) {
|
|
420
|
+
frozenFrom = revocation.ip;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
if (frozenFrom) {
|
|
424
|
+
return {
|
|
425
|
+
verdict: { accepted: false, reason: `that machine is frozen, it was used from ${frozenFrom} which it is not allowed from` },
|
|
426
|
+
froze: false,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
372
429
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
430
|
+
if (machine.ips.includes(ip)) {
|
|
431
|
+
return { verdict: { accepted: true, reason: "" }, froze: false };
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Listed, but talking to us from somewhere it should not be. Recorded once for this machine
|
|
435
|
+
// and address, so being talked to repeatedly does not write repeatedly.
|
|
436
|
+
let pair = pairKey({ fingerprint: machineId, ip });
|
|
437
|
+
let alreadyRecorded = revocations.some(revocation =>
|
|
438
|
+
pairKey({ fingerprint: revocation.machineId, ip: revocation.ip }) === pair);
|
|
439
|
+
if (!alreadyRecorded && !allowedAgain(pair)) {
|
|
440
|
+
await recordMachineRevocation({ sourceURL, machineId, ip, hostLabel: os.hostname() });
|
|
441
|
+
return { verdict: { accepted: false, reason: `that machine is not allowed from ${ip}, so it is now frozen everywhere` }, froze: true };
|
|
442
|
+
}
|
|
443
|
+
return { verdict: { accepted: false, reason: `that machine is not allowed from ${ip}` }, froze: false };
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
let { verdict, froze } = await evaluate();
|
|
447
|
+
// An accept, or a rejection that just froze the machine, is the final word. Any other rejection
|
|
448
|
+
// might just be a stale list - a machine added seconds ago we have not caught up to - so it is
|
|
449
|
+
// worth one fresh look.
|
|
450
|
+
if (verdict.accepted || froze) {
|
|
451
|
+
return verdict;
|
|
452
|
+
}
|
|
453
|
+
// Re-read the list at most once a minute, so a burst of bad callers cannot make us re-read on
|
|
454
|
+
// every one of them, then take whatever the fresh look says as final.
|
|
455
|
+
if (Date.now() - lastMachinesInvalidation > MACHINES_INVALIDATION_INTERVAL) {
|
|
456
|
+
lastMachinesInvalidation = Date.now();
|
|
457
|
+
trustedMachines.reset();
|
|
381
458
|
}
|
|
382
|
-
return
|
|
459
|
+
return (await evaluate()).verdict;
|
|
383
460
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
@@ -203,4 +203,4 @@ function stopDiscordNotifications() {
|
|
|
203
203
|
}
|
|
204
204
|
exports.stopDiscordNotifications = stopDiscordNotifications;
|
|
205
205
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzY29yZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRpc2NvcmQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsMkRBQTZCO0FBRTdCLHNIQUFzSDtBQUN0SCxrR0FBa0c7QUFDbEcsOENBQThDO0FBRWpDLFFBQUEseUJBQXlCLEdBQUcsaUNBQWlDLENBQUM7QUFDM0UsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUM3QyxNQUFNLHNCQUFzQixHQUFHO0lBQzNCLG1DQUFtQztJQUNuQyxzQ0FBc0M7SUFDdEMsMENBQTBDO0NBQzdDLENBQUM7QUFDRixNQUFNLHFCQUFxQixHQUFHLElBQUksQ0FBQztBQUNuQyxNQUFNLHFCQUFxQixHQUFHLEdBQUcsQ0FBQztBQUNsQyxNQUFNLGlCQUFpQixHQUFHLENBQUMsQ0FBQztBQUM1QixNQUFNLHNCQUFzQixHQUFHLENBQUMsQ0FBQztBQUNqQyxNQUFNLHVCQUF1QixHQUFHLENBQUMsR0FBRyxJQUFJLENBQUM7QUFFekMsSUFBSSxpQkFJUyxDQUFDO0FBRWQsc0ZBQXNGO0FBQ3RGLDRDQUE0QztBQUM1QyxJQUFJLFNBQVMsR0FBcUIsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO0FBRXBEO3NDQUNzQztBQUN0QyxTQUFnQixnQkFBZ0IsQ0FBQyxNQUFnRDtJQUM3RSxJQUFJLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUN0QyxJQUFJLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUN4RyxJQUFJLFVBQVUsR0FBRyxL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Q29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5cbi8vIFBPUlRFRCBDT0RFOiBzZWN1cml0eS9hdXRob3JpemVkS2V5cy9kYWVtb24vcG9ydHNlY3VyZURhZW1vbi5qcyBlbWJlZHMgYSBoYW5kIHBvcnQgb2YgdGhpcyBmaWxlIGluIHBsYWluIEpTLCBzbyB0aGVcbi8vIGRhZW1vbiBjYW4gcnVuIHdpdGggbm8gZGVwZW5kZW5jaWVzLiBUaGUgdHdvIGFyZSBleHBlY3RlZCB0byBiZWhhdmUgaWRlbnRpY2FsbHkgLSBpZiB5b3UgY2hhbmdlXG4vLyBvbmUsIG1ha2UgdGhlIG1hdGNoaW5nIGNoYW5nZSBpbiB0aGUgb3RoZXIuXG5cbmV4cG9ydCBjb25zdCBERUZBVUxUX1dFQkhPT0tfRklMRV9QQVRIID0gXCIvZXRjL3BvcnRzZWN1cmUvZGlzY29yZC13ZWJob29rXCI7XG5jb25zdCBERUZBVUxUX0NIRUNLX0lOVEVSVkFMID0gNSAqIDYwICogMTAwMDtcbmNvbnN0IFZBTElEX1dFQkhPT0tfUFJFRklYRVMgPSBbXG4gICAgXCJodHRwczovL2Rpc2NvcmQuY29tL2FwaS93ZWJob29rcy9cIixcbiAgICBcImh0dHBzOi8vZGlzY29yZGFwcC5jb20vYXBpL3dlYmhvb2tzL1wiLFxuICAgIFwiaHR0cHM6Ly9jYW5hcnkuZGlzY29yZC5jb20vYXBpL3dlYmhvb2tzL1wiLFxuXTtcbmNvbnN0IERJU0NPUkRfTUVTU0FHRV9MSU1JVCA9IDIwMDA7XG5jb25zdCBNQVhfRVJST1JfQk9EWV9MRU5HVEggPSA1MDA7XG5jb25zdCBNQVhfU0VORF9BVFRFTVBUUyA9IDM7XG5jb25zdCBSRURBQ1RFRF9UT0tFTl9WSVNJQkxFID0gODtcbmNvbnN0IERFRkFVTFRfUkFURV9MSU1JVF9XQUlUID0gMiAqIDEwMDA7XG5cbmxldCBub3RpZmljYXRpb25TdGF0ZToge1xuICAgIGZpbGVQYXRoOiBzdHJpbmc7XG4gICAgd2ViaG9va1VSTDogc3RyaW5nO1xuICAgIGNoZWNrVGltZXI6IE5vZGVKUy5UaW1lb3V0O1xufSB8IHVuZGVmaW5lZDtcblxuLy8gRGlzY29yZCB3ZWJob29rcyBhcmUgcmF0ZSBsaW1pdGVkIChyb3VnaGx5IDUgcmVxdWVzdHMgcGVyIDIgc2Vjb25kcyksIHNvIGV2ZXJ5IHNlbmRcbi8vIGdvZXMgdGhyb3VnaCBvbmUgY2hhaW4gaW5zdGVhZCBvZiByYWNpbmcuXG5sZXQgc2VuZENoYWluOiBQcm9taXNlPHVua25vd24+ID0gUHJvbWlzZS5yZXNvbHZlKCk7XG5cbi8qKiBQdWxscyB0aGUgd2ViaG9vayBVUkwgb3V0IG9mIHdlYmhvb2sgZmlsZSBjb250ZW50cy4gYHNvdXJjZU5hbWVgIG9ubHkgYXBwZWFycyBpbiBlcnJvcnMsIHNvXG4gICAgY2FsbGVycyBjYW4gbmFtZSBhIHJlbW90ZSBwYXRoLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlV2ViaG9va0ZpbGUoY29uZmlnOiB7IGNvbnRlbnRzOiBzdHJpbmc7IHNvdXJjZU5hbWU6IHN0cmluZyB9KSB7XG4gICAgbGV0IHsgY29udGVudHMsIHNvdXJjZU5hbWUgfSA9IGNvbmZpZztcbiAgICBsZXQgbGluZXMgPSBjb250ZW50cy5zcGxpdChcIlxcblwiKS5tYXAobGluZSA9PiBsaW5lLnRyaW0oKSkuZmlsdGVyKGxpbmUgPT4gbGluZSAmJiAhbGluZS5zdGFydHNXaXRoKFwiI1wiKSk7XG4gICAgbGV0IHdlYmhvb2tVUkwgPSBsaW5lc1swXTtcbiAgICBpZiAoIXdlYmhvb2tVUkwpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhIERpc2NvcmQgd2ViaG9vayBVUkwgaW4gJHtzb3VyY2VOYW1lfSwgdGhlIGZpbGUgaGFzIG5vIHVzYWJsZSBsaW5lc2ApO1xuICAgIH1cbiAgICBpZiAoIVZBTElEX1dFQkhPT0tfUFJFRklYRVMuc29tZShwcmVmaXggPT4gd2ViaG9va1VSTC5zdGFydHNXaXRoKHByZWZpeCkpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBFeHBlY3RlZCBhIERpc2NvcmQgd2ViaG9vayBVUkwgc3RhcnRpbmcgd2l0aCBvbmUgb2YgJHtWQUxJRF9XRUJIT09LX1BSRUZJWEVTLmpvaW4oXCIsIFwiKX0sIGBcbiAgICAgICAgICAgICsgYHdhcyAke3dlYmhvb2tVUkwuc2xpY2UoMCwgTUFYX0VSUk9SX0JPRFlfTEVOR1RIKX0gKGluICR7c291cmNlTmFtZX0pYFxuICAgICAgICApO1xuICAgIH1cbiAgICByZXR1cm4gd2ViaG9va1VSTDtcbn1cblxuLyoqIEtlZXBzIHRoZSBpZCBhbmQgYm90aCBlbmRzIG9mIHRoZSB0b2tlbiwgc28gYSByZWFkZXIgY2FuIGNvbmZpcm0gd2hpY2ggd2ViaG9vayByZXBsYWNlZCB0aGVpcnNcbiAgICB3aXRob3V0IHJlY2VpdmluZyBvbmUgdGhleSBjb3VsZCBwb3N0IHRvLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZGFjdFdlYmhvb2tVUkwod2ViaG9va1VSTDogc3RyaW5nKSB7XG4gICAgbGV0IHNlcGFyYXRvckluZGV4ID0gd2ViaG9va1VSTC5sYXN0SW5kZXhPZihcIi9cIik7XG4gICAgbGV0IGJhc2UgPSB3ZWJob29rVVJMLnNsaWNlKDAsIHNlcGFyYXRvckluZGV4ICsgMSk7XG4gICAgbGV0IHRva2VuID0gd2ViaG9va1VSTC5zbGljZShzZXBhcmF0b3JJbmRleCArIDEpO1xuICAgIGlmICh0b2tlbi5sZW5ndGggPD0gUkVEQUNURURfVE9LRU5fVklTSUJMRSAqIDIpIHtcbiAgICAgICAgLy8gVG9vIHNob3J0IHRvIHNob3cgYm90aCBlbmRzIHdpdGhvdXQgZ2l2aW5nIGF3YXkgdGhlIHdob2xlIHRva2VuLlxuICAgICAgICByZXR1cm4gYCR7YmFzZX0ke3Rva2VuLnNsaWNlKDAsIFJFREFDVEVEX1RPS0VOX1ZJU0lCTEUpfS4uLmA7XG4gICAgfVxuICAgIHJldHVybiBgJHtiYXNlfSR7dG9rZW4uc2xpY2UoMCwgUkVEQUNURURfVE9LRU5fVklTSUJMRSl9Li4uJHt0b2tlbi5zbGljZSgtUkVEQUNURURfVE9LRU5fVklTSUJMRSl9YDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdFdlYmhvb2tGaWxlKHdlYmhvb2tVUkw6IHN0cmluZykge1xuICAgIHJldHVybiBgIyBwb3J0c2VjdXJlIERpc2NvcmQgd2ViaG9vay4gRmlyc3Qgbm9uLWNvbW1lbnQgbGluZSBpcyB1c2VkLlxcbiR7d2ViaG9va1VSTH1cXG5gO1xufVxuXG5hc3luYyBmdW5jdGlvbiByZWFkV2ViaG9va0ZpbGUoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIGxldCBjb250ZW50cztcbiAgICB0cnkge1xuICAgICAgICBjb250ZW50cyA9IGF3YWl0IGZzLnJlYWRGaWxlKGZpbGVQYXRoLCBcInV0ZjhcIik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgcmVhZGFibGUgRGlzY29yZCB3ZWJob29rIGZpbGUgYXQgJHtmaWxlUGF0aH0sICR7ZX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcnNlV2ViaG9va0ZpbGUoeyBjb250ZW50cywgc291cmNlTmFtZTogZmlsZVBhdGggfSk7XG59XG5cbi8qKiBXaGVuIHRoZSBtZXNzYWdlIHdhcyBzZW50LCBpbiB0aGUgc2VuZGluZyBtYWNoaW5lJ3Mgb3duIHRpbWUgem9uZS4gRGlzY29yZCBzaG93cyB3aGVuIGl0XG4gICAgcmVjZWl2ZWQgc29tZXRoaW5nLCB3aGljaCBpcyBub3QgdGhlIHNhbWUgdGhpbmcgd2hlbiBhIG1hY2hpbmUgaGFzIGJlZW4gb2ZmbGluZSBvciBhIHNlbmQgaGFzXG4gICAgYmVlbiByZXRyaWVkLCBhbmQgdGhlIHpvbmUgbWF0dGVycyB3aGVuIHRoZSBtYWNoaW5lcyBhcmUgbm90IGFsbCBpbiBvbmUgcGxhY2UuICovXG5leHBvcnQgZnVuY3Rpb24gbWVzc2FnZVRpbWVzdGFtcChub3c6IERhdGUpIHtcbiAgICBsZXQgZGF0ZSA9IG5vdy50b0xvY2FsZURhdGVTdHJpbmcoXCJlbi1DQVwiKTtcbiAgICBsZXQgdGltZSA9IG5vdy50b0xvY2FsZVRpbWVTdHJpbmcoXCJlbi1VU1wiLCB7XG4gICAgICAgIGhvdXI6IFwiMi1kaWdpdFwiLFxuICAgICAgICBtaW51dGU6IFwiMi1kaWdpdFwiLFxuICAgICAgICBzZWNvbmQ6IFwiMi1kaWdpdFwiLFxuICAgICAgICBob3VyMTI6IHRydWUsXG4gICAgICAgIHRpbWVab25lTmFtZTogXCJzaG9ydFwiLFxuICAgIH0pO1xuICAgIHJldHVybiBgJHtkYXRlfSAke3RpbWV9YDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcG9zdFRvV2ViaG9vayh3ZWJob29rVVJMOiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZykge1xuICAgIC8vIFN0YW1wZWQgb25jZSByYXRoZXIgdGhhbiBwZXIgYXR0ZW1wdCwgc28gYSByZXRyeSBzYXlzIHdoZW4gdGhlIHRoaW5nIGhhcHBlbmVkIHJhdGhlciB0aGFuXG4gICAgLy8gd2hlbiB3ZSBsYXN0IG1hbmFnZWQgdG8gZ2V0IGl0IG91dC4gQXQgdGhlIGVuZCwgYmVjYXVzZSB0aGUgZmlyc3QgbGluZSBvZiBhIG1lc3NhZ2UgaXMgdGhlXG4gICAgLy8gbm90aWZpY2F0aW9uIHByZXZpZXcgYW5kIGEgdGltZXN0YW1wIHRoZXJlIHdvdWxkIHNwZW5kIGl0IHNheWluZyBub3RoaW5nLlxuICAgIGxldCBjb250ZW50ID0gYCR7bWVzc2FnZX0gwrcgXFxgJHttZXNzYWdlVGltZXN0YW1wKG5ldyBEYXRlKCkpfVxcYGA7XG4gICAgaWYgKGNvbnRlbnQubGVuZ3RoID4gRElTQ09SRF9NRVNTQUdFX0xJTUlUKSB7XG4gICAgICAgIGNvbnRlbnQgPSBjb250ZW50LnNsaWNlKDAsIERJU0NPUkRfTUVTU0FHRV9MSU1JVCAtIDMpICsgXCIuLi5cIjtcbiAgICB9XG4gICAgZm9yIChsZXQgYXR0ZW1wdCA9IDE7IGF0dGVtcHQgPD0gTUFYX1NFTkRfQVRURU1QVFM7IGF0dGVtcHQrKykge1xuICAgICAgICBsZXQgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh3ZWJob29rVVJMLCB7XG4gICAgICAgICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgICAgICAgaGVhZGVyczogeyBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIiB9LFxuICAgICAgICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoeyBjb250ZW50IH0pLFxuICAgICAgICB9KTtcbiAgICAgICAgaWYgKHJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGJvZHkgPSAoYXdhaXQgcmVzcG9uc2UudGV4dCgpKS5zbGljZSgwLCBNQVhfRVJST1JfQk9EWV9MRU5HVEgpO1xuICAgICAgICBpZiAocmVzcG9uc2Uuc3RhdHVzID09PSA0MjkgJiYgYXR0ZW1wdCA8IE1BWF9TRU5EX0FUVEVNUFRTKSB7XG4gICAgICAgICAgICBsZXQgcmV0cnlBZnRlciA9IE51bWJlcihyZXNwb25zZS5oZWFkZXJzLmdldChcInJldHJ5LWFmdGVyXCIpKTtcbiAgICAgICAgICAgIGxldCB3YWl0VGltZSA9IHJldHJ5QWZ0ZXIgJiYgcmV0cnlBZnRlciAqIDEwMDAgfHwgREVGQVVMVF9SQVRFX0xJTUlUX1dBSVQ7XG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgd2FpdFRpbWUpKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBFeHBlY3RlZCBhIDJ4eCByZXNwb25zZSBmcm9tIHRoZSBEaXNjb3JkIHdlYmhvb2ssIHdhcyAke3Jlc3BvbnNlLnN0YXR1c30gJHtyZXNwb25zZS5zdGF0dXNUZXh0fSwgYm9keSAke2JvZHl9YFxuICAgICAgICApO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gcXVldWVTZW5kKHdlYmhvb2tVUkw6IHN0cmluZywgbWVzc2FnZTogc3RyaW5nKSB7XG4gICAgbGV0IHNlbmQgPSAoKSA9PiBwb3N0VG9XZWJob29rKHdlYmhvb2tVUkwsIG1lc3NhZ2UpO1xuICAgIGxldCByZXN1bHQgPSBzZW5kQ2hhaW4udGhlbihzZW5kLCBzZW5kKTtcbiAgICBzZW5kQ2hhaW4gPSByZXN1bHQuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKiogU2VuZHMgdG8gYW4gZXhwbGljaXQgd2ViaG9vayBVUkwsIGZvciB0b29saW5nIHRoYXQgYWN0cyBvbiBhIHdlYmhvb2sgYmVmb3JlIChvciBpbnN0ZWFkIG9mKVxuICAgIGNvbmZpZ3VyZURpc2NvcmROb3RpZmljYXRpb25zIC0gc2V0dXAsIG1pZ3JhdGlvbnMsIGNvbm5lY3Rpdml0eSBjaGVja3MuICovXG5leHBvcnQgZnVuY3Rpb24gc2VuZFRvV2ViaG9va1VSTChjb25maWc6IHsgd2ViaG9va1VSTDogc3RyaW5nOyBtZXNzYWdlOiBzdHJpbmcgfSkge1xuICAgIHJldHVybiBxdWV1ZVNlbmQoY29uZmlnLndlYmhvb2tVUkwsIGNvbmZpZy5tZXNzYWdlKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2hlY2tXZWJob29rRmlsZUNoYW5nZWQoKSB7XG4gICAgbGV0IHN0YXRlID0gbm90aWZpY2F0aW9uU3RhdGU7XG4gICAgaWYgKCFzdGF0ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBuZXdXZWJob29rVVJMO1xuICAgIHRyeSB7XG4gICAgICAgIG5ld1dlYmhvb2tVUkwgPSBhd2FpdCByZWFkV2ViaG9va0ZpbGUoc3RhdGUuZmlsZVBhdGgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihgcG9ydHNlY3VyZTogRGlzY29yZCB3ZWJob29rIGZpbGUgaXMgbm8gbG9uZ2VyIHJlYWRhYmxlLCBzdGlsbCB1c2luZyB0aGUgbG9hZGVkIHdlYmhvb2suICR7ZX1gKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAobmV3V2ViaG9va1VSTCA9PT0gc3RhdGUud2ViaG9va1VSTCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIFdhcm4gdGhlIG9sZCBjaGFubmVsIGZpcnN0LCB3aXRoIHRoZSBuZXcgd2ViaG9vayByZWRhY3RlZCwgc28gYSBzdG9sZW4gb2xkIHdlYmhvb2sgZG9lcyBub3RcbiAgICAvLyBoYW5kIHRoZSBhdHRhY2tlciBhIHVzYWJsZSBuZXcgb25lLlxuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHF1ZXVlU2VuZChcbiAgICAgICAgICAgIHN0YXRlLndlYmhvb2tVUkwsXG4gICAgICAgICAgICBgKipwb3J0c2VjdXJlKio6ICoqTk9USUZJQ0FUSU9OUyBBUkUgTU9WSU5HIFRPIEFOT1RIRVIgQ0hBTk5FTCoqYFxuICAgICAgICAgICAgKyBgXFxuXFxuVGhpcyBjaGFubmVsIHN0b3BzIHJlY2VpdmluZyB0aGVtIG5vdy4gSWYgdGhhdCB3YXMgbm90IHlvdSwgc29tZWJvZHkgd2l0aCBhY2Nlc3NgXG4gICAgICAgICAgICArIGAgdG8gdGhpcyBtYWNoaW5lIGp1c3QgcmVkaXJlY3RlZCBpdHMgYWxlcnRzLmBcbiAgICAgICAgICAgICsgYFxcblxcbm5ldyB3ZWJob29rOiBcXGAke3JlZGFjdFdlYmhvb2tVUkwobmV3V2ViaG9va1VSTCl9XFxgYFxuICAgICAgICAgICAgKyBgXFxuc2V0IGluOiBcXGAke3N0YXRlLmZpbGVQYXRofVxcYGBcbiAgICAgICAgKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoYHBvcnRzZWN1cmU6IGZhaWxlZCB0byB3YXJuIHRoZSBvbGQgRGlzY29yZCB3ZWJob29rIGFib3V0IHRoZSBjaGFuZ2UuICR7ZX1gKTtcbiAgICB9XG4gICAgc3RhdGUud2ViaG9va1VSTCA9IG5ld1dlYmhvb2tVUkw7XG59XG5cbi8qKiBNdXN0IGJlIGNhbGxlZCBvbmNlIG9uIHN0YXJ0dXAsIGJlZm9yZSBhbnkgbm90aWZpY2F0aW9uIGlzIHNlbnQuIEFib3J0cyB0aGUgcHJvY2VzcyBpZiB0aGVcbiAgICB3ZWJob29rIGZpbGUgaXMgbWlzc2luZyBvciBpbnZhbGlkLCB0aGVuIHJlLWNoZWNrcyB0aGUgZmlsZSBvbiBhbiBpbnRlcnZhbCBhbmQgd2FybnMgdGhlIG9sZFxuICAgIHdlYmhvb2sgd2hlbmV2ZXIgaXQgY2hhbmdlcy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjb25maWd1cmVEaXNjb3JkTm90aWZpY2F0aW9ucyhjb25maWc/OiB7XG4gICAgZmlsZVBhdGg/OiBzdHJpbmc7XG4gICAgY2hlY2tJbnRlcnZhbD86IG51bWJlcjtcbn0pIHtcbiAgICBpZiAobm90aWZpY2F0aW9uU3RhdGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBjb25maWd1cmVEaXNjb3JkTm90aWZpY2F0aW9ucyB0byBiZSBjYWxsZWQgb25jZSwgd2FzIGNhbGxlZCBhZ2FpbiAoYWxyZWFkeSB1c2luZyAke25vdGlmaWNhdGlvblN0YXRlLmZpbGVQYXRofSlgKTtcbiAgICB9XG4gICAgbGV0IGZpbGVQYXRoID0gY29uZmlnPy5maWxlUGF0aCB8fCBERUZBVUxUX1dFQkhPT0tfRklMRV9QQVRIO1xuICAgIGxldCBjaGVja0ludGVydmFsID0gY29uZmlnPy5jaGVja0ludGVydmFsIHx8IERFRkFVTFRfQ0hFQ0tfSU5URVJWQUw7XG4gICAgbGV0IHdlYmhvb2tVUkw7XG4gICAgdHJ5IHtcbiAgICAgICAgd2ViaG9va1VSTCA9IGF3YWl0IHJlYWRXZWJob29rRmlsZShmaWxlUGF0aCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBwb3J0c2VjdXJlOiByZWZ1c2luZyB0byBzdGFydCB3aXRob3V0IGEgdmFsaWQgRGlzY29yZCB3ZWJob29rIGZpbGUuXFxuJHtlfWApO1xuICAgICAgICBwcm9jZXNzLmV4aXQoMSk7XG4gICAgfVxuICAgIGxldCBjaGVja1RpbWVyID0gc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgICAgICBjaGVja1dlYmhvb2tGaWxlQ2hhbmdlZCgpLmNhdGNoKGUgPT4gY29uc29sZS5lcnJvcihgcG9ydHNlY3VyZTogRGlzY29yZCB3ZWJob29rIGZpbGUgY2hlY2sgZmFpbGVkLiAke2V9YCkpO1xuICAgIH0sIGNoZWNrSW50ZXJ2YWwpO1xuICAgIC8vIFRoZSBjaGVjayBzaG91bGQgbmV2ZXIgYmUgdGhlIHJlYXNvbiB0aGUgcHJvY2VzcyBzdGF5cyBhbGl2ZS5cbiAgICBjaGVja1RpbWVyLnVucmVmKCk7XG4gICAgbm90aWZpY2F0aW9uU3RhdGUgPSB7IGZpbGVQYXRoLCB3ZWJob29rVVJMLCBjaGVja1RpbWVyIH07XG4gICAgcmV0dXJuIHsgZmlsZVBhdGgsIGNoZWNrSW50ZXJ2YWwgfTtcbn1cblxuLy8gRE8gTk9UIGFkZCBuZXcgY2FsbHMgdG8gdGhpcy4gRXZlcnkgbWVzc2FnZSBnb2VzIHRvIGEgcmVhbCBEaXNjb3JkIHNlcnZlciBzb21lb25lIHJlYWRzLCBzbyBhXG4vLyBub3RpZmljYXRpb24gaXMgb25seSBldmVyIGFkZGVkIHdoZW4gdGhlIHVzZXIgZXhwbGljaXRseSBhc2tzIGZvciB0aGF0IHNwZWNpZmljIGNhc2UuIFN0YXJ0dXAsXG4vLyBzdWNjZXNzLCBlcnJvcnMsIHJldHJpZXMgYW5kIHJlY292ZXJpZXMgYWxsIGJlbG9uZyBpbiBhIGxvZyBpbnN0ZWFkLlxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNlbmREaXNjb3JkTm90aWZpY2F0aW9uKG1lc3NhZ2U6IHN0cmluZykge1xuICAgIGxldCBzdGF0ZSA9IG5vdGlmaWNhdGlvblN0YXRlO1xuICAgIGlmICghc3RhdGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBjb25maWd1cmVEaXNjb3JkTm90aWZpY2F0aW9ucyB0byBiZSBjYWxsZWQgYmVmb3JlIHNlbmRpbmcsIHdhcyBjYWxsZWQgd2l0aCBtZXNzYWdlICR7bWVzc2FnZS5zbGljZSgwLCBNQVhfRVJST1JfQk9EWV9MRU5HVEgpfWApO1xuICAgIH1cbiAgICBhd2FpdCBxdWV1ZVNlbmQoc3RhdGUud2ViaG9va1VSTCwgbWVzc2FnZSk7XG59XG5cbi8qKiBXaGV0aGVyIG5vdGlmaWNhdGlvbnMgYXJlIHNldCB1cCBpbiB0aGlzIHByb2Nlc3MuIEZvciBjb2RlIHRoYXQgbWF5IHJ1biBvdXRzaWRlIHRoZSBkYWVtb24sXG4gICAgd2hlcmUgc2VuZGluZyBpcyB3b3J0aCBkb2luZyBpZiBpdCBjYW4gYmUgYW5kIG5vdCB3b3J0aCBmYWlsaW5nIG92ZXIgaWYgaXQgY2Fubm90LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGFyZURpc2NvcmROb3RpZmljYXRpb25zQ29uZmlndXJlZCgpIHtcbiAgICByZXR1cm4gISFub3RpZmljYXRpb25TdGF0ZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHN0b3BEaXNjb3JkTm90aWZpY2F0aW9ucygpIHtcbiAgICBpZiAoIW5vdGlmaWNhdGlvblN0YXRlKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY2xlYXJJbnRlcnZhbChub3RpZmljYXRpb25TdGF0ZS5jaGVja1RpbWVyKTtcbiAgICBub3RpZmljYXRpb25TdGF0ZSA9IHVuZGVmaW5lZDtcbn1cbiJdfQ==
|
|
206
|
-
/* _JS_SOURCE_HASH = "
|
|
206
|
+
/* _JS_SOURCE_HASH = "a4fe18f537fa6da028d1607b16331b146697f9fabb96c6de058f0b41c5553b17"; */
|
|
@@ -24,7 +24,7 @@ function parseArgs(argv: string[]) {
|
|
|
24
24
|
return { host, webhookURL, replace };
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
async function main() {
|
|
28
28
|
let { host, webhookURL, replace } = parseArgs(process.argv.slice(2));
|
|
29
29
|
let { outcome, filePath } = await ensureRemoteWebhook({ host, webhookURL, replace });
|
|
30
30
|
if (outcome === "unchanged") {
|
|
@@ -36,3 +36,8 @@ export async function main() {
|
|
|
36
36
|
}
|
|
37
37
|
console.log(`Wrote ${filePath} on ${describeHost(host)} (mode 600), and confirmed on the new webhook.`);
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
main().catch(e => {
|
|
41
|
+
console.error(`${e}`);
|
|
42
|
+
process.exitCode = 1;
|
|
43
|
+
}).finally(() => process.exit());
|
|
@@ -9,7 +9,7 @@ Sends one message to a webhook, to prove it works. With no host it uses this mac
|
|
|
9
9
|
${DEFAULT_WEBHOOK_FILE_PATH}. With a host it reads that host's webhook and sends to that instead,
|
|
10
10
|
which is how you check a machine you have just set up.`;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
async function main() {
|
|
13
13
|
let argv = process.argv.slice(2);
|
|
14
14
|
if (argv.length > 1) {
|
|
15
15
|
throw new Error(`Expected at most a host, was ${argv.length} argument(s)\n${USAGE}`);
|
|
@@ -46,3 +46,8 @@ export async function main() {
|
|
|
46
46
|
});
|
|
47
47
|
console.log(`Sent a test message to the webhook ${source} uses.`);
|
|
48
48
|
}
|
|
49
|
+
|
|
50
|
+
main().catch(e => {
|
|
51
|
+
console.error(`${e}`);
|
|
52
|
+
process.exitCode = 1;
|
|
53
|
+
}).finally(() => process.exit());
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
@@ -82,4 +82,4 @@ function formatManifest(manifest) {
|
|
|
82
82
|
}
|
|
83
83
|
exports.formatManifest = formatManifest;
|
|
84
84
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFuaWZlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJtYW5pZmVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUN4Qiw0Q0FBZ0Q7QUFFaEQsa0dBQWtHO0FBQ2xHLGlHQUFpRztBQUNqRyxrR0FBa0c7QUFDbEcsdUJBQXVCO0FBRVYsUUFBQSxhQUFhLEdBQUcsa0JBQWtCLENBQUM7QUFDbkMsUUFBQSxjQUFjLEdBQUcsc0JBQXNCLENBQUM7QUFDckQsb0dBQW9HO0FBQ3ZGLFFBQUEsY0FBYyxHQUFHLFdBQVcsQ0FBQztBQUM3QixRQUFBLGdCQUFnQixHQUFHLENBQUMsQ0FBQztBQU9sQzs7Ozs7OzswRkFPMEY7QUFDbkYsS0FBSyxVQUFVLGFBQWEsQ0FBQyxRQUFnQjtJQUNoRCxJQUFJLE1BQU0sR0FBRyxNQUFNLElBQUEsb0JBQVksRUFBQztRQUM1QixPQUFPLEVBQUUsS0FBSztRQUNkLElBQUksRUFBRSxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLG9CQUFvQixDQUFDO1FBQ2hFLEdBQUcsRUFBRSxRQUFRO0tBQ2hCLENBQUMsQ0FBQztJQUNILElBQUksTUFBTSxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUN0QixNQUFNLElBQUksS0FBSyxDQUNYLGlDQUFpQyxRQUFRLHlCQUF5QixNQUFNLENBQUMsTUFBTSxJQUFJO2NBQ2pGLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUNoRCxDQUFDO0lBQ04sQ0FBQztJQUNELElBQUksTUFBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQztTQUNqQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7U0FDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLElBQUksS0FBSyxxQkFBYSxJQUFJLElBQUksS0FBSyxzQkFBYyxDQUFDO1NBQ3pFLElBQUksRUFBRSxDQUFDO0lBRVosSUFBSSxPQUFPLEdBQWEsRUFBRSxDQUFDO0lBQzNCLEtBQUssSUFBSSxZQUFZLElBQUksTUFBTSxFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDO1lBQ0QsTUFBTSxrQkFBRSxDQUFDLE1BQU0sQ0FBQyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO1lBQ25ELE9BQU8sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDL0IsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDVCxPQUFPLENBQUMsR0FBRyxDQUFDLFdBQVcsWUFBWSx3REFBd0QsQ0FBQyxDQUFDO1FBQ2pHLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxPQUFPLENBQUM7QUFDbkIsQ0FBQztBQTNCRCxzQ0EyQkM7QUFFRDs7OytCQUcrQjtBQUMvQixTQUFnQixnQkFBZ0IsQ0FBQyxRQUFnQjtJQUM3QyxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBQ3JGLENBQUM7QUFGRCw0Q0FFQztBQUVEOytGQUMrRjtBQUN4RixLQUFLLFVBQVUsVUFBVSxDQUFDLFFBQWdCO0lBQzdDLElBQUksUUFBUSxHQUFHLGdCQUFnQixDQUFDLE1BQU0sa0JBQUUsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztJQUM3RCxPQUFPLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLGdCQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztBQUN6RyxDQUFDO0FBSEQsZ0NBR0M7QUFFTSxLQUFLLFVBQVUsYUFBYSxDQUFDLFFBQWdCO0lBQ2hELElBQUksS0FBSyxHQUFzQixFQUFFLENBQUM7SUFDbEMsS0FBSyxJQUFJLFlBQVksSUFBSSxNQUFNLGFBQWEsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQ3JELElBQUksTUFBTSxHQUFHLE1BQU0sVUFBVSxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7UUFDakUsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO0lBQ2pGLENBQUM7SUFDRCxPQUFPLEVBQUUsT0FBTyxFQUFFLHdCQUFnQixFQUFFLEtBQUssRUFBRSxDQUFDO0FBQ2hELENBQUM7QUFQRCxzQ0FPQztBQUVELG1HQUFtRztBQUNuRyxTQUFnQixjQUFjLENBQUMsUUFBa0I7SUFDN0MsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDO0FBQ3pELENBQUM7QUFGRCx3Q0FFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IHNwYXduUHJvbWlzZSB9IGZyb20gXCIuLi9oZWxwZXJzL3NwYXduXCI7XG5cbi8vIFBPUlRFRCBDT0RFOiBzZWN1cml0eS9hdXRob3JpemVkS2V5cy9kYWVtb24vcG9ydHNlY3VyZURhZW1vbi5qcyBjb250YWlucyBhIHBsYWluIEpTIHBvcnQgb2YgdGhlXG4vLyB2ZXJpZnlpbmcgaGFsZiBvZiB0aGlzIGZpbGUsIHNvIGl0IGNhbiBjaGVjayBhIHNpZ25hdHVyZSB3aXRoIG5vIGRlcGVuZGVuY2llcy4gQm90aCBzaWRlcyBtdXN0XG4vLyBhZ3JlZSBvbiB0aGUgbWFuaWZlc3Qgc2hhcGUgYW5kIG9uIHdoaWNoIGZpbGVzIGl0IGNvdmVycyAtIGlmIHlvdSBjaGFuZ2Ugb25lLCBtYWtlIHRoZSBtYXRjaGluZ1xuLy8gY2hhbmdlIGluIHRoZSBvdGhlci5cblxuZXhwb3J0IGNvbnN0IE1BTklGRVNUX05BTUUgPSBcInNpZ25lZGZpbGVzLmpzb25cIjtcbmV4cG9ydCBjb25zdCBTSUdOQVRVUkVfTkFNRSA9IFwic2lnbmVkZmlsZXMuanNvbi5zaWdcIjtcbi8vIHNzaCBzaWduYXR1cmVzIGFyZSBuYW1lc3BhY2VkLCBzbyBhIHNpZ25hdHVyZSBtYWRlIGZvciBvbmUgcHVycG9zZSBjYW5ub3QgYmUgcmVwbGF5ZWQgYXMgYW5vdGhlci5cbmV4cG9ydCBjb25zdCBTSUdOX05BTUVTUEFDRSA9IFwic2lnbmZpbGVzXCI7XG5leHBvcnQgY29uc3QgTUFOSUZFU1RfVkVSU0lPTiA9IDE7XG5cbmV4cG9ydCB0eXBlIE1hbmlmZXN0ID0ge1xuICAgIHZlcnNpb246IG51bWJlcjtcbiAgICBmaWxlczogeyBwYXRoOiBzdHJpbmc7IHNpemU6IG51bWJlcjsgc2hhMjU2OiBzdHJpbmcgfVtdO1xufTtcblxuLyoqIEV2ZXJ5dGhpbmcgaW4gdGhlIHJlcG8gdGhhdCBpcyBub3QgaWdub3JlZDogd2hhdCBpcyBpbiB0aGUgaW5kZXgsIHBsdXMgd2hhdCBpcyBub3Qgc3RhZ2VkIHlldC5cbiAgICBHaXQgaXMgYXNrZWQgYmVjYXVzZSBnaXQgaXMgd2hhdCBrbm93cyBob3cgdG8gYXBwbHkgdGhlIGlnbm9yZSBydWxlcy5cblxuICAgIFdoYXQgY29tZXMgYmFjayBpcyBhIGhpbnQgdGhhdCBhIGZpbGUgbWlnaHQgYmUgdGhlcmUsIG5vdCB0aGF0IGl0IGlzLiBBIGZpbGUgZGVsZXRlZCBmcm9tIHRoZVxuICAgIHdvcmtpbmcgdHJlZSBzdGF5cyBpbiB0aGUgaW5kZXggdW50aWwgdGhhdCBkZWxldGlvbiBpcyBzdGFnZWQsIHNvIGdpdCBuYW1lcyBpdCBhbmQgdGhlcmUgaXNcbiAgICBub3RoaW5nIHRvIHJlYWQsIHdoaWNoIGlzIHdoeSBlYWNoIG9uZSBpcyBjaGVja2VkIGJlZm9yZSBpdCBnb2VzIGluLlxuXG4gICAgVGhlIG1hbmlmZXN0IGFuZCBpdHMgc2lnbmF0dXJlIGFyZSBsZWZ0IG91dCwgc2luY2UgdGhleSBjYW5ub3QgZGVzY3JpYmUgdGhlbXNlbHZlcy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0UmVwb0ZpbGVzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgcmVzdWx0ID0gYXdhaXQgc3Bhd25Qcm9taXNlKHtcbiAgICAgICAgY29tbWFuZDogXCJnaXRcIixcbiAgICAgICAgYXJnczogW1wibHMtZmlsZXNcIiwgXCItLWNhY2hlZFwiLCBcIi0tb3RoZXJzXCIsIFwiLS1leGNsdWRlLXN0YW5kYXJkXCJdLFxuICAgICAgICBjd2Q6IHJlcG9QYXRoLFxuICAgIH0pO1xuICAgIGlmIChyZXN1bHQuc3RhdHVzICE9PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBFeHBlY3RlZCB0byBsaXN0IHRoZSBmaWxlcyBpbiAke3JlcG9QYXRofSwgZ2l0IGxzLWZpbGVzIGV4aXRlZCAke3Jlc3VsdC5zdGF0dXN9LiBgXG4gICAgICAgICAgICArIGAkeyhyZXN1bHQuc3Rkb3V0ICsgcmVzdWx0LnN0ZGVycikudHJpbSgpfWBcbiAgICAgICAgKTtcbiAgICB9XG4gICAgbGV0IGxpc3RlZCA9IHJlc3VsdC5zdGRvdXQuc3BsaXQoXCJcXG5cIilcbiAgICAgICAgLm1hcChsaW5lID0+IGxpbmUudHJpbSgpKVxuICAgICAgICAuZmlsdGVyKGxpbmUgPT4gbGluZSAmJiBsaW5lICE9PSBNQU5JRkVTVF9OQU1FICYmIGxpbmUgIT09IFNJR05BVFVSRV9OQU1FKVxuICAgICAgICAuc29ydCgpO1xuXG4gICAgbGV0IHByZXNlbnQ6IHN0cmluZ1tdID0gW107XG4gICAgZm9yIChsZXQgcmVsYXRpdmVQYXRoIG9mIGxpc3RlZCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZnMuYWNjZXNzKHBhdGguam9pbihyZXBvUGF0aCwgcmVsYXRpdmVQYXRoKSk7XG4gICAgICAgICAgICBwcmVzZW50LnB1c2gocmVsYXRpdmVQYXRoKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coYExlYXZpbmcgJHtyZWxhdGl2ZVBhdGh9IG91dCBvZiB0aGUgbWFuaWZlc3QsIGl0IGlzIGdvbmUgZnJvbSB0aGUgd29ya2luZyB0cmVlYCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHByZXNlbnQ7XG59XG5cbi8qKiBBIFdpbmRvd3MgY2hlY2tvdXQgdHVybnMgTEYgaW50byBDUkxGLCBzbyB0aGUgc2FtZSBjb21taXQgaGFzaGVzIGRpZmZlcmVudGx5IHRoZXJlIHRoYW4gaXRcbiAgICBkb2VzIG9uIHRoZSBtYWNoaW5lIHRoYXQgcHVsbHMgaXQuIE5vcm1hbGlzaW5nIGZpcnN0IG1ha2VzIHRoZSBkaWdlc3QgZGVzY3JpYmUgdGhlIGNvbnRlbnRcbiAgICByYXRoZXIgdGhhbiB3aGljaGV2ZXIgY2hlY2tvdXQgcHJvZHVjZWQgaXQuIGxhdGluMSByb3VuZCB0cmlwcyBldmVyeSBieXRlLCBzbyB0aGlzIGlzIHNhZmUgb25cbiAgICBmaWxlcyB0aGF0IGFyZSBub3QgdGV4dC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBub3JtYWxpemVDb250ZW50KGNvbnRlbnRzOiBCdWZmZXIpIHtcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oY29udGVudHMudG9TdHJpbmcoXCJsYXRpbjFcIikucmVwbGFjZSgvXFxyXFxuL2csIFwiXFxuXCIpLCBcImxhdGluMVwiKTtcbn1cblxuLyoqIFRoZSBzaXplIGFuZCBoYXNoIG9mIGEgZmlsZSdzIG5vcm1hbGlzZWQgY29udGVudC4gVGhlIHNpemUgaXMgdGhlIG5vcm1hbGlzZWQgb25lIG9uIHB1cnBvc2UsXG4gICAgc28gaXQgYWdyZWVzIHdpdGggdGhlIGhhc2ggcmF0aGVyIHRoYW4gd2l0aCB3aGF0ZXZlciB0aGUgbG9jYWwgY2hlY2tvdXQgaGFwcGVucyB0byBob2xkLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGRpZ2VzdEZpbGUoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIGxldCBjb250ZW50cyA9IG5vcm1hbGl6ZUNvbnRlbnQoYXdhaXQgZnMucmVhZEZpbGUoZmlsZVBhdGgpKTtcbiAgICByZXR1cm4geyBzaXplOiBjb250ZW50cy5sZW5ndGgsIHNoYTI1NjogY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGNvbnRlbnRzKS5kaWdlc3QoXCJoZXhcIikgfTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJ1aWxkTWFuaWZlc3QocmVwb1BhdGg6IHN0cmluZykge1xuICAgIGxldCBmaWxlczogTWFuaWZlc3RbXCJmaWxlc1wiXSA9IFtdO1xuICAgIGZvciAobGV0IHJlbGF0aXZlUGF0aCBvZiBhd2FpdCBsaXN0UmVwb0ZpbGVzKHJlcG9QYXRoKSkge1xuICAgICAgICBsZXQgZGlnZXN0ID0gYXdhaXQgZGlnZXN0RmlsZShwYXRoLmpvaW4ocmVwb1BhdGgsIHJlbGF0aXZlUGF0aCkpO1xuICAgICAgICBmaWxlcy5wdXNoKHsgcGF0aDogcmVsYXRpdmVQYXRoLCBzaXplOiBkaWdlc3Quc2l6ZSwgc2hhMjU2OiBkaWdlc3Quc2hhMjU2IH0pO1xuICAgIH1cbiAgICByZXR1cm4geyB2ZXJzaW9uOiBNQU5JRkVTVF9WRVJTSU9OLCBmaWxlcyB9O1xufVxuXG4vKiogU29ydGVkIGtleXMgYW5kIGEgdHJhaWxpbmcgbmV3bGluZSwgc28gdGhlIHNhbWUgdHJlZSBhbHdheXMgcHJvZHVjZXMgdGhlIHNhbWUgYnl0ZXMgdG8gc2lnbi4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRNYW5pZmVzdChtYW5pZmVzdDogTWFuaWZlc3QpIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkobWFuaWZlc3QsIHVuZGVmaW5lZCwgNCkgKyBcIlxcblwiO1xufVxuIl19
|
|
85
|
-
/* _JS_SOURCE_HASH = "
|
|
85
|
+
/* _JS_SOURCE_HASH = "201e773734f1a3a4a276457669646f936d46b81026afab845e5b8161d1b4310d"; */
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
6
|
+
//exports.verifySSHSIG = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
// Verifies an SSHSIG signature (the format ssh-keygen -Y sign produces) in process, so nothing has
|
|
9
|
+
// to shell out to ssh-keygen to check one. The wire format is PROTOCOL.sshsig, and the actual
|
|
10
|
+
// check is one ed25519 verification.
|
|
11
|
+
//
|
|
12
|
+
// Both ed25519 and the hardware sk-ed25519 variant are handled, since signfiles signs with a
|
|
13
|
+
// hardware ed25519-sk key. The sk variant signs a little more than the message - the authenticator
|
|
14
|
+
// flags and counter go in too - but it is still ed25519 underneath.
|
|
15
|
+
const MAGIC = "SSHSIG";
|
|
16
|
+
// An ed25519 public key as a DER SPKI is this fixed 12 byte header followed by the 32 byte key.
|
|
17
|
+
const ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
18
|
+
/** Reads the length prefixed fields SSH wire format is made of. */
|
|
19
|
+
class Reader {
|
|
20
|
+
constructor(buffer) {
|
|
21
|
+
this.buffer = buffer;
|
|
22
|
+
this.offset = 0;
|
|
23
|
+
}
|
|
24
|
+
u8() {
|
|
25
|
+
return this.buffer.readUInt8(this.offset++);
|
|
26
|
+
}
|
|
27
|
+
u32() {
|
|
28
|
+
let value = this.buffer.readUInt32BE(this.offset);
|
|
29
|
+
this.offset += 4;
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
string() {
|
|
33
|
+
let length = this.u32();
|
|
34
|
+
let value = this.buffer.subarray(this.offset, this.offset + length);
|
|
35
|
+
this.offset += length;
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
remaining() {
|
|
39
|
+
return this.buffer.length - this.offset;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** One length prefixed field, the way SSH writes them. */
|
|
43
|
+
function sshString(bytes) {
|
|
44
|
+
let length = Buffer.alloc(4);
|
|
45
|
+
length.writeUInt32BE(bytes.length);
|
|
46
|
+
return Buffer.concat([length, bytes]);
|
|
47
|
+
}
|
|
48
|
+
function hash(algorithm, data) {
|
|
49
|
+
// SSHSIG names sha256 or sha512; node uses the same names.
|
|
50
|
+
if (algorithm !== "sha256" && algorithm !== "sha512") {
|
|
51
|
+
throw new Error(`Unsupported SSHSIG hash algorithm ${JSON.stringify(algorithm)}`);
|
|
52
|
+
}
|
|
53
|
+
return crypto_1.default.createHash(algorithm).update(data).digest();
|
|
54
|
+
}
|
|
55
|
+
function ed25519PublicKey(rawKey) {
|
|
56
|
+
if (rawKey.length !== 32) {
|
|
57
|
+
throw new Error(`Expected a 32 byte ed25519 key, was ${rawKey.length}`);
|
|
58
|
+
}
|
|
59
|
+
return crypto_1.default.createPublicKey({
|
|
60
|
+
key: Buffer.concat([ED25519_SPKI_PREFIX, rawKey]),
|
|
61
|
+
format: "der",
|
|
62
|
+
type: "spki",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/** Verifies an SSHSIG signature over a message, and that it was made for the given namespace.
|
|
66
|
+
Returns the signing public key and its fingerprint, in the forms ssh-keygen reports them.
|
|
67
|
+
Throws if it does not verify, or is not for this namespace. */
|
|
68
|
+
function verifySSHSIG(config) {
|
|
69
|
+
let { signature, message, namespace } = config;
|
|
70
|
+
let body = signature.split("\n").filter(line => line && !line.startsWith("-----")).join("");
|
|
71
|
+
let blob = Buffer.from(body, "base64");
|
|
72
|
+
if (blob.subarray(0, MAGIC.length).toString() !== MAGIC) {
|
|
73
|
+
throw new Error(`Expected an ${MAGIC} signature, started with ${JSON.stringify(blob.subarray(0, MAGIC.length).toString())}`);
|
|
74
|
+
}
|
|
75
|
+
let reader = new Reader(blob.subarray(MAGIC.length));
|
|
76
|
+
let version = reader.u32();
|
|
77
|
+
if (version !== 1) {
|
|
78
|
+
throw new Error(`Expected SSHSIG version 1, was ${version}`);
|
|
79
|
+
}
|
|
80
|
+
let publicKeyBlob = reader.string();
|
|
81
|
+
let signatureNamespace = reader.string().toString();
|
|
82
|
+
reader.string(); // reserved
|
|
83
|
+
let hashAlgorithm = reader.string().toString();
|
|
84
|
+
let signatureBlob = reader.string();
|
|
85
|
+
if (signatureNamespace !== namespace) {
|
|
86
|
+
throw new Error(`Signature is for namespace ${JSON.stringify(signatureNamespace)}, expected ${JSON.stringify(namespace)}`);
|
|
87
|
+
}
|
|
88
|
+
let publicKeyReader = new Reader(publicKeyBlob);
|
|
89
|
+
let keyType = publicKeyReader.string().toString();
|
|
90
|
+
let rawKey = publicKeyReader.string();
|
|
91
|
+
let application = publicKeyReader.remaining() ? publicKeyReader.string() : Buffer.alloc(0);
|
|
92
|
+
let signatureReader = new Reader(signatureBlob);
|
|
93
|
+
let signatureType = signatureReader.string().toString();
|
|
94
|
+
let rawSignature = signatureReader.string();
|
|
95
|
+
if (signatureType !== keyType) {
|
|
96
|
+
throw new Error(`Signature type ${signatureType} does not match key type ${keyType}`);
|
|
97
|
+
}
|
|
98
|
+
// The bytes the signature is over: the magic, the namespace, the reserved field, the hash
|
|
99
|
+
// algorithm, and the hash of the message. Never the message itself, so a huge file still signs
|
|
100
|
+
// a fixed size blob.
|
|
101
|
+
let signed = Buffer.concat([
|
|
102
|
+
Buffer.from(MAGIC),
|
|
103
|
+
sshString(Buffer.from(signatureNamespace)),
|
|
104
|
+
sshString(Buffer.alloc(0)),
|
|
105
|
+
sshString(Buffer.from(hashAlgorithm)),
|
|
106
|
+
sshString(hash(hashAlgorithm, message)),
|
|
107
|
+
]);
|
|
108
|
+
let toVerify;
|
|
109
|
+
if (keyType === "ssh-ed25519") {
|
|
110
|
+
toVerify = signed;
|
|
111
|
+
}
|
|
112
|
+
else if (keyType === "sk-ssh-ed25519@openssh.com") {
|
|
113
|
+
// A hardware key signs over what the authenticator saw, not the blob directly: the hash of
|
|
114
|
+
// the application it is scoped to, the flags and counter it returned, and the hash of the
|
|
115
|
+
// blob. Reconstructing that is the whole difference from a plain ed25519 signature.
|
|
116
|
+
let flags = signatureReader.u8();
|
|
117
|
+
let counter = signatureReader.u32();
|
|
118
|
+
let counterBytes = Buffer.alloc(4);
|
|
119
|
+
counterBytes.writeUInt32BE(counter);
|
|
120
|
+
toVerify = Buffer.concat([
|
|
121
|
+
hash("sha256", application),
|
|
122
|
+
Buffer.from([flags]),
|
|
123
|
+
counterBytes,
|
|
124
|
+
hash("sha256", signed),
|
|
125
|
+
]);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
throw new Error(`Unsupported SSHSIG key type ${JSON.stringify(keyType)}`);
|
|
129
|
+
}
|
|
130
|
+
if (!crypto_1.default.verify(null, toVerify, ed25519PublicKey(rawKey), rawSignature)) {
|
|
131
|
+
throw new Error(`The SSHSIG signature does not verify`);
|
|
132
|
+
}
|
|
133
|
+
let fingerprint = "SHA256:" + crypto_1.default.createHash("sha256").update(publicKeyBlob).digest("base64").replace(/=+$/, "");
|
|
134
|
+
return { publicKey: `${keyType} ${publicKeyBlob.toString("base64")}`, fingerprint };
|
|
135
|
+
}
|
|
136
|
+
exports.verifySSHSIG = verifySSHSIG;
|
|
137
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3Noc2lnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic3Noc2lnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLG9EQUE0QjtBQUU1QixtR0FBbUc7QUFDbkcsOEZBQThGO0FBQzlGLHFDQUFxQztBQUNyQyxFQUFFO0FBQ0YsNkZBQTZGO0FBQzdGLG1HQUFtRztBQUNuRyxvRUFBb0U7QUFFcEUsTUFBTSxLQUFLLEdBQUcsUUFBUSxDQUFDO0FBQ3ZCLGdHQUFnRztBQUNoRyxNQUFNLG1CQUFtQixHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsMEJBQTBCLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFFM0UsbUVBQW1FO0FBQ25FLE1BQU0sTUFBTTtJQUVSLFlBQW9CLE1BQWM7UUFBZCxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBRDFCLFdBQU0sR0FBRyxDQUFDLENBQUM7SUFDbUIsQ0FBQztJQUN2QyxFQUFFO1FBQ0UsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztJQUNoRCxDQUFDO0lBQ0QsR0FBRztRQUNDLElBQUksS0FBSyxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQztRQUNqQixPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0lBQ0QsTUFBTTtRQUNGLElBQUksTUFBTSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUN4QixJQUFJLEtBQUssR0FBRyxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDLENBQUM7UUFDcEUsSUFBSSxDQUFDLE1BQU0sSUFBSSxNQUFNLENBQUM7UUFDdEIsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUNE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LE1BQU0sSUFBSSxLQUFLLENBQUMsK0JBQStCLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFRCxJQUFJLENBQUMsZ0JBQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsRUFBRSxZQUFZLENBQUMsRUFBRSxDQUFDO1FBQ3pFLE1BQU0sSUFBSSxLQUFLLENBQUMsc0NBQXNDLENBQUMsQ0FBQztJQUM1RCxDQUFDO0lBRUQsSUFBSSxXQUFXLEdBQUcsU0FBUyxHQUFHLGdCQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsT0FBTyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztJQUNwSCxPQUFPLEVBQUUsU0FBUyxFQUFFLEdBQUcsT0FBTyxJQUFJLGFBQWEsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUN4RixDQUFDO0FBMUVELG9DQTBFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjcnlwdG8gZnJvbSBcImNyeXB0b1wiO1xuXG4vLyBWZXJpZmllcyBhbiBTU0hTSUcgc2lnbmF0dXJlICh0aGUgZm9ybWF0IHNzaC1rZXlnZW4gLVkgc2lnbiBwcm9kdWNlcykgaW4gcHJvY2Vzcywgc28gbm90aGluZyBoYXNcbi8vIHRvIHNoZWxsIG91dCB0byBzc2gta2V5Z2VuIHRvIGNoZWNrIG9uZS4gVGhlIHdpcmUgZm9ybWF0IGlzIFBST1RPQ09MLnNzaHNpZywgYW5kIHRoZSBhY3R1YWxcbi8vIGNoZWNrIGlzIG9uZSBlZDI1NTE5IHZlcmlmaWNhdGlvbi5cbi8vXG4vLyBCb3RoIGVkMjU1MTkgYW5kIHRoZSBoYXJkd2FyZSBzay1lZDI1NTE5IHZhcmlhbnQgYXJlIGhhbmRsZWQsIHNpbmNlIHNpZ25maWxlcyBzaWducyB3aXRoIGFcbi8vIGhhcmR3YXJlIGVkMjU1MTktc2sga2V5LiBUaGUgc2sgdmFyaWFudCBzaWducyBhIGxpdHRsZSBtb3JlIHRoYW4gdGhlIG1lc3NhZ2UgLSB0aGUgYXV0aGVudGljYXRvclxuLy8gZmxhZ3MgYW5kIGNvdW50ZXIgZ28gaW4gdG9vIC0gYnV0IGl0IGlzIHN0aWxsIGVkMjU1MTkgdW5kZXJuZWF0aC5cblxuY29uc3QgTUFHSUMgPSBcIlNTSFNJR1wiO1xuLy8gQW4gZWQyNTUxOSBwdWJsaWMga2V5IGFzIGEgREVSIFNQS0kgaXMgdGhpcyBmaXhlZCAxMiBieXRlIGhlYWRlciBmb2xsb3dlZCBieSB0aGUgMzIgYnl0ZSBrZXkuXG5jb25zdCBFRDI1NTE5X1NQS0lfUFJFRklYID0gQnVmZmVyLmZyb20oXCIzMDJhMzAwNTA2MDMyYjY1NzAwMzIxMDBcIiwgXCJoZXhcIik7XG5cbi8qKiBSZWFkcyB0aGUgbGVuZ3RoIHByZWZpeGVkIGZpZWxkcyBTU0ggd2lyZSBmb3JtYXQgaXMgbWFkZSBvZi4gKi9cbmNsYXNzIFJlYWRlciB7XG4gICAgcHJpdmF0ZSBvZmZzZXQgPSAwO1xuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgYnVmZmVyOiBCdWZmZXIpIHsgfVxuICAgIHU4KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5idWZmZXIucmVhZFVJbnQ4KHRoaXMub2Zmc2V0KyspO1xuICAgIH1cbiAgICB1MzIoKSB7XG4gICAgICAgIGxldCB2YWx1ZSA9IHRoaXMuYnVmZmVyLnJlYWRVSW50MzJCRSh0aGlzLm9mZnNldCk7XG4gICAgICAgIHRoaXMub2Zmc2V0ICs9IDQ7XG4gICAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gICAgc3RyaW5nKCkge1xuICAgICAgICBsZXQgbGVuZ3RoID0gdGhpcy51MzIoKTtcbiAgICAgICAgbGV0IHZhbHVlID0gdGhpcy5idWZmZXIuc3ViYXJyYXkodGhpcy5vZmZzZXQsIHRoaXMub2Zmc2V0ICsgbGVuZ3RoKTtcbiAgICAgICAgdGhpcy5vZmZzZXQgKz0gbGVuZ3RoO1xuICAgICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuICAgIHJlbWFpbmluZygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYnVmZmVyLmxlbmd0aCAtIHRoaXMub2Zmc2V0O1xuICAgIH1cbn1cblxuLyoqIE9uZSBsZW5ndGggcHJlZml4ZWQgZmllbGQsIHRoZSB3YXkgU1NIIHdyaXRlcyB0aGVtLiAqL1xuZnVuY3Rpb24gc3NoU3RyaW5nKGJ5dGVzOiBCdWZmZXIpIHtcbiAgICBsZXQgbGVuZ3RoID0gQnVmZmVyLmFsbG9jKDQpO1xuICAgIGxlbmd0aC53cml0ZVVJbnQzMkJFKGJ5dGVzLmxlbmd0aCk7XG4gICAgcmV0dXJuIEJ1ZmZlci5jb25jYXQoW2xlbmd0aCwgYnl0ZXNdKTtcbn1cblxuZnVuY3Rpb24gaGFzaChhbGdvcml0aG06IHN0cmluZywgZGF0YTogQnVmZmVyKSB7XG4gICAgLy8gU1NIU0lHIG5hbWVzIHNoYTI1NiBvciBzaGE1MTI7IG5vZGUgdXNlcyB0aGUgc2FtZSBuYW1lcy5cbiAgICBpZiAoYWxnb3JpdGhtICE9PSBcInNoYTI1NlwiICYmIGFsZ29yaXRobSAhPT0gXCJzaGE1MTJcIikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIFNTSFNJRyBoYXNoIGFsZ29yaXRobSAke0pTT04uc3RyaW5naWZ5KGFsZ29yaXRobSl9YCk7XG4gICAgfVxuICAgIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaChhbGdvcml0aG0pLnVwZGF0ZShkYXRhKS5kaWdlc3QoKTtcbn1cblxuZnVuY3Rpb24gZWQyNTUxOVB1YmxpY0tleShyYXdLZXk6IEJ1ZmZlcikge1xuICAgIGlmIChyYXdLZXkubGVuZ3RoICE9PSAzMikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgMzIgYnl0ZSBlZDI1NTE5IGtleSwgd2FzICR7cmF3S2V5Lmxlbmd0aH1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGNyeXB0by5jcmVhdGVQdWJsaWNLZXkoe1xuICAgICAgICBrZXk6IEJ1ZmZlci5jb25jYXQoW0VEMjU1MTlfU1BLSV9QUkVGSVgsIHJhd0tleV0pLFxuICAgICAgICBmb3JtYXQ6IFwiZGVyXCIsXG4gICAgICAgIHR5cGU6IFwic3BraVwiLFxuICAgIH0pO1xufVxuXG4vKiogVmVyaWZpZXMgYW4gU1NIU0lHIHNpZ25hdHVyZSBvdmVyIGEgbWVzc2FnZSwgYW5kIHRoYXQgaXQgd2FzIG1hZGUgZm9yIHRoZSBnaXZlbiBuYW1lc3BhY2UuXG4gICAgUmV0dXJucyB0aGUgc2lnbmluZyBwdWJsaWMga2V5IGFuZCBpdHMgZmluZ2VycHJpbnQsIGluIHRoZSBmb3JtcyBzc2gta2V5Z2VuIHJlcG9ydHMgdGhlbS5cbiAgICBUaHJvd3MgaWYgaXQgZG9lcyBub3QgdmVyaWZ5LCBvciBpcyBub3QgZm9yIHRoaXMgbmFtZXNwYWNlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZlcmlmeVNTSFNJRyhjb25maWc6IHsgc2lnbmF0dXJlOiBzdHJpbmc7IG1lc3NhZ2U6IEJ1ZmZlcjsgbmFtZXNwYWNlOiBzdHJpbmcgfSkge1xuICAgIGxldCB7IHNpZ25hdHVyZSwgbWVzc2FnZSwgbmFtZXNwYWNlIH0gPSBjb25maWc7XG5cbiAgICBsZXQgYm9keSA9IHNpZ25hdHVyZS5zcGxpdChcIlxcblwiKS5maWx0ZXIobGluZSA9PiBsaW5lICYmICFsaW5lLnN0YXJ0c1dpdGgoXCItLS0tLVwiKSkuam9pbihcIlwiKTtcbiAgICBsZXQgYmxvYiA9IEJ1ZmZlci5mcm9tKGJvZHksIFwiYmFzZTY0XCIpO1xuICAgIGlmIChibG9iLnN1YmFycmF5KDAsIE1BR0lDLmxlbmd0aCkudG9TdHJpbmcoKSAhPT0gTUFHSUMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhbiAke01BR0lDfSBzaWduYXR1cmUsIHN0YXJ0ZWQgd2l0aCAke0pTT04uc3RyaW5naWZ5KGJsb2Iuc3ViYXJyYXkoMCwgTUFHSUMubGVuZ3RoKS50b1N0cmluZygpKX1gKTtcbiAgICB9XG5cbiAgICBsZXQgcmVhZGVyID0gbmV3IFJlYWRlcihibG9iLnN1YmFycmF5KE1BR0lDLmxlbmd0aCkpO1xuICAgIGxldCB2ZXJzaW9uID0gcmVhZGVyLnUzMigpO1xuICAgIGlmICh2ZXJzaW9uICE9PSAxKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgU1NIU0lHIHZlcnNpb24gMSwgd2FzICR7dmVyc2lvbn1gKTtcbiAgICB9XG4gICAgbGV0IHB1YmxpY0tleUJsb2IgPSByZWFkZXIuc3RyaW5nKCk7XG4gICAgbGV0IHNpZ25hdHVyZU5hbWVzcGFjZSA9IHJlYWRlci5zdHJpbmcoKS50b1N0cmluZygpO1xuICAgIHJlYWRlci5zdHJpbmcoKTsgLy8gcmVzZXJ2ZWRcbiAgICBsZXQgaGFzaEFsZ29yaXRobSA9IHJlYWRlci5zdHJpbmcoKS50b1N0cmluZygpO1xuICAgIGxldCBzaWduYXR1cmVCbG9iID0gcmVhZGVyLnN0cmluZygpO1xuXG4gICAgaWYgKHNpZ25hdHVyZU5hbWVzcGFjZSAhPT0gbmFtZXNwYWNlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgU2lnbmF0dXJlIGlzIGZvciBuYW1lc3BhY2UgJHtKU09OLnN0cmluZ2lmeShzaWduYXR1cmVOYW1lc3BhY2UpfSwgZXhwZWN0ZWQgJHtKU09OLnN0cmluZ2lmeShuYW1lc3BhY2UpfWApO1xuICAgIH1cblxuICAgIGxldCBwdWJsaWNLZXlSZWFkZXIgPSBuZXcgUmVhZGVyKHB1YmxpY0tleUJsb2IpO1xuICAgIGxldCBrZXlUeXBlID0gcHVibGljS2V5UmVhZGVyLnN0cmluZygpLnRvU3RyaW5nKCk7XG4gICAgbGV0IHJhd0tleSA9IHB1YmxpY0tleVJlYWRlci5zdHJpbmcoKTtcbiAgICBsZXQgYXBwbGljYXRpb24gPSBwdWJsaWNLZXlSZWFkZXIucmVtYWluaW5nKCkgPyBwdWJsaWNLZXlSZWFkZXIuc3RyaW5nKCkgOiBCdWZmZXIuYWxsb2MoMCk7XG5cbiAgICBsZXQgc2lnbmF0dXJlUmVhZGVyID0gbmV3IFJlYWRlcihzaWduYXR1cmVCbG9iKTtcbiAgICBsZXQgc2lnbmF0dXJlVHlwZSA9IHNpZ25hdHVyZVJlYWRlci5zdHJpbmcoKS50b1N0cmluZygpO1xuICAgIGxldCByYXdTaWduYXR1cmUgPSBzaWduYXR1cmVSZWFkZXIuc3RyaW5nKCk7XG4gICAgaWYgKHNpZ25hdHVyZVR5cGUgIT09IGtleVR5cGUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTaWduYXR1cmUgdHlwZSAke3NpZ25hdHVyZVR5cGV9IGRvZXMgbm90IG1hdGNoIGtleSB0eXBlICR7a2V5VHlwZX1gKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgYnl0ZXMgdGhlIHNpZ25hdHVyZSBpcyBvdmVyOiB0aGUgbWFnaWMsIHRoZSBuYW1lc3BhY2UsIHRoZSByZXNlcnZlZCBmaWVsZCwgdGhlIGhhc2hcbiAgICAvLyBhbGdvcml0aG0sIGFuZCB0aGUgaGFzaCBvZiB0aGUgbWVzc2FnZS4gTmV2ZXIgdGhlIG1lc3NhZ2UgaXRzZWxmLCBzbyBhIGh1Z2UgZmlsZSBzdGlsbCBzaWduc1xuICAgIC8vIGEgZml4ZWQgc2l6ZSBibG9iLlxuICAgIGxldCBzaWduZWQgPSBCdWZmZXIuY29uY2F0KFtcbiAgICAgICAgQnVmZmVyLmZyb20oTUFHSUMpLFxuICAgICAgICBzc2hTdHJpbmcoQnVmZmVyLmZyb20oc2lnbmF0dXJlTmFtZXNwYWNlKSksXG4gICAgICAgIHNzaFN0cmluZyhCdWZmZXIuYWxsb2MoMCkpLFxuICAgICAgICBzc2hTdHJpbmcoQnVmZmVyLmZyb20oaGFzaEFsZ29yaXRobSkpLFxuICAgICAgICBzc2hTdHJpbmcoaGFzaChoYXNoQWxnb3JpdGhtLCBtZXNzYWdlKSksXG4gICAgXSk7XG5cbiAgICBsZXQgdG9WZXJpZnk6IEJ1ZmZlcjtcbiAgICBpZiAoa2V5VHlwZSA9PT0gXCJzc2gtZWQyNTUxOVwiKSB7XG4gICAgICAgIHRvVmVyaWZ5ID0gc2lnbmVkO1xuICAgIH0gZWxzZSBpZiAoa2V5VHlwZSA9PT0gXCJzay1zc2gtZWQyNTUxOUBvcGVuc3NoLmNvbVwiKSB7XG4gICAgICAgIC8vIEEgaGFyZHdhcmUga2V5IHNpZ25zIG92ZXIgd2hhdCB0aGUgYXV0aGVudGljYXRvciBzYXcsIG5vdCB0aGUgYmxvYiBkaXJlY3RseTogdGhlIGhhc2ggb2ZcbiAgICAgICAgLy8gdGhlIGFwcGxpY2F0aW9uIGl0IGlzIHNjb3BlZCB0bywgdGhlIGZsYWdzIGFuZCBjb3VudGVyIGl0IHJldHVybmVkLCBhbmQgdGhlIGhhc2ggb2YgdGhlXG4gICAgICAgIC8vIGJsb2IuIFJlY29uc3RydWN0aW5nIHRoYXQgaXMgdGhlIHdob2xlIGRpZmZlcmVuY2UgZnJvbSBhIHBsYWluIGVkMjU1MTkgc2lnbmF0dXJlLlxuICAgICAgICBsZXQgZmxhZ3MgPSBzaWduYXR1cmVSZWFkZXIudTgoKTtcbiAgICAgICAgbGV0IGNvdW50ZXIgPSBzaWduYXR1cmVSZWFkZXIudTMyKCk7XG4gICAgICAgIGxldCBjb3VudGVyQnl0ZXMgPSBCdWZmZXIuYWxsb2MoNCk7XG4gICAgICAgIGNvdW50ZXJCeXRlcy53cml0ZVVJbnQzMkJFKGNvdW50ZXIpO1xuICAgICAgICB0b1ZlcmlmeSA9IEJ1ZmZlci5jb25jYXQoW1xuICAgICAgICAgICAgaGFzaChcInNoYTI1NlwiLCBhcHBsaWNhdGlvbiksXG4gICAgICAgICAgICBCdWZmZXIuZnJvbShbZmxhZ3NdKSxcbiAgICAgICAgICAgIGNvdW50ZXJCeXRlcyxcbiAgICAgICAgICAgIGhhc2goXCJzaGEyNTZcIiwgc2lnbmVkKSxcbiAgICAgICAgXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBTU0hTSUcga2V5IHR5cGUgJHtKU09OLnN0cmluZ2lmeShrZXlUeXBlKX1gKTtcbiAgICB9XG5cbiAgICBpZiAoIWNyeXB0by52ZXJpZnkobnVsbCwgdG9WZXJpZnksIGVkMjU1MTlQdWJsaWNLZXkocmF3S2V5KSwgcmF3U2lnbmF0dXJlKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSBTU0hTSUcgc2lnbmF0dXJlIGRvZXMgbm90IHZlcmlmeWApO1xuICAgIH1cblxuICAgIGxldCBmaW5nZXJwcmludCA9IFwiU0hBMjU2OlwiICsgY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHB1YmxpY0tleUJsb2IpLmRpZ2VzdChcImJhc2U2NFwiKS5yZXBsYWNlKC89KyQvLCBcIlwiKTtcbiAgICByZXR1cm4geyBwdWJsaWNLZXk6IGAke2tleVR5cGV9ICR7cHVibGljS2V5QmxvYi50b1N0cmluZyhcImJhc2U2NFwiKX1gLCBmaW5nZXJwcmludCB9O1xufVxuIl19
|
|
138
|
+
/* _JS_SOURCE_HASH = "7806dd475f184dc11a03815e46fb4e4e3f975c3a65ac16bd167b7b6936c9149b"; */
|