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,11 +3,10 @@ import os from "os";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { resolveKeysRepo } from "../authorizedKeys/keysRepo";
|
|
5
5
|
import { revokeRepo, syncRepoFiles } from "../authorizedKeys/daemon/repoFiles";
|
|
6
|
-
import {
|
|
7
|
-
import { newRevocationId, pairKey, readRevocationFiles, readUnrevokes } from "../authorizedKeys/daemon/revocation";
|
|
6
|
+
import { newRevocationId } from "../authorizedKeys/daemon/revocation";
|
|
8
7
|
import { runGit, syncRepo } from "../authorizedKeys/daemon/git";
|
|
9
8
|
import { ensureRevokeKey } from "../authorizedKeys/daemon/repoFiles";
|
|
10
|
-
import { readSignedRepo } from "../authorizedKeys/daemon/trust";
|
|
9
|
+
import { isIdentityFrozen, isPairRevoked, isPairUnrevoked, noteRevocation, readSignedRepo } from "../authorizedKeys/daemon/trust";
|
|
11
10
|
import { revokeRepoPath, revokeRepoURL } from "../authorizedKeys/revokeSource";
|
|
12
11
|
import { notify } from "../authorizedKeys/daemon/notify";
|
|
13
12
|
import { areDiscordNotificationsConfigured, configureDiscordNotifications, DEFAULT_WEBHOOK_FILE_PATH } from "../notifications/discord";
|
|
@@ -81,8 +80,8 @@ export async function getMachines(repoPath?: string): Promise<MachineState[]> {
|
|
|
81
80
|
read - an unsigned machines/*.json is not evidence of anything, so readSignedRepo has already
|
|
82
81
|
left it out. */
|
|
83
82
|
async function readTrustedMachines() {
|
|
84
|
-
let { repoPath } = await keysRepo();
|
|
85
|
-
let { files } = await readSignedRepo(repoPath);
|
|
83
|
+
let { repoPath, sourceURL } = await keysRepo();
|
|
84
|
+
let { files } = await readSignedRepo({ repoPath, sourceURL });
|
|
86
85
|
let machines: MachineState[] = [];
|
|
87
86
|
for (let [filePath, contents] of files) {
|
|
88
87
|
let name = filePath.startsWith(`${MACHINES_DIR}/`) && filePath.slice(MACHINES_DIR.length + 1) || "";
|
|
@@ -237,43 +236,17 @@ async function readMachines(repoPath: string) {
|
|
|
237
236
|
|
|
238
237
|
let lastRevokeSync = 0;
|
|
239
238
|
|
|
240
|
-
/**
|
|
241
|
-
|
|
242
|
-
|
|
239
|
+
/** Pulls the keys repo and its revoke repo, at most once a REVOKE_SYNC_INTERVAL, because this is
|
|
240
|
+
asked per request. Both, since either changing changes the answer: the keys repo carries the
|
|
241
|
+
machines and unrevokes, the revoke repo carries the revocations. A sync that fails leaves the
|
|
242
|
+
checkouts we already have. */
|
|
243
243
|
async function syncRevocations(sourceURL: string) {
|
|
244
244
|
if (Date.now() - lastRevokeSync < REVOKE_SYNC_INTERVAL) {
|
|
245
245
|
return;
|
|
246
246
|
}
|
|
247
247
|
lastRevokeSync = Date.now();
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
} catch (e) {
|
|
251
|
-
console.log(`Could not read ${revokeRepoURL(sourceURL)}, using the revocations already here. ${e}`);
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
/** Machine revocations, read out of the revoke repo the same way key revocations are. */
|
|
256
|
-
async function readMachineRevocations(sourceURL: string) {
|
|
257
|
-
let repo = revokeRepo(sourceURL);
|
|
258
|
-
let revocations: { revocationId: string; machineId: string; ip: string }[] = [];
|
|
259
|
-
for (let name of await listRepoDir(repo, REVOCATIONS_DIR)) {
|
|
260
|
-
if (!name.endsWith(".json")) {
|
|
261
|
-
continue;
|
|
262
|
-
}
|
|
263
|
-
try {
|
|
264
|
-
let parsed = JSON.parse(await readRepoFile(repo, path.join(REVOCATIONS_DIR, name)) || "");
|
|
265
|
-
if (parsed.machineId) {
|
|
266
|
-
revocations.push({
|
|
267
|
-
revocationId: parsed.revocationId || name.replace(/\.json$/, ""),
|
|
268
|
-
machineId: parsed.machineId,
|
|
269
|
-
ip: parsed.ip || "",
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
} catch (e) {
|
|
273
|
-
console.log(`Ignoring unreadable revocation ${name}. ${e}`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
return revocations;
|
|
248
|
+
await syncRepo(sourceURL).catch(e => console.log(`Could not sync ${sourceURL}, using the checkout already here. ${e}`));
|
|
249
|
+
await syncRepoFiles(revokeRepo(sourceURL)).catch(e => console.log(`Could not sync ${revokeRepoURL(sourceURL)}, using the revocations already absorbed. ${e}`));
|
|
277
250
|
}
|
|
278
251
|
|
|
279
252
|
/** What to run to trust a machine that has just been refused.
|
|
@@ -284,7 +257,7 @@ async function readMachineRevocations(sourceURL: string) {
|
|
|
284
257
|
the machine that owns the repo, so telling them costs nothing. */
|
|
285
258
|
export function addMachineCommand(config: { machineId: string; ip: string; domain?: string }) {
|
|
286
259
|
let { machineId, ip, domain } = config;
|
|
287
|
-
return `To trust
|
|
260
|
+
return `To trust ${machineId}, run: yarn addmachine ${domain || "<domain>"} ${machineId} ${ip} git`;
|
|
288
261
|
}
|
|
289
262
|
|
|
290
263
|
/** Sends the one notification this file is allowed to send, when it can.
|
|
@@ -342,19 +315,20 @@ async function recordMachineRevocation(config: {
|
|
|
342
315
|
console.log(`Could not push the revocation of ${machineId} from ${ip}. ${(push.stdout + push.stderr).trim()}`);
|
|
343
316
|
return;
|
|
344
317
|
}
|
|
318
|
+
noteRevocation(revocationId, machineId, ip);
|
|
345
319
|
console.log(`Revoked ${machineId} from ${ip}, ${revocationId}`);
|
|
346
320
|
|
|
347
321
|
// Said by whoever wrote the revocation, once, the same as for an ssh key. Machines that only
|
|
348
322
|
// read it later say nothing, or one event would be reported by every machine that saw it.
|
|
349
323
|
await notifyBestEffort(
|
|
350
324
|
`SUSPICIOUS IP ${ip} FROZE MACHINE ${machineId}`,
|
|
351
|
-
`
|
|
352
|
-
+ ` from.
|
|
353
|
-
+ ` or
|
|
354
|
-
+ `\n\
|
|
325
|
+
`Trusted machine ${machineId} talked to us from ${ip}, an address ${machineId} is not`
|
|
326
|
+
+ ` allowed from. The caller proved possession of ${machineId}'s key, so either someone`
|
|
327
|
+
+ ` else has a copy of the key, or the machine's address changed.`
|
|
328
|
+
+ `\n\nMachine ${machineId} is frozen everywhere now, and nothing accepts calls from ${machineId}.`
|
|
355
329
|
+ `\n\nIf this was an attack, remove \`machines/${machineId}.json\` from \`${sourceURL}\` now.`
|
|
356
|
-
+ `\nIf
|
|
357
|
-
+ `
|
|
330
|
+
+ `\nIf the new address is legitimate, run \`yarn unrevoke git\` in \`${sourceURL}\`. The`
|
|
331
|
+
+ ` unrevoke allows ${machineId} from ${ip}, and takes effect as each machine picks it up.`
|
|
358
332
|
+ `\n\nmachine: \`${machineId}\``
|
|
359
333
|
+ `\nfrozen by: \`${hostLabel}\``
|
|
360
334
|
);
|
|
@@ -396,35 +370,15 @@ export async function isMachineAccepted(config: {
|
|
|
396
370
|
return { verdict: { accepted: true, reason: "" }, froze: false };
|
|
397
371
|
}
|
|
398
372
|
let { sourceURL } = await keysRepo();
|
|
399
|
-
|
|
373
|
+
await syncRevocations(sourceURL);
|
|
374
|
+
// The list has revocations already applied - readSignedRepo drops frozen machines - so a
|
|
375
|
+
// machine in it is trusted, and a machine missing from it is either unknown or frozen.
|
|
400
376
|
let machine = (await getTrustedMachines()).find(entry => entry.machineId === machineId);
|
|
401
377
|
if (!machine) {
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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;
|
|
378
|
+
if (isIdentityFrozen(machineId)) {
|
|
379
|
+
return { verdict: { accepted: false, reason: `Machine ${machineId} is frozen, having been used from an unapproved address.` }, froze: false };
|
|
418
380
|
}
|
|
419
|
-
|
|
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
|
-
};
|
|
381
|
+
return { verdict: { accepted: false, reason: `Machine ${machineId} is not trusted. ${addMachineCommand({ machineId, ip, domain })}` }, froze: false };
|
|
428
382
|
}
|
|
429
383
|
|
|
430
384
|
if (machine.ips.includes(ip)) {
|
|
@@ -433,14 +387,11 @@ export async function isMachineAccepted(config: {
|
|
|
433
387
|
|
|
434
388
|
// Listed, but talking to us from somewhere it should not be. Recorded once for this machine
|
|
435
389
|
// and address, so being talked to repeatedly does not write repeatedly.
|
|
436
|
-
|
|
437
|
-
let alreadyRecorded = revocations.some(revocation =>
|
|
438
|
-
pairKey({ fingerprint: revocation.machineId, ip: revocation.ip }) === pair);
|
|
439
|
-
if (!alreadyRecorded && !allowedAgain(pair)) {
|
|
390
|
+
if (!isPairRevoked(machineId, ip) && !isPairUnrevoked(machineId, ip)) {
|
|
440
391
|
await recordMachineRevocation({ sourceURL, machineId, ip, hostLabel: os.hostname() });
|
|
441
|
-
return { verdict: { accepted: false, reason: `
|
|
392
|
+
return { verdict: { accepted: false, reason: `Machine ${machineId} is not allowed from ${ip}, and is now frozen everywhere.` }, froze: true };
|
|
442
393
|
}
|
|
443
|
-
return { verdict: { accepted: false, reason: `
|
|
394
|
+
return { verdict: { accepted: false, reason: `Machine ${machineId} is not allowed from ${ip}.` }, froze: false };
|
|
444
395
|
};
|
|
445
396
|
|
|
446
397
|
let { verdict, froze } = await evaluate();
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DEV_listIdentityDomains, getOwnMachineId, loadIdentityCA } from "../../misc/https/certs";
|
|
2
|
+
|
|
3
|
+
// Prints this machine's id under every domain it has an identity for. A machine has a different
|
|
4
|
+
// identity, and so a different machine id, under every domain it runs under.
|
|
5
|
+
async function main() {
|
|
6
|
+
let domains = DEV_listIdentityDomains();
|
|
7
|
+
if (!domains.length) {
|
|
8
|
+
throw new Error(`This machine has no identities`);
|
|
9
|
+
}
|
|
10
|
+
for (let domain of domains) {
|
|
11
|
+
await loadIdentityCA(domain);
|
|
12
|
+
console.log(`${domain} ${getOwnMachineId(domain)}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
main().catch(e => {
|
|
17
|
+
console.error(`${e}`);
|
|
18
|
+
process.exitCode = 1;
|
|
19
|
+
}).finally(() => process.exit());
|
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
6
|
-
//exports.
|
|
6
|
+
//exports.signRepo = exports.DEFAULT_KEY_PATH = exports.DEFAULT_KEY_TYPE = void 0;
|
|
7
7
|
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
8
|
const os_1 = __importDefault(require("os"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
@@ -11,21 +11,14 @@ const runPromise_1 = require("socket-function/src/runPromise");
|
|
|
11
11
|
const paths_1 = require("../helpers/paths");
|
|
12
12
|
const spawn_1 = require("../helpers/spawn");
|
|
13
13
|
const manifest_1 = require("./manifest");
|
|
14
|
+
const sshsig_1 = require("./sshsig");
|
|
14
15
|
const unrevoke_1 = require("../authorizedKeys/unrevoke");
|
|
15
|
-
const keysRepo_1 = require("../authorizedKeys/keysRepo");
|
|
16
16
|
const authorizedKeys_1 = require("../authorizedKeys/authorizedKeys");
|
|
17
17
|
// A hardware backed key is the entire point. A key sitting on disk is compromised the moment the
|
|
18
18
|
// machine is, and then the signature proves nothing, so this is what we make when asked to make one.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const GIT_KEYWORD = "git";
|
|
22
|
-
const COMMIT_MESSAGE = "deploying signed files";
|
|
19
|
+
exports.DEFAULT_KEY_TYPE = "ed25519-sk";
|
|
20
|
+
exports.DEFAULT_KEY_PATH = "~/.ssh/signfiles_ed25519_sk";
|
|
23
21
|
const MAX_ERROR_BODY_LENGTH = 500;
|
|
24
|
-
const USAGE = `Usage: yarn signfiles [signing-key] [${GIT_KEYWORD}]
|
|
25
|
-
|
|
26
|
-
Signs the files of the repo in the current directory. With no key, a hardware backed
|
|
27
|
-
${DEFAULT_KEY_TYPE} key at ${DEFAULT_KEY_PATH} is used, and created if it does not exist.
|
|
28
|
-
Pass ${GIT_KEYWORD} to also commit and push the result.`;
|
|
29
22
|
/** runPromise takes a command line rather than an argument list, so anything holding a path has to
|
|
30
23
|
survive the shell. Double quotes work on both cmd and posix shells. */
|
|
31
24
|
function quote(value) {
|
|
@@ -42,14 +35,14 @@ async function pathExists(filePath) {
|
|
|
42
35
|
}
|
|
43
36
|
/** Creating this needs the security key plugged in, and a touch. */
|
|
44
37
|
async function ensureDefaultKey() {
|
|
45
|
-
let keyPath = (0, paths_1.expandHome)(DEFAULT_KEY_PATH);
|
|
38
|
+
let keyPath = (0, paths_1.expandHome)(exports.DEFAULT_KEY_PATH);
|
|
46
39
|
if (await pathExists(keyPath)) {
|
|
47
40
|
return keyPath;
|
|
48
41
|
}
|
|
49
|
-
console.log(`No signing key at ${keyPath}, creating an ${DEFAULT_KEY_TYPE} one.`);
|
|
42
|
+
console.log(`No signing key at ${keyPath}, creating an ${exports.DEFAULT_KEY_TYPE} one.`);
|
|
50
43
|
console.log(`Plug your security key in - you will be asked to touch it.`);
|
|
51
44
|
await promises_1.default.mkdir(path_1.default.dirname(keyPath), { recursive: true, mode: 0o700 });
|
|
52
|
-
await (0, runPromise_1.runPromise)(`ssh-keygen -t ${DEFAULT_KEY_TYPE} -f ${quote(keyPath)} -N "" -C signfiles`);
|
|
45
|
+
await (0, runPromise_1.runPromise)(`ssh-keygen -t ${exports.DEFAULT_KEY_TYPE} -f ${quote(keyPath)} -N "" -C signfiles`);
|
|
53
46
|
return keyPath;
|
|
54
47
|
}
|
|
55
48
|
/** The public key in the form the daemon reports it, so what is printed here can be compared
|
|
@@ -112,14 +105,6 @@ async function refuseRevokedKeys(repoPath) {
|
|
|
112
105
|
}).join("\n")
|
|
113
106
|
+ `\nDelete them from authorized_keys, or run "yarn unrevoke" here to allow them again.`);
|
|
114
107
|
}
|
|
115
|
-
function parseArgs(argv) {
|
|
116
|
-
let pushToGit = argv.includes(GIT_KEYWORD);
|
|
117
|
-
let positional = argv.filter(arg => arg !== GIT_KEYWORD);
|
|
118
|
-
if (positional.length > 1) {
|
|
119
|
-
throw new Error(`Expected at most a signing key, was ${positional.length} argument(s): ${positional.join(" ")}\n${USAGE}`);
|
|
120
|
-
}
|
|
121
|
-
return { keyPath: positional[0], pushToGit };
|
|
122
|
-
}
|
|
123
108
|
/** Writes the manifest and its signature into a repo. Separate from the command so anything that
|
|
124
109
|
changes a keys repo can leave it signed, rather than telling someone to go and do it. */
|
|
125
110
|
async function signRepo(config) {
|
|
@@ -141,39 +126,18 @@ async function signRepo(config) {
|
|
|
141
126
|
await promises_1.default.writeFile(stagedManifest, (0, manifest_1.formatManifest)(manifest));
|
|
142
127
|
// Signing happens before any git work, so a failed push never costs a second touch of the key.
|
|
143
128
|
await (0, runPromise_1.runPromise)(`ssh-keygen -Y sign -f ${quote(signingKey)} -n ${manifest_1.SIGN_NAMESPACE} ${quote(stagedManifest)}`);
|
|
144
|
-
// Checked
|
|
145
|
-
|
|
129
|
+
// Checked with the same code the daemon verifies with, over the same normalised bytes, so what
|
|
130
|
+
// is about to be committed is proven to pass the check every other machine will run on it.
|
|
131
|
+
(0, sshsig_1.verifySSHSIG)({
|
|
132
|
+
signature: await promises_1.default.readFile(stagedSignature, "utf8"),
|
|
133
|
+
message: (0, manifest_1.normalizeContent)(await promises_1.default.readFile(stagedManifest)),
|
|
134
|
+
namespace: manifest_1.SIGN_NAMESPACE,
|
|
135
|
+
});
|
|
146
136
|
await promises_1.default.copyFile(stagedManifest, path_1.default.join(repoPath, manifest_1.MANIFEST_NAME));
|
|
147
137
|
await promises_1.default.copyFile(stagedSignature, path_1.default.join(repoPath, manifest_1.SIGNATURE_NAME));
|
|
148
138
|
await promises_1.default.rm(stagingDirectory, { recursive: true, force: true });
|
|
149
139
|
console.log(`Signed with ${await publicKeyOf(signingKey)}`);
|
|
150
140
|
}
|
|
151
141
|
exports.signRepo = signRepo;
|
|
152
|
-
async function main() {
|
|
153
|
-
|
|
154
|
-
// The keys repo, which is this one when it holds keys and this machine's otherwise. Signing
|
|
155
|
-
// whatever repo the terminal happened to be in is how you end up signing something that is not
|
|
156
|
-
// a keys repo at all.
|
|
157
|
-
let { repoPath } = await (0, keysRepo_1.resolveKeysRepo)();
|
|
158
|
-
console.log(`Signing ${repoPath}`);
|
|
159
|
-
await signRepo({ repoPath, keyPath });
|
|
160
|
-
if (!pushToGit) {
|
|
161
|
-
console.log(`Commit and push ${manifest_1.MANIFEST_NAME} and ${manifest_1.SIGNATURE_NAME} for anything to see them.`);
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
await (0, runPromise_1.runPromise)(`git add -A`, { cwd: repoPath });
|
|
165
|
-
// Nothing staged is not worth stopping on. git commit calls that a failure, but it only means
|
|
166
|
-
// the signature matches the one already committed, so there is nothing to deploy.
|
|
167
|
-
let status = await (0, spawn_1.spawnPromise)({ command: "git", args: ["status", "--porcelain"], cwd: repoPath });
|
|
168
|
-
let staged = status.stdout;
|
|
169
|
-
if (!staged.trim()) {
|
|
170
|
-
console.log(`Nothing changed, ${manifest_1.MANIFEST_NAME} and ${manifest_1.SIGNATURE_NAME} are already committed.`);
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
await (0, runPromise_1.runPromise)(`git commit -m ${quote(COMMIT_MESSAGE)}`, { cwd: repoPath });
|
|
174
|
-
await (0, runPromise_1.runPromise)(`git push`, { cwd: repoPath });
|
|
175
|
-
console.log(`Committed and pushed.`);
|
|
176
|
-
}
|
|
177
|
-
exports.main = main;
|
|
178
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbkZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2lnbkZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJEQUE2QjtBQUM3Qiw0Q0FBb0I7QUFDcEIsZ0RBQXdCO0FBQ3hCLCtEQUE0RDtBQUM1RCw0Q0FBOEM7QUFDOUMsNENBQWdEO0FBQ2hELHlDQUEwRztBQUMxRyx5REFBK0Q7QUFDL0QseURBQTZEO0FBQzdELHFFQUFrRjtBQUVsRixpR0FBaUc7QUFDakcscUdBQXFHO0FBQ3JHLE1BQU0sZ0JBQWdCLEdBQUcsWUFBWSxDQUFDO0FBQ3RDLE1BQU0sZ0JBQWdCLEdBQUcsNkJBQTZCLENBQUM7QUFDdkQsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDO0FBQzFCLE1BQU0sY0FBYyxHQUFHLHdCQUF3QixDQUFDO0FBQ2hELE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBQ2xDLE1BQU0sS0FBSyxHQUFHLHdDQUF3QyxXQUFXOzs7RUFHL0QsZ0JBQWdCLFdBQVcsZ0JBQWdCO09BQ3RDLFdBQVcsc0NBQXNDLENBQUM7QUFFekQ7MEVBQzBFO0FBQzFFLFNBQVMsS0FBSyxDQUFDLEtBQWE7SUFDeEIsT0FBTyxJQUFJLEtBQUssR0FBRyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxLQUFLLFVBQVUsVUFBVSxDQUFDLFFBQWdCO0lBQ3RDLElBQUksQ0FBQztRQUNELE1BQU0sa0JBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUIsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDVCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0FBQ0wsQ0FBQztBQUVELG9FQUFvRTtBQUNwRSxLQUFLLFVBQVUsZ0JBQWdCO0lBQzNCLElBQUksT0FBTyxHQUFHLElBQUEsa0JBQVUsRUFBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzNDLElBQUksTUFBTSxVQUFVLENBQUMsT0FB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QyxDQUFDO0FBQ3pDLENBQUM7QUExQkQsb0JBMEJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IG9zIGZyb20gXCJvc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IHJ1blByb21pc2UgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9ydW5Qcm9taXNlXCI7XG5pbXBvcnQgeyBleHBhbmRIb21lIH0gZnJvbSBcIi4uL2hlbHBlcnMvcGF0aHNcIjtcbmltcG9ydCB7IHNwYXduUHJvbWlzZSB9IGZyb20gXCIuLi9oZWxwZXJzL3NwYXduXCI7XG5pbXBvcnQgeyBidWlsZE1hbmlmZXN0LCBmb3JtYXRNYW5pZmVzdCwgTUFOSUZFU1RfTkFNRSwgU0lHTkFUVVJFX05BTUUsIFNJR05fTkFNRVNQQUNFIH0gZnJvbSBcIi4vbWFuaWZlc3RcIjtcbmltcG9ydCB7IHJldm9rZWRLZXlzSW5SZXBvIH0gZnJvbSBcIi4uL2F1dGhvcml6ZWRLZXlzL3VucmV2b2tlXCI7XG5pbXBvcnQgeyByZXNvbHZlS2V5c1JlcG8gfSBmcm9tIFwiLi4vYXV0aG9yaXplZEtleXMva2V5c1JlcG9cIjtcbmltcG9ydCB7IGZpbmRLZXlQcm9ibGVtcywgbm9ybWFsaXplS2V5cyB9IGZyb20gXCIuLi9hdXRob3JpemVkS2V5cy9hdXRob3JpemVkS2V5c1wiO1xuXG4vLyBBIGhhcmR3YXJlIGJhY2tlZCBrZXkgaXMgdGhlIGVudGlyZSBwb2ludC4gQSBrZXkgc2l0dGluZyBvbiBkaXNrIGlzIGNvbXByb21pc2VkIHRoZSBtb21lbnQgdGhlXG4vLyBtYWNoaW5lIGlzLCBhbmQgdGhlbiB0aGUgc2lnbmF0dXJlIHByb3ZlcyBub3RoaW5nLCBzbyB0aGlzIGlzIHdoYXQgd2UgbWFrZSB3aGVuIGFza2VkIHRvIG1ha2Ugb25lLlxuY29uc3QgREVGQVVMVF9LRVlfVFlQRSA9IFwiZWQyNTUxOS1za1wiO1xuY29uc3QgREVGQVVMVF9LRVlfUEFUSCA9IFwifi8uc3NoL3NpZ25maWxlc19lZDI1NTE5X3NrXCI7XG5jb25zdCBHSVRfS0VZV09SRCA9IFwiZ2l0XCI7XG5jb25zdCBDT01NSVRfTUVTU0FHRSA9IFwiZGVwbG95aW5nIHNpZ25lZCBmaWxlc1wiO1xuY29uc3QgTUFYX0VSUk9SX0JPRFlfTEVOR1RIID0gNTAwO1xuY29uc3QgVVNBR0UgPSBgVXNhZ2U6IHlhcm4gc2lnbmZpbGVzIFtzaWduaW5nLWtleV0gWyR7R0lUX0tFWVdPUkR9XVxuXG5TaWducyB0aGUgZmlsZXMgb2YgdGhlIHJlcG8gaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5LiBXaXRoIG5vIGtleSwgYSBoYXJkd2FyZSBiYWNrZWRcbiR7REVGQVVMVF9LRVlfVFlQRX0ga2V5IGF0ICR7REVGQVVMVF9LRVlfUEFUSH0gaXMgdXNlZCwgYW5kIGNyZWF0ZWQgaWYgaXQgZG9lcyBub3QgZXhpc3QuXG5QYXNzICR7R0lUX0tFWVdPUkR9IHRvIGFsc28gY29tbWl0IGFuZCBwdXNoIHRoZSByZXN1bHQuYDtcblxuLyoqIHJ1blByb21pc2UgdGFrZXMgYSBjb21tYW5kIGxpbmUgcmF0aGVyIHRoYW4gYW4gYXJndW1lbnQgbGlzdCwgc28gYW55dGhpbmcgaG9sZGluZyBhIHBhdGggaGFzIHRvXG4gICAgc3Vydml2ZSB0aGUgc2hlbGwuIERvdWJsZSBxdW90ZXMgd29yayBvbiBib3RoIGNtZCBhbmQgcG9zaXggc2hlbGxzLiAqL1xuZnVuY3Rpb24gcXVvdGUodmFsdWU6IHN0cmluZykge1xuICAgIHJldHVybiBgXCIke3ZhbHVlfVwiYDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcGF0aEV4aXN0cyhmaWxlUGF0aDogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZnMuYWNjZXNzKGZpbGVQYXRoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG4vKiogQ3JlYXRpbmcgdGhpcyBuZWVkcyB0aGUgc2VjdXJpdHkga2V5IHBsdWdnZWQgaW4sIGFuZCBhIHRvdWNoLiAqL1xuYXN5bmMgZnVuY3Rpb24gZW5zdXJlRGVmYXVsdEtleSgpIHtcbiAgICBsZXQga2V5UGF0aCA9IGV4cGFuZEhvbWUoREVGQVVMVF9LRVlfUEFUSCk7XG4gICAgaWYgKGF3YWl0IHBhdGhFeGlzdHMoa2V5UGF0aCkpIHtcbiAgICAgICAgcmV0dXJuIGtleVBhdGg7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBObyBzaWduaW5nIGtleSBhdCAke2tleVBhdGh9LCBjcmVhdGluZyBhbiAke0RFRkFVTFRfS0VZX1RZUEV9IG9uZS5gKTtcbiAgICBjb25zb2xlLmxvZyhgUGx1ZyB5b3VyIHNlY3VyaXR5IGtleSBpbiAtIHlvdSB3aWxsIGJlIGFza2VkIHRvIHRvdWNoIGl0LmApO1xuICAgIGF3YWl0IGZzLm1rZGlyKHBhdGguZGlybmFtZShrZXlQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUsIG1vZGU6IDBvNzAwIH0pO1xuICAgIGF3YWl0IHJ1blByb21pc2UoYHNzaC1rZXlnZW4gLXQgJHtERUZBVUxUX0tFWV9UWVBFfSAtZiAke3F1b3RlKGtleVBhdGgpfSAtTiBcIlwiIC1DIHNpZ25maWxlc2ApO1xuICAgIHJldHVybiBrZXlQYXRoO1xufVxuXG4vKiogVGhlIHB1YmxpYyBrZXkgaW4gdGhlIGZvcm0gdGhlIGRhZW1vbiByZXBvcnRzIGl0LCBzbyB3aGF0IGlzIHByaW50ZWQgaGVyZSBjYW4gYmUgY29tcGFyZWRcbiAgICBhZ2FpbnN0IHdoYXQgYXJyaXZlcyBvbiBEaXNjb3JkLiAqL1xuYXN5bmMgZnVuY3Rpb24gcHVibGljS2V5T2Yoa2V5UGF0aDogc3RyaW5nKSB7XG4gICAgbGV0IGNvbnRlbnRzID0gYXdhaXQgZnMucmVhZEZpbGUoYCR7a2V5UGF0aH0ucHViYCwgXCJ1dGY4XCIpO1xuICAgIGxldCBba2V5VHlwZSwga2V5Qm9keV0gPSBjb250ZW50cy50cmltKCkuc3BsaXQoL1xccysvKTtcbiAgICBpZiAoIWtleVR5cGUgfHwgIWtleUJvZHkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhIHB1YmxpYyBrZXkgaW4gJHtrZXlQYXRofS5wdWIsIHdhcyAke2NvbnRlbnRzLnNsaWNlKDAsIE1BWF9FUlJPUl9CT0RZX0xFTkdUSCl9YCk7XG4gICAgfVxuICAgIHJldHVybiBgJHtrZXlUeXBlfSAke2tleUJvZHl9YDtcbn1cblxuLyoqIEEga2V5cyByZXBvIGhhcyBydWxlcyB0aGUgcmVzdCBvZiB0aGlzIGNhbm5vdCBlbmZvcmNlIGFmdGVyd2FyZHMsIHNvIHRoZXkgYXJlIGVuZm9yY2VkIGJlZm9yZSBpdFxuICAgIGlzIHNpZ25lZC4gU2lnbmluZyBhbnl0aGluZyB0aGF0IGlzIG5vdCBhIGtleXMgcmVwbyBpcyBub25lIG9mIHRoaXMgZnVuY3Rpb24ncyBidXNpbmVzcy4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlZnVzZVVudXNhYmxlS2V5cyhyZXBvUGF0aDogc3RyaW5nKSB7XG4gICAgbGV0IGF1dGhvcml6ZWRQYXRoID0gcGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKTtcbiAgICBpZiAoIWF3YWl0IHBhdGhFeGlzdHMoYXV0aG9yaXplZFBhdGgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHByb2JsZW1zID0gZmluZEtleVByb2JsZW1zKG5vcm1hbGl6ZUtleXMoYXdhaXQgZnMucmVhZEZpbGUoYXV0aG9yaXplZFBhdGgsIFwidXRmOFwiKSkpO1xuICAgIGlmICghcHJvYmxlbXMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgRXhwZWN0ZWQgZXZlcnkga2V5IGluICR7YXV0aG9yaXplZFBhdGh9IHRvIGJlIHJlc3RyaWN0ZWQgYW5kIHRvIGJlbG9uZyB0byBvbmUgcGVyc29uLGBcbiAgICAgICAgKyBgIGZvdW5kICR7cHJvYmxlbXMubGVuZ3RofSBwcm9ibGVtKHMpOlxcbmBcbiAgICAgICAgKyBwcm9ibGVtcy5tYXAocHJvYmxlbSA9PiBgICAtICR7cHJvYmxlbX1gKS5qb2luKFwiXFxuXCIpXG4gICAgICAgICsgYFxcblxcbkV2ZXJ5IGtleSBuZWVkcyBhIGZyb209IG5hbWluZyB0aGUgYWRkcmVzc2VzIGl0IG1heSBiZSB1c2VkIGZyb20sIGFuZCBubyB0d28ga2V5cyBtYXlgXG4gICAgICAgICsgYFxcbm5hbWUgdGhlIHNhbWUgb25lcy4gUmV2b2tpbmcgYSBrZXkgdGhhdCBzaGFyZXMgaXRzIGFkZHJlc3NlcyB3aXRoIGFub3RoZXIgbGVhdmVzIHRoYXRgXG4gICAgICAgICsgYFxcbm90aGVyIGtleSB3b3JraW5nLCB3aGljaCBkZWZlYXRzIHRoZSBwb2ludCBvZiByZXZva2luZyBpdC5gXG4gICAgKTtcbn1cblxuLyoqIFNpZ25pbmcgYSBrZXlzIHJlcG8gdGhhdCBzdGlsbCBob2xkcyBhIHJldm9rZWQga2V5IHdvdWxkIHB1Ymxpc2ggaXQgYmFjayB0byBldmVyeSBtYWNoaW5lIHRoYXRcbiAgICB0b29rIGl0IG91dC4gT25seSBhcHBsaWVzIHRvIGEgcmVwbyB0aGF0IGhvbGRzIGtleXMgYW5kIGhhcyBhIHJldm9rZSByZXBvIHRvIGNoZWNrIC0gc2lnbmluZ1xuICAgIGFueXRoaW5nIGVsc2UgaXMgbm9uZSBvZiB0aGlzIGZ1bmN0aW9uJ3MgYnVzaW5lc3MuICovXG5hc3luYyBmdW5jdGlvbiByZWZ1c2VSZXZva2VkS2V5cyhyZXBvUGF0aDogc3RyaW5nKSB7XG4gICAgaWYgKCFhd2FpdCBwYXRoRXhpc3RzKHBhdGguam9pbihyZXBvUGF0aCwgXCJhdXRob3JpemVkX2tleXNcIikpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gUmVhZCBmb3IgaXRzIHZhbHVlLCBzbyBzdGRvdXQgaGFzIHRvIGJlIG9uIGl0cyBvd24uIHJ1blByb21pc2Ugam9pbnMgaXQgd2l0aCBzdGRlcnIuXG4gICAgbGV0IG9yaWdpbiA9IGF3YWl0IHNwYXduUHJvbWlzZSh7IGNvbW1hbmQ6IFwiZ2l0XCIsIGFyZ3M6IFtcInJlbW90ZVwiLCBcImdldC11cmxcIiwgXCJvcmlnaW5cIl0sIGN3ZDogcmVwb1BhdGggfSk7XG4gICAgbGV0IG9yaWdpblVSTCA9IG9yaWdpbi5zdGRvdXQudHJpbSgpO1xuICAgIGlmIChvcmlnaW4uc3RhdHVzICE9PSAwIHx8ICFvcmlnaW5VUkwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgcmV2b2tlZDtcbiAgICB0cnkge1xuICAgICAgICByZXZva2VkID0gYXdhaXQgcmV2b2tlZEtleXNJblJlcG8oeyByZXBvUGF0aCwgc291cmNlVVJMOiBvcmlnaW5VUkwgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyBObyByZXZva2UgcmVwbywgb3Igbm8gYWNjZXNzIHRvIGl0LiBOb3RoaW5nIGhhcyBiZWVuIHJldm9rZWQgdGhhdCB3ZSBjYW4gc2VlLlxuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghcmV2b2tlZC5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBFeHBlY3RlZCAke3JlcG9QYXRofSB0byBob2xkIG5vIHJldm9rZWQga2V5cywgaXQgaG9sZHMgJHtyZXZva2VkLmxlbmd0aH06XFxuYFxuICAgICAgICArIHJldm9rZWQubWFwKGVudHJ5ID0+IGAgICR7ZW50cnkucmV2b2NhdGlvbi5maW5nZXJwcmludH0gcmV2b2tlZCBieSAke2VudHJ5LnJldm9jYXRpb24ucmV2b2tlZEJ5IHx8IFwiP1wifWBcbiAgICAgICAgICAgICsgYCBhZnRlciB1c2UgZnJvbSAke2VudHJ5LnJldm9jYXRpb24uYXR0ZW1wdD8uaXAgfHwgXCI/XCJ9YCkuam9pbihcIlxcblwiKVxuICAgICAgICArIGBcXG5EZWxldGUgdGhlbSBmcm9tIGF1dGhvcml6ZWRfa2V5cywgb3IgcnVuIFwieWFybiB1bnJldm9rZVwiIGhlcmUgdG8gYWxsb3cgdGhlbSBhZ2Fpbi5gXG4gICAgKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdKSB7XG4gICAgbGV0IHB1c2hUb0dpdCA9IGFyZ3YuaW5jbHVkZXMoR0lUX0tFWVdPUkQpO1xuICAgIGxldCBwb3NpdGlvbmFsID0gYXJndi5maWx0ZXIoYXJnID0+IGFyZyAhPT0gR0lUX0tFWVdPUkQpO1xuICAgIGlmIChwb3NpdGlvbmFsLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhdCBtb3N0IGEgc2lnbmluZyBrZXksIHdhcyAke3Bvc2l0aW9uYWwubGVuZ3RofSBhcmd1bWVudChzKTogJHtwb3NpdGlvbmFsLmpvaW4oXCIgXCIpfVxcbiR7VVNBR0V9YCk7XG4gICAgfVxuICAgIHJldHVybiB7IGtleVBhdGg6IHBvc2l0aW9uYWxbMF0sIHB1c2hUb0dpdCB9O1xufVxuXG4vKiogV3JpdGVzIHRoZSBtYW5pZmVzdCBhbmQgaXRzIHNpZ25hdHVyZSBpbnRvIGEgcmVwby4gU2VwYXJhdGUgZnJvbSB0aGUgY29tbWFuZCBzbyBhbnl0aGluZyB0aGF0XG4gICAgY2hhbmdlcyBhIGtleXMgcmVwbyBjYW4gbGVhdmUgaXQgc2lnbmVkLCByYXRoZXIgdGhhbiB0ZWxsaW5nIHNvbWVvbmUgdG8gZ28gYW5kIGRvIGl0LiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpZ25SZXBvKGNvbmZpZzogeyByZXBvUGF0aDogc3RyaW5nOyBrZXlQYXRoPzogc3RyaW5nIH0pIHtcbiAgICBsZXQgeyByZXBvUGF0aCB9ID0gY29uZmlnO1xuICAgIGxldCBzaWduaW5nS2V5ID0gY29uZmlnLmtleVBhdGggJiYgZXhwYW5kSG9tZShjb25maWcua2V5UGF0aCkgfHwgYXdhaXQgZW5zdXJlRGVmYXVsdEtleSgpO1xuICAgIGlmICghYXdhaXQgcGF0aEV4aXN0cyhzaWduaW5nS2V5KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgc2lnbmluZyBrZXkgYXQgJHtzaWduaW5nS2V5fSwgbm8gc3VjaCBmaWxlIGV4aXN0c2ApO1xuICAgIH1cblxuICAgIGF3YWl0IHJlZnVzZVVudXNhYmxlS2V5cyhyZXBvUGF0aCk7XG4gICAgYXdhaXQgcmVmdXNlUmV2b2tlZEtleXMocmVwb1BhdGgpO1xuXG4gICAgbGV0IG1hbmlmZXN0ID0gYXdhaXQgYnVpbGRNYW5pZmVzdChyZXBvUGF0aCk7XG4gICAgY29uc29sZS5sb2coYCR7TUFOSUZFU1RfTkFNRX0gY292ZXJzICR7bWFuaWZlc3QuZmlsZXMubGVuZ3RofSBmaWxlKHMpIGluICR7cmVwb1BhdGh9YCk7XG5cbiAgICAvLyBUaGUgbWFuaWZlc3QgaXMgYnVpbHQgYW5kIHNpZ25lZCBhd2F5IGZyb20gdGhlIHJlcG8sIGFuZCBvbmx5IG1vdmVkIGluIG9uY2UgYm90aCBleGlzdC5cbiAgICAvLyBMYW5kaW5nIGEgbmV3IG1hbmlmZXN0IG5leHQgdG8gYW4gb2xkIHNpZ25hdHVyZSBwcm9kdWNlcyBhIHBhaXIgdGhhdCBjYW4gbmV2ZXIgdmVyaWZ5LCBhbmRcbiAgICAvLyB0aGUgZGFlbW9uIHJlYWRpbmcgaXQgY2FuIG9ubHkgdHJlYXQgdGhhdCBhcyB0YW1wZXJpbmcuXG4gICAgbGV0IHN0YWdpbmdEaXJlY3RvcnkgPSBhd2FpdCBmcy5ta2R0ZW1wKHBhdGguam9pbihvcy50bXBkaXIoKSwgXCJzaWduZmlsZXMtXCIpKTtcbiAgICBsZXQgc3RhZ2VkTWFuaWZlc3QgPSBwYXRoLmpvaW4oc3RhZ2luZ0RpcmVjdG9yeSwgTUFOSUZFU1RfTkFNRSk7XG4gICAgbGV0IHN0YWdlZFNpZ25hdHVyZSA9IGAke3N0YWdlZE1hbmlmZXN0fS5zaWdgO1xuICAgIGF3YWl0IGZzLndyaXRlRmlsZShzdGFnZWRNYW5pZmVzdCwgZm9ybWF0TWFuaWZlc3QobWFuaWZlc3QpKTtcblxuICAgIC8vIFNpZ25pbmcgaGFwcGVucyBiZWZvcmUgYW55IGdpdCB3b3JrLCBzbyBhIGZhaWxlZCBwdXNoIG5ldmVyIGNvc3RzIGEgc2Vjb25kIHRvdWNoIG9mIHRoZSBrZXkuXG4gICAgYXdhaXQgcnVuUHJvbWlzZShgc3NoLWtleWdlbiAtWSBzaWduIC1mICR7cXVvdGUoc2lnbmluZ0tleSl9IC1uICR7U0lHTl9OQU1FU1BBQ0V9ICR7cXVvdGUoc3RhZ2VkTWFuaWZlc3QpfWApO1xuICAgIC8vIENoZWNrZWQgaGVyZSByYXRoZXIgdGhhbiBsZWZ0IGZvciBhIG1hY2hpbmUgdGhhdCBoYXMgYWxyZWFkeSBwdWxsZWQgaXQgdG8gZGlzY292ZXIuXG4gICAgYXdhaXQgcnVuUHJvbWlzZShcbiAgICAgICAgYHNzaC1rZXlnZW4gLVkgY2hlY2stbm92YWxpZGF0ZSAtbiAke1NJR05fTkFNRVNQQUNFfSAtcyAke3F1b3RlKHN0YWdlZFNpZ25hdHVyZSl9IDwgJHtxdW90ZShzdGFnZWRNYW5pZmVzdCl9YFxuICAgICk7XG4gICAgYXdhaXQgZnMuY29weUZpbGUoc3RhZ2VkTWFuaWZlc3QsIHBhdGguam9pbihyZXBvUGF0aCwgTUFOSUZFU1RfTkFNRSkpO1xuICAgIGF3YWl0IGZzLmNvcHlGaWxlKHN0YWdlZFNpZ25hdHVyZSwgcGF0aC5qb2luKHJlcG9QYXRoLCBTSUdOQVRVUkVfTkFNRSkpO1xuICAgIGF3YWl0IGZzLnJtKHN0YWdpbmdEaXJlY3RvcnksIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBjb25zb2xlLmxvZyhgU2lnbmVkIHdpdGggJHthd2FpdCBwdWJsaWNLZXlPZihzaWduaW5nS2V5KX1gKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7XG4gICAgbGV0IHsga2V5UGF0aCwgcHVzaFRvR2l0IH0gPSBwYXJzZUFyZ3MocHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTtcblxuICAgIC8vIFRoZSBrZXlzIHJlcG8sIHdoaWNoIGlzIHRoaXMgb25lIHdoZW4gaXQgaG9sZHMga2V5cyBhbmQgdGhpcyBtYWNoaW5lJ3Mgb3RoZXJ3aXNlLiBTaWduaW5nXG4gICAgLy8gd2hhdGV2ZXIgcmVwbyB0aGUgdGVybWluYWwgaGFwcGVuZWQgdG8gYmUgaW4gaXMgaG93IHlvdSBlbmQgdXAgc2lnbmluZyBzb21ldGhpbmcgdGhhdCBpcyBub3RcbiAgICAvLyBhIGtleXMgcmVwbyBhdCBhbGwuXG4gICAgbGV0IHsgcmVwb1BhdGggfSA9IGF3YWl0IHJlc29sdmVLZXlzUmVwbygpO1xuICAgIGNvbnNvbGUubG9nKGBTaWduaW5nICR7cmVwb1BhdGh9YCk7XG4gICAgYXdhaXQgc2lnblJlcG8oeyByZXBvUGF0aCwga2V5UGF0aCB9KTtcblxuICAgIGlmICghcHVzaFRvR2l0KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBDb21taXQgYW5kIHB1c2ggJHtNQU5JRkVTVF9OQU1FfSBhbmQgJHtTSUdOQVRVUkVfTkFNRX0gZm9yIGFueXRoaW5nIHRvIHNlZSB0aGVtLmApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IHJ1blByb21pc2UoYGdpdCBhZGQgLUFgLCB7IGN3ZDogcmVwb1BhdGggfSk7XG4gICAgLy8gTm90aGluZyBzdGFnZWQgaXMgbm90IHdvcnRoIHN0b3BwaW5nIG9uLiBnaXQgY29tbWl0IGNhbGxzIHRoYXQgYSBmYWlsdXJlLCBidXQgaXQgb25seSBtZWFuc1xuICAgIC8vIHRoZSBzaWduYXR1cmUgbWF0Y2hlcyB0aGUgb25lIGFscmVhZHkgY29tbWl0dGVkLCBzbyB0aGVyZSBpcyBub3RoaW5nIHRvIGRlcGxveS5cbiAgICBsZXQgc3RhdHVzID0gYXdhaXQgc3Bhd25Qcm9taXNlKHsgY29tbWFuZDogXCJnaXRcIiwgYXJnczogW1wic3RhdHVzXCIsIFwiLS1wb3JjZWxhaW5cIl0sIGN3ZDogcmVwb1BhdGggfSk7XG4gICAgbGV0IHN0YWdlZCA9IHN0YXR1cy5zdGRvdXQ7XG4gICAgaWYgKCFzdGFnZWQudHJpbSgpKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBOb3RoaW5nIGNoYW5nZWQsICR7TUFOSUZFU1RfTkFNRX0gYW5kICR7U0lHTkFUVVJFX05BTUV9IGFyZSBhbHJlYWR5IGNvbW1pdHRlZC5gKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgY29tbWl0IC1tICR7cXVvdGUoQ09NTUlUX01FU1NBR0UpfWAsIHsgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgcHVzaGAsIHsgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBjb25zb2xlLmxvZyhgQ29tbWl0dGVkIGFuZCBwdXNoZWQuYCk7XG59XG4iXX0=
|
|
179
|
-
/* _JS_SOURCE_HASH = "e62739f311ed1c2d2b818032186647cfb19cc96beec3178194cb15bda564b243"; */
|
|
142
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbkZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2lnbkZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJEQUE2QjtBQUM3Qiw0Q0FBb0I7QUFDcEIsZ0RBQXdCO0FBQ3hCLCtEQUE0RDtBQUM1RCw0Q0FBOEM7QUFDOUMsNENBQWdEO0FBQ2hELHlDQUE0SDtBQUM1SCxxQ0FBd0M7QUFDeEMseURBQStEO0FBQy9ELHFFQUFrRjtBQUVsRixpR0FBaUc7QUFDakcscUdBQXFHO0FBQ3hGLFFBQUEsZ0JBQWdCLEdBQUcsWUFBWSxDQUFDO0FBQ2hDLFFBQUEsZ0JBQWdCLEdBQUcsNkJBQTZCLENBQUM7QUFDOUQsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLENBQUM7QUFFbEM7MEVBQzBFO0FBQzFFLFNBQVMsS0FBSyxDQUFDLEtBQWE7SUFDeEIsT0FBTyxJQUFJLEtBQUssR0FBRyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxLQUFLLFVBQVUsVUFBVSxDQUFDLFFBQWdCO0lBQ3RDLElBQUksQ0FBQztRQUNELE1BQU0sa0JBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUIsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDVCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0FBQ0wsQ0FBQztBQUVELG9FQUFvRTtBQUNwRSxLQUFLLFVBQVUsZ0JBQWdCO0lBQzNCLElBQUksT0FBTyxHQUFHLElBQUEsa0JBQVUsRUFBQyx3QkFBZ0IsQ0FBQyxDQUFDO0lBQzNDLElBQUksTUFBTSxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM1QixPQUFPLE9BQU8sQ0FBQztJQUNuQixDQUFDO0lBQ0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsT0FBTyxpQkFBaUIsd0JBQWdCLE9BQU8sQ0FBQyxDQUFDO0lBQ2xGLE9BQU8sQ0FBQyxHQUFHLENBQUMsNERBQTRE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O0lBQ3RFLE1BQU0sa0JBQUUsQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLGNBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLHlCQUFjLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLE1BQU0sa0JBQUUsQ0FBQyxFQUFFLENBQUMsZ0JBQWdCLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2hFLE9BQU8sQ0FBQyxHQUFHLENBQUMsZUFBZSxNQUFNLFdBQVcsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7QUFDaEUsQ0FBQztBQWxDRCw0QkFrQ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgb3MgZnJvbSBcIm9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgcnVuUHJvbWlzZSB9IGZyb20gXCJzb2NrZXQtZnVuY3Rpb24vc3JjL3J1blByb21pc2VcIjtcbmltcG9ydCB7IGV4cGFuZEhvbWUgfSBmcm9tIFwiLi4vaGVscGVycy9wYXRoc1wiO1xuaW1wb3J0IHsgc3Bhd25Qcm9taXNlIH0gZnJvbSBcIi4uL2hlbHBlcnMvc3Bhd25cIjtcbmltcG9ydCB7IGJ1aWxkTWFuaWZlc3QsIGZvcm1hdE1hbmlmZXN0LCBNQU5JRkVTVF9OQU1FLCBub3JtYWxpemVDb250ZW50LCBTSUdOQVRVUkVfTkFNRSwgU0lHTl9OQU1FU1BBQ0UgfSBmcm9tIFwiLi9tYW5pZmVzdFwiO1xuaW1wb3J0IHsgdmVyaWZ5U1NIU0lHIH0gZnJvbSBcIi4vc3Noc2lnXCI7XG5pbXBvcnQgeyByZXZva2VkS2V5c0luUmVwbyB9IGZyb20gXCIuLi9hdXRob3JpemVkS2V5cy91bnJldm9rZVwiO1xuaW1wb3J0IHsgZmluZEtleVByb2JsZW1zLCBub3JtYWxpemVLZXlzIH0gZnJvbSBcIi4uL2F1dGhvcml6ZWRLZXlzL2F1dGhvcml6ZWRLZXlzXCI7XG5cbi8vIEEgaGFyZHdhcmUgYmFja2VkIGtleSBpcyB0aGUgZW50aXJlIHBvaW50LiBBIGtleSBzaXR0aW5nIG9uIGRpc2sgaXMgY29tcHJvbWlzZWQgdGhlIG1vbWVudCB0aGVcbi8vIG1hY2hpbmUgaXMsIGFuZCB0aGVuIHRoZSBzaWduYXR1cmUgcHJvdmVzIG5vdGhpbmcsIHNvIHRoaXMgaXMgd2hhdCB3ZSBtYWtlIHdoZW4gYXNrZWQgdG8gbWFrZSBvbmUuXG5leHBvcnQgY29uc3QgREVGQVVMVF9LRVlfVFlQRSA9IFwiZWQyNTUxOS1za1wiO1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfS0VZX1BBVEggPSBcIn4vLnNzaC9zaWduZmlsZXNfZWQyNTUxOV9za1wiO1xuY29uc3QgTUFYX0VSUk9SX0JPRFlfTEVOR1RIID0gNTAwO1xuXG4vKiogcnVuUHJvbWlzZSB0YWtlcyBhIGNvbW1hbmQgbGluZSByYXRoZXIgdGhhbiBhbiBhcmd1bWVudCBsaXN0LCBzbyBhbnl0aGluZyBob2xkaW5nIGEgcGF0aCBoYXMgdG9cbiAgICBzdXJ2aXZlIHRoZSBzaGVsbC4gRG91YmxlIHF1b3RlcyB3b3JrIG9uIGJvdGggY21kIGFuZCBwb3NpeCBzaGVsbHMuICovXG5mdW5jdGlvbiBxdW90ZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGBcIiR7dmFsdWV9XCJgO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwYXRoRXhpc3RzKGZpbGVQYXRoOiBzdHJpbmcpIHtcbiAgICB0cnkge1xuICAgICAgICBhd2FpdCBmcy5hY2Nlc3MoZmlsZVBhdGgpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59XG5cbi8qKiBDcmVhdGluZyB0aGlzIG5lZWRzIHRoZSBzZWN1cml0eSBrZXkgcGx1Z2dlZCBpbiwgYW5kIGEgdG91Y2guICovXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVEZWZhdWx0S2V5KCkge1xuICAgIGxldCBrZXlQYXRoID0gZXhwYW5kSG9tZShERUZBVUxUX0tFWV9QQVRIKTtcbiAgICBpZiAoYXdhaXQgcGF0aEV4aXN0cyhrZXlQYXRoKSkge1xuICAgICAgICByZXR1cm4ga2V5UGF0aDtcbiAgICB9XG4gICAgY29uc29sZS5sb2coYE5vIHNpZ25pbmcga2V5IGF0ICR7a2V5UGF0aH0sIGNyZWF0aW5nIGFuICR7REVGQVVMVF9LRVlfVFlQRX0gb25lLmApO1xuICAgIGNvbnNvbGUubG9nKGBQbHVnIHlvdXIgc2VjdXJpdHkga2V5IGluIC0geW91IHdpbGwgYmUgYXNrZWQgdG8gdG91Y2ggaXQuYCk7XG4gICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKGtleVBhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgbW9kZTogMG83MDAgfSk7XG4gICAgYXdhaXQgcnVuUHJvbWlzZShgc3NoLWtleWdlbiAtdCAke0RFRkFVTFRfS0VZX1RZUEV9IC1mICR7cXVvdGUoa2V5UGF0aCl9IC1OIFwiXCIgLUMgc2lnbmZpbGVzYCk7XG4gICAgcmV0dXJuIGtleVBhdGg7XG59XG5cbi8qKiBUaGUgcHVibGljIGtleSBpbiB0aGUgZm9ybSB0aGUgZGFlbW9uIHJlcG9ydHMgaXQsIHNvIHdoYXQgaXMgcHJpbnRlZCBoZXJlIGNhbiBiZSBjb21wYXJlZFxuICAgIGFnYWluc3Qgd2hhdCBhcnJpdmVzIG9uIERpc2NvcmQuICovXG5hc3luYyBmdW5jdGlvbiBwdWJsaWNLZXlPZihrZXlQYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgY29udGVudHMgPSBhd2FpdCBmcy5yZWFkRmlsZShgJHtrZXlQYXRofS5wdWJgLCBcInV0ZjhcIik7XG4gICAgbGV0IFtrZXlUeXBlLCBrZXlCb2R5XSA9IGNvbnRlbnRzLnRyaW0oKS5zcGxpdCgvXFxzKy8pO1xuICAgIGlmICgha2V5VHlwZSB8fCAha2V5Qm9keSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgcHVibGljIGtleSBpbiAke2tleVBhdGh9LnB1Yiwgd2FzICR7Y29udGVudHMuc2xpY2UoMCwgTUFYX0VSUk9SX0JPRFlfTEVOR1RIKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGAke2tleVR5cGV9ICR7a2V5Qm9keX1gO1xufVxuXG4vKiogQSBrZXlzIHJlcG8gaGFzIHJ1bGVzIHRoZSByZXN0IG9mIHRoaXMgY2Fubm90IGVuZm9yY2UgYWZ0ZXJ3YXJkcywgc28gdGhleSBhcmUgZW5mb3JjZWQgYmVmb3JlIGl0XG4gICAgaXMgc2lnbmVkLiBTaWduaW5nIGFueXRoaW5nIHRoYXQgaXMgbm90IGEga2V5cyByZXBvIGlzIG5vbmUgb2YgdGhpcyBmdW5jdGlvbidzIGJ1c2luZXNzLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVmdXNlVW51c2FibGVLZXlzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgYXV0aG9yaXplZFBhdGggPSBwYXRoLmpvaW4ocmVwb1BhdGgsIFwiYXV0aG9yaXplZF9rZXlzXCIpO1xuICAgIGlmICghYXdhaXQgcGF0aEV4aXN0cyhhdXRob3JpemVkUGF0aCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgcHJvYmxlbXMgPSBmaW5kS2V5UHJvYmxlbXMobm9ybWFsaXplS2V5cyhhd2FpdCBmcy5yZWFkRmlsZShhdXRob3JpemVkUGF0aCwgXCJ1dGY4XCIpKSk7XG4gICAgaWYgKCFwcm9ibGVtcy5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBFeHBlY3RlZCBldmVyeSBrZXkgaW4gJHthdXRob3JpemVkUGF0aH0gdG8gYmUgcmVzdHJpY3RlZCBhbmQgdG8gYmVsb25nIHRvIG9uZSBwZXJzb24sYFxuICAgICAgICArIGAgZm91bmQgJHtwcm9ibGVtcy5sZW5ndGh9IHByb2JsZW0ocyk6XFxuYFxuICAgICAgICArIHByb2JsZW1zLm1hcChwcm9ibGVtID0+IGAgIC0gJHtwcm9ibGVtfWApLmpvaW4oXCJcXG5cIilcbiAgICAgICAgKyBgXFxuXFxuRXZlcnkga2V5IG5lZWRzIGEgZnJvbT0gbmFtaW5nIHRoZSBhZGRyZXNzZXMgaXQgbWF5IGJlIHVzZWQgZnJvbSwgYW5kIG5vIHR3byBrZXlzIG1heWBcbiAgICAgICAgKyBgXFxubmFtZSB0aGUgc2FtZSBvbmVzLiBSZXZva2luZyBhIGtleSB0aGF0IHNoYXJlcyBpdHMgYWRkcmVzc2VzIHdpdGggYW5vdGhlciBsZWF2ZXMgdGhhdGBcbiAgICAgICAgKyBgXFxub3RoZXIga2V5IHdvcmtpbmcsIHdoaWNoIGRlZmVhdHMgdGhlIHBvaW50IG9mIHJldm9raW5nIGl0LmBcbiAgICApO1xufVxuXG4vKiogU2lnbmluZyBhIGtleXMgcmVwbyB0aGF0IHN0aWxsIGhvbGRzIGEgcmV2b2tlZCBrZXkgd291bGQgcHVibGlzaCBpdCBiYWNrIHRvIGV2ZXJ5IG1hY2hpbmUgdGhhdFxuICAgIHRvb2sgaXQgb3V0LiBPbmx5IGFwcGxpZXMgdG8gYSByZXBvIHRoYXQgaG9sZHMga2V5cyBhbmQgaGFzIGEgcmV2b2tlIHJlcG8gdG8gY2hlY2sgLSBzaWduaW5nXG4gICAgYW55dGhpbmcgZWxzZSBpcyBub25lIG9mIHRoaXMgZnVuY3Rpb24ncyBidXNpbmVzcy4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlZnVzZVJldm9rZWRLZXlzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBpZiAoIWF3YWl0IHBhdGhFeGlzdHMocGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBSZWFkIGZvciBpdHMgdmFsdWUsIHNvIHN0ZG91dCBoYXMgdG8gYmUgb24gaXRzIG93bi4gcnVuUHJvbWlzZSBqb2lucyBpdCB3aXRoIHN0ZGVyci5cbiAgICBsZXQgb3JpZ2luID0gYXdhaXQgc3Bhd25Qcm9taXNlKHsgY29tbWFuZDogXCJnaXRcIiwgYXJnczogW1wicmVtb3RlXCIsIFwiZ2V0LXVybFwiLCBcIm9yaWdpblwiXSwgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBsZXQgb3JpZ2luVVJMID0gb3JpZ2luLnN0ZG91dC50cmltKCk7XG4gICAgaWYgKG9yaWdpbi5zdGF0dXMgIT09IDAgfHwgIW9yaWdpblVSTCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCByZXZva2VkO1xuICAgIHRyeSB7XG4gICAgICAgIHJldm9rZWQgPSBhd2FpdCByZXZva2VkS2V5c0luUmVwbyh7IHJlcG9QYXRoLCBzb3VyY2VVUkw6IG9yaWdpblVSTCB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIE5vIHJldm9rZSByZXBvLCBvciBubyBhY2Nlc3MgdG8gaXQuIE5vdGhpbmcgaGFzIGJlZW4gcmV2b2tlZCB0aGF0IHdlIGNhbiBzZWUuXG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCFyZXZva2VkLmxlbmd0aCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEV4cGVjdGVkICR7cmVwb1BhdGh9IHRvIGhvbGQgbm8gcmV2b2tlZCBrZXlzLCBpdCBob2xkcyAke3Jldm9rZWQubGVuZ3RofTpcXG5gXG4gICAgICAgICsgcmV2b2tlZC5tYXAoZW50cnkgPT4gYCAgJHtlbnRyeS5yZXZvY2F0aW9uLmZpbmdlcnByaW50fSByZXZva2VkIGJ5ICR7ZW50cnkucmV2b2NhdGlvbi5yZXZva2VkQnkgfHwgXCI/XCJ9YFxuICAgICAgICAgICAgKyBgIGFmdGVyIHVzZSBmcm9tICR7ZW50cnkucmV2b2NhdGlvbi5hdHRlbXB0Py5pcCB8fCBcIj9cIn1gKS5qb2luKFwiXFxuXCIpXG4gICAgICAgICsgYFxcbkRlbGV0ZSB0aGVtIGZyb20gYXV0aG9yaXplZF9rZXlzLCBvciBydW4gXCJ5YXJuIHVucmV2b2tlXCIgaGVyZSB0byBhbGxvdyB0aGVtIGFnYWluLmBcbiAgICApO1xufVxuXG4vKiogV3JpdGVzIHRoZSBtYW5pZmVzdCBhbmQgaXRzIHNpZ25hdHVyZSBpbnRvIGEgcmVwby4gU2VwYXJhdGUgZnJvbSB0aGUgY29tbWFuZCBzbyBhbnl0aGluZyB0aGF0XG4gICAgY2hhbmdlcyBhIGtleXMgcmVwbyBjYW4gbGVhdmUgaXQgc2lnbmVkLCByYXRoZXIgdGhhbiB0ZWxsaW5nIHNvbWVvbmUgdG8gZ28gYW5kIGRvIGl0LiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpZ25SZXBvKGNvbmZpZzogeyByZXBvUGF0aDogc3RyaW5nOyBrZXlQYXRoPzogc3RyaW5nIH0pIHtcbiAgICBsZXQgeyByZXBvUGF0aCB9ID0gY29uZmlnO1xuICAgIGxldCBzaWduaW5nS2V5ID0gY29uZmlnLmtleVBhdGggJiYgZXhwYW5kSG9tZShjb25maWcua2V5UGF0aCkgfHwgYXdhaXQgZW5zdXJlRGVmYXVsdEtleSgpO1xuICAgIGlmICghYXdhaXQgcGF0aEV4aXN0cyhzaWduaW5nS2V5KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgc2lnbmluZyBrZXkgYXQgJHtzaWduaW5nS2V5fSwgbm8gc3VjaCBmaWxlIGV4aXN0c2ApO1xuICAgIH1cblxuICAgIGF3YWl0IHJlZnVzZVVudXNhYmxlS2V5cyhyZXBvUGF0aCk7XG4gICAgYXdhaXQgcmVmdXNlUmV2b2tlZEtleXMocmVwb1BhdGgpO1xuXG4gICAgbGV0IG1hbmlmZXN0ID0gYXdhaXQgYnVpbGRNYW5pZmVzdChyZXBvUGF0aCk7XG4gICAgY29uc29sZS5sb2coYCR7TUFOSUZFU1RfTkFNRX0gY292ZXJzICR7bWFuaWZlc3QuZmlsZXMubGVuZ3RofSBmaWxlKHMpIGluICR7cmVwb1BhdGh9YCk7XG5cbiAgICAvLyBUaGUgbWFuaWZlc3QgaXMgYnVpbHQgYW5kIHNpZ25lZCBhd2F5IGZyb20gdGhlIHJlcG8sIGFuZCBvbmx5IG1vdmVkIGluIG9uY2UgYm90aCBleGlzdC5cbiAgICAvLyBMYW5kaW5nIGEgbmV3IG1hbmlmZXN0IG5leHQgdG8gYW4gb2xkIHNpZ25hdHVyZSBwcm9kdWNlcyBhIHBhaXIgdGhhdCBjYW4gbmV2ZXIgdmVyaWZ5LCBhbmRcbiAgICAvLyB0aGUgZGFlbW9uIHJlYWRpbmcgaXQgY2FuIG9ubHkgdHJlYXQgdGhhdCBhcyB0YW1wZXJpbmcuXG4gICAgbGV0IHN0YWdpbmdEaXJlY3RvcnkgPSBhd2FpdCBmcy5ta2R0ZW1wKHBhdGguam9pbihvcy50bXBkaXIoKSwgXCJzaWduZmlsZXMtXCIpKTtcbiAgICBsZXQgc3RhZ2VkTWFuaWZlc3QgPSBwYXRoLmpvaW4oc3RhZ2luZ0RpcmVjdG9yeSwgTUFOSUZFU1RfTkFNRSk7XG4gICAgbGV0IHN0YWdlZFNpZ25hdHVyZSA9IGAke3N0YWdlZE1hbmlmZXN0fS5zaWdgO1xuICAgIGF3YWl0IGZzLndyaXRlRmlsZShzdGFnZWRNYW5pZmVzdCwgZm9ybWF0TWFuaWZlc3QobWFuaWZlc3QpKTtcblxuICAgIC8vIFNpZ25pbmcgaGFwcGVucyBiZWZvcmUgYW55IGdpdCB3b3JrLCBzbyBhIGZhaWxlZCBwdXNoIG5ldmVyIGNvc3RzIGEgc2Vjb25kIHRvdWNoIG9mIHRoZSBrZXkuXG4gICAgYXdhaXQgcnVuUHJvbWlzZShgc3NoLWtleWdlbiAtWSBzaWduIC1mICR7cXVvdGUoc2lnbmluZ0tleSl9IC1uICR7U0lHTl9OQU1FU1BBQ0V9ICR7cXVvdGUoc3RhZ2VkTWFuaWZlc3QpfWApO1xuICAgIC8vIENoZWNrZWQgd2l0aCB0aGUgc2FtZSBjb2RlIHRoZSBkYWVtb24gdmVyaWZpZXMgd2l0aCwgb3ZlciB0aGUgc2FtZSBub3JtYWxpc2VkIGJ5dGVzLCBzbyB3aGF0XG4gICAgLy8gaXMgYWJvdXQgdG8gYmUgY29tbWl0dGVkIGlzIHByb3ZlbiB0byBwYXNzIHRoZSBjaGVjayBldmVyeSBvdGhlciBtYWNoaW5lIHdpbGwgcnVuIG9uIGl0LlxuICAgIHZlcmlmeVNTSFNJRyh7XG4gICAgICAgIHNpZ25hdHVyZTogYXdhaXQgZnMucmVhZEZpbGUoc3RhZ2VkU2lnbmF0dXJlLCBcInV0ZjhcIiksXG4gICAgICAgIG1lc3NhZ2U6IG5vcm1hbGl6ZUNvbnRlbnQoYXdhaXQgZnMucmVhZEZpbGUoc3RhZ2VkTWFuaWZlc3QpKSxcbiAgICAgICAgbmFtZXNwYWNlOiBTSUdOX05BTUVTUEFDRSxcbiAgICB9KTtcbiAgICBhd2FpdCBmcy5jb3B5RmlsZShzdGFnZWRNYW5pZmVzdCwgcGF0aC5qb2luKHJlcG9QYXRoLCBNQU5JRkVTVF9OQU1FKSk7XG4gICAgYXdhaXQgZnMuY29weUZpbGUoc3RhZ2VkU2lnbmF0dXJlLCBwYXRoLmpvaW4ocmVwb1BhdGgsIFNJR05BVFVSRV9OQU1FKSk7XG4gICAgYXdhaXQgZnMucm0oc3RhZ2luZ0RpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIGNvbnNvbGUubG9nKGBTaWduZWQgd2l0aCAke2F3YWl0IHB1YmxpY0tleU9mKHNpZ25pbmdLZXkpfWApO1xufVxuIl19
|
|
143
|
+
/* _JS_SOURCE_HASH = "4a0362e3ebb2c3e38ab98fe24ab7f151737c241a4186d0e880713fb9d14fa48f"; */
|
|
@@ -36,9 +36,9 @@ export declare class ArchivesRemote implements IArchives {
|
|
|
36
36
|
private authenticate;
|
|
37
37
|
private callAuthed;
|
|
38
38
|
waitingForAccess(): Promise<{
|
|
39
|
-
link: string;
|
|
40
39
|
machineId: string;
|
|
41
40
|
ip: string;
|
|
41
|
+
reason: string;
|
|
42
42
|
} | undefined>;
|
|
43
43
|
hasWriteAccess(): Promise<boolean>;
|
|
44
44
|
private registerAccessRequest;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SocketFunction } from "socket-function/SocketFunction";
|
|
2
2
|
import { timeInMinute } from "socket-function/src/misc";
|
|
3
3
|
import { delay } from "socket-function/src/batching";
|
|
4
|
-
import { getIdentityCA, loadIdentityCA, sign } from "../../misc/https/certs";
|
|
4
|
+
import { getIdentityCA, getThreadKeyCert, loadIdentityCA, sign } from "../../misc/https/certs";
|
|
5
5
|
import { IArchives, ArchiveFileInfo, ArchivesConfig, ArchivesSyncStatus, ChangesAfterConfig, DelConfig, FindConfig, GetConfig, GetInfoConfig, MoveFileConfig, SourceConfig, SetConfig, SetLargeFileConfig, LARGE_SET_THRESHOLD, bufferChunkStream } from "../IArchives";
|
|
6
6
|
import { parseHostedUrl, getBucketBaseUrl, buildFileUrl } from "./remoteConfig";
|
|
7
7
|
import {
|
|
@@ -41,14 +41,20 @@ export async function authenticateStorage(config: { address: string; port: numbe
|
|
|
41
41
|
SocketFunction.ENABLE_CLIENT_MODE = true;
|
|
42
42
|
let rootDomain = config.address.split(".").slice(-2).join(".");
|
|
43
43
|
await loadIdentityCA(rootDomain);
|
|
44
|
-
let
|
|
44
|
+
let threadKeyCert = getThreadKeyCert(rootDomain);
|
|
45
|
+
let issuer = getIdentityCA(rootDomain);
|
|
45
46
|
let data = {
|
|
46
47
|
purpose: STORAGE_AUTH_PURPOSE,
|
|
47
48
|
time: Date.now(),
|
|
48
49
|
server: `${config.address}:${config.port}`,
|
|
49
50
|
};
|
|
50
|
-
let signature = sign(
|
|
51
|
-
return await RemoteStorageController.nodes[config.nodeId].authenticate({
|
|
51
|
+
let signature = sign(threadKeyCert, data);
|
|
52
|
+
return await RemoteStorageController.nodes[config.nodeId].authenticate({
|
|
53
|
+
certPem: threadKeyCert.cert.toString(),
|
|
54
|
+
issuerPem: issuer.cert.toString(),
|
|
55
|
+
signature,
|
|
56
|
+
data,
|
|
57
|
+
});
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
export class ArchivesRemote implements IArchives {
|
|
@@ -99,14 +105,14 @@ export class ArchivesRemote implements IArchives {
|
|
|
99
105
|
}
|
|
100
106
|
}
|
|
101
107
|
|
|
102
|
-
// Returns undefined if this machine has access to the account. Otherwise returns our machineId + ip as the server sees them,
|
|
103
|
-
public async waitingForAccess(): Promise<{
|
|
108
|
+
// Returns undefined if this machine has access to the account. Otherwise returns our machineId + ip as the server sees them, why we were refused, and the exact command that grants access.
|
|
109
|
+
public async waitingForAccess(): Promise<{ machineId: string; ip: string; reason: string } | undefined> {
|
|
104
110
|
let state = await this.callAuthed(() => this.controller.getAccessState({ account: this.account }));
|
|
105
111
|
if (state.hasAccess) return undefined;
|
|
106
112
|
return {
|
|
107
|
-
link: `https://${this.parsed.address}:${this.parsed.port}/${this.account}`,
|
|
108
113
|
machineId: state.machineId,
|
|
109
114
|
ip: state.ip,
|
|
115
|
+
reason: state.reason || "",
|
|
110
116
|
};
|
|
111
117
|
}
|
|
112
118
|
|
|
@@ -120,7 +126,7 @@ export class ArchivesRemote implements IArchives {
|
|
|
120
126
|
if (Date.now() - this.lastDeniedLog < timeInMinute) return;
|
|
121
127
|
let state = await this.callAuthed(() => this.controller.getAccessState({ account: this.account }));
|
|
122
128
|
this.lastDeniedLog = Date.now();
|
|
123
|
-
console.log(`No access to storage account ${JSON.stringify(this.account)} on ${this.parsed.address}:${this.parsed.port}
|
|
129
|
+
console.log(`No access to storage account ${JSON.stringify(this.account)} on ${this.parsed.address}:${this.parsed.port}. ${state.reason || ""}`);
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
// Runs a call, authenticating (and re-authenticating after reconnects) and waiting for account access as needed. With waitForAccess false, denied calls throw immediately instead - but the access request is still registered (in the background), so the denial is grantable.
|
|
@@ -1,131 +1,12 @@
|
|
|
1
1
|
process.env.NODE_ENV = "production";
|
|
2
2
|
|
|
3
3
|
import preact from "preact";
|
|
4
|
-
import { observable } from "mobx";
|
|
5
|
-
import { observer } from "../../render-utils/observer";
|
|
6
4
|
import { isNode } from "socket-function/src/misc";
|
|
7
5
|
import { css } from "typesafecss";
|
|
8
|
-
import { SocketFunction } from "socket-function/SocketFunction";
|
|
9
|
-
import { RemoteStorageController, AccessState } from "./storageController";
|
|
10
|
-
import { authenticateStorage } from "./ArchivesRemote";
|
|
11
6
|
|
|
12
|
-
// The storage server's
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const COPIED_RESET_DELAY = 2000;
|
|
16
|
-
|
|
17
|
-
@observer
|
|
18
|
-
class CopyableCommand extends preact.Component<{ command: string }> {
|
|
19
|
-
synced = observable({
|
|
20
|
-
copied: false,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
render() {
|
|
24
|
-
let command = this.props.command;
|
|
25
|
-
return <div className={css.hbox(8).alignItems("flex-start")}>
|
|
26
|
-
<button onClick={async () => {
|
|
27
|
-
await navigator.clipboard.writeText(command);
|
|
28
|
-
this.synced.copied = true;
|
|
29
|
-
setTimeout(() => { this.synced.copied = false; }, COPIED_RESET_DELAY);
|
|
30
|
-
}}>
|
|
31
|
-
{this.synced.copied && "Copied!" || "Copy"}
|
|
32
|
-
</button>
|
|
33
|
-
<code className={css.fontFamily("monospace").whiteSpace("pre-wrap")
|
|
34
|
-
.hsl(0, 0, 92).pad2(8, 4).borderRadius(4)
|
|
35
|
-
}>
|
|
36
|
-
{command}
|
|
37
|
-
</code>
|
|
38
|
-
</div>;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
@observer
|
|
43
|
-
class AccessPage extends preact.Component {
|
|
44
|
-
synced = observable({
|
|
45
|
-
account: "",
|
|
46
|
-
state: undefined as AccessState | undefined,
|
|
47
|
-
error: "",
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
componentDidMount() {
|
|
51
|
-
let account = decodeURIComponent(location.pathname.split("/")[1] || "");
|
|
52
|
-
this.synced.account = account;
|
|
53
|
-
if (!account) return;
|
|
54
|
-
void (async () => {
|
|
55
|
-
while (true) {
|
|
56
|
-
try {
|
|
57
|
-
await this.refresh(account);
|
|
58
|
-
} catch (e) {
|
|
59
|
-
this.synced.error = String(e);
|
|
60
|
-
}
|
|
61
|
-
if (this.synced.state?.hasAccess) break;
|
|
62
|
-
await new Promise(resolve => setTimeout(resolve, REFRESH_INTERVAL));
|
|
63
|
-
}
|
|
64
|
-
})();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
private authenticated = false;
|
|
68
|
-
private async controller() {
|
|
69
|
-
let address = location.hostname;
|
|
70
|
-
let port = +location.port || 443;
|
|
71
|
-
let nodeId = SocketFunction.connect({ address, port });
|
|
72
|
-
if (!this.authenticated) {
|
|
73
|
-
await authenticateStorage({ address, port, nodeId });
|
|
74
|
-
this.authenticated = true;
|
|
75
|
-
}
|
|
76
|
-
return RemoteStorageController.nodes[nodeId];
|
|
77
|
-
}
|
|
78
|
-
private async refresh(account: string) {
|
|
79
|
-
let controller = await this.controller();
|
|
80
|
-
this.synced.state = await controller.getAccessState({ account });
|
|
81
|
-
this.synced.error = "";
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
render() {
|
|
85
|
-
let synced = this.synced;
|
|
86
|
-
let { account, state, error } = synced;
|
|
87
|
-
if (!account) {
|
|
88
|
-
return <div className={css.vbox(8).pad2(16)}>
|
|
89
|
-
<div>Remote storage server.</div>
|
|
90
|
-
<div>Visit /(account name) to see whether this browser's machine has access to an account.</div>
|
|
91
|
-
</div>;
|
|
92
|
-
}
|
|
93
|
-
return <div className={css.vbox(12).pad2(16)}>
|
|
94
|
-
<div>Storage account: {account}</div>
|
|
95
|
-
{error && <div>Error: {error}</div>}
|
|
96
|
-
{!state && !error && <div>Checking access...</div>}
|
|
97
|
-
{state && !state.hasAccess && <div className={css.vbox(8)}>
|
|
98
|
-
<div>This machine ({state.machineId}, ip {state.ip}) does NOT have access.</div>
|
|
99
|
-
{state.reason && <div>{state.reason}</div>}
|
|
100
|
-
<div>Run this in the authorized_keys repo, on a machine with the signing key:</div>
|
|
101
|
-
{state.addMachineCommand && <CopyableCommand command={state.addMachineCommand} />}
|
|
102
|
-
<div>This page rechecks every {REFRESH_INTERVAL / 1000} seconds.</div>
|
|
103
|
-
</div>}
|
|
104
|
-
{state && state.hasAccess && <div className={css.vbox(16)}>
|
|
105
|
-
<div>This machine ({state.machineId}, ip {state.ip}) has access.</div>
|
|
106
|
-
<div className={css.vbox(6)}>
|
|
107
|
-
<div>Trusted machines:</div>
|
|
108
|
-
<table>
|
|
109
|
-
<thead>
|
|
110
|
-
<tr>
|
|
111
|
-
<th className={css.pad2(8, 2).textAlign("left")}>Machine</th>
|
|
112
|
-
<th className={css.pad2(8, 2).textAlign("left")}>Allowed from</th>
|
|
113
|
-
<th className={css.pad2(8, 2).textAlign("left")}>Added</th>
|
|
114
|
-
</tr>
|
|
115
|
-
</thead>
|
|
116
|
-
<tbody>
|
|
117
|
-
{(state.trustedMachines || []).map(m => <tr key={m.machineId}>
|
|
118
|
-
<td className={css.pad2(8, 2)}>{m.machineId}</td>
|
|
119
|
-
<td className={css.pad2(8, 2)}>{m.ips.join(", ")}</td>
|
|
120
|
-
<td className={css.pad2(8, 2)}>{m.addedAt}</td>
|
|
121
|
-
</tr>)}
|
|
122
|
-
</tbody>
|
|
123
|
-
</table>
|
|
124
|
-
</div>
|
|
125
|
-
</div>}
|
|
126
|
-
</div>;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
7
|
+
// The storage server's fallback page. There is no access-granting page any more: access errors in
|
|
8
|
+
// the console say exactly why a machine was refused and the addmachine command that fixes it. This
|
|
9
|
+
// only remains for the cert-trust flow (?trustCert=1, see certTrustModal.tsx).
|
|
129
10
|
|
|
130
11
|
// Reached via the cert-trust flow (showCertTrustModal links here as ?trustCert=1). The browser only loads this page if it has ACCEPTED the certificate - so the mere fact that it rendered is the confirmation. Once accepted, the app's background connection to this same server works, so the user just returns.
|
|
131
12
|
function CertTrustedPage() {
|
|
@@ -141,7 +22,10 @@ async function main() {
|
|
|
141
22
|
preact.render(<CertTrustedPage />, document.body);
|
|
142
23
|
return;
|
|
143
24
|
}
|
|
144
|
-
preact.render(<
|
|
25
|
+
preact.render(<div className={css.vbox(8).pad2(16)}>
|
|
26
|
+
<div>Remote storage server.</div>
|
|
27
|
+
<div>Access is granted by adding a machine to the authorized_keys repo (yarn addmachine). Denied requests print the exact command in their error.</div>
|
|
28
|
+
</div>, document.body);
|
|
145
29
|
}
|
|
146
30
|
|
|
147
31
|
main().catch(console.error);
|
|
@@ -23,9 +23,9 @@ export declare class ArchivesChain implements IArchives {
|
|
|
23
23
|
private prepareWrongTargetRetry;
|
|
24
24
|
private request;
|
|
25
25
|
waitingForAccess(): Promise<{
|
|
26
|
-
link: string;
|
|
27
26
|
machineId: string;
|
|
28
27
|
ip: string;
|
|
28
|
+
reason: string;
|
|
29
29
|
} | undefined>;
|
|
30
30
|
/** The sources that can serve a file right now, in dispatch order - the first is the write node, the one a plain read asks first. Each entry's url is what GetConfig.sourceUrl / GetInfoConfig.sourceUrl accept, so listing these and then reading with sourceUrl compares the copies the sources actually hold. */
|
|
31
31
|
getFileSources(fileName: string): Promise<SourceConfig[]>;
|
|
@@ -319,7 +319,7 @@ export class ArchivesChain implements IArchives {
|
|
|
319
319
|
return await this.run(state, config, run);
|
|
320
320
|
}
|
|
321
321
|
|
|
322
|
-
public async waitingForAccess(): Promise<{
|
|
322
|
+
public async waitingForAccess(): Promise<{ machineId: string; ip: string; reason: string } | undefined> {
|
|
323
323
|
let state = await this.state.getState();
|
|
324
324
|
for (let source of state.sources) {
|
|
325
325
|
// A source whose window has passed is never read or written again, so its access state is irrelevant - and asking a dead intermediate would just hang or throw. Future windows DO matter: access should be granted before their window starts.
|