sliftutils 1.7.129 → 1.7.130
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/misc/dist/ownIPs.ts.cache +30 -4
- package/misc/dist/strings.ts.cache +2 -2
- package/misc/https/dist/certs.ts.cache +2 -2
- package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
- package/misc/ownIPs.ts +29 -1
- package/package.json +1 -1
- package/security/authorizedKeys/daemon/dist/paths.ts.cache +3 -6
- package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
- package/security/authorizedKeys/daemon/dist/state.ts.cache +5 -3
- package/security/authorizedKeys/daemon/paths.ts +0 -3
- package/security/authorizedKeys/daemon/revocation.ts +0 -0
- package/security/authorizedKeys/daemon/state.ts +4 -8
- package/security/authorizedKeys/dist/keysRepo.ts.cache +111 -0
- package/security/authorizedKeys/dist/secureSSH.ts.cache +147 -71
- package/security/authorizedKeys/dist/unrevoke.ts.cache +70 -51
- package/security/authorizedKeys/keysRepo.ts +111 -0
- package/security/authorizedKeys/secureSSH.ts +28 -38
- package/security/authorizedKeys/unrevoke.ts +9 -36
- package/security/machines/addMachine.ts +4 -3
- package/security/machines/dist/identity.ts.cache +2 -2
- package/security/machines/dist/machines.ts.cache +36 -94
- package/security/machines/machines.ts +39 -90
- package/security/machines/trustServer.ts +5 -3
- package/security/notifications/dist/remoteWebhook.ts.cache +78 -0
- package/security/notifications/dist/setupNotify.ts.cache +39 -0
- package/security/signedFiles/dist/signFiles.ts.cache +8 -10
- package/security/signedFiles/signFiles.ts +6 -10
- package/security/machines/trustState.ts +0 -53
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "fs/promises";
|
|
2
2
|
import os from "os";
|
|
3
3
|
import path from "path";
|
|
4
|
-
import {
|
|
4
|
+
import { resolveKeysRepo } from "../authorizedKeys/keysRepo";
|
|
5
5
|
import { revokeRepo, syncRepoFiles } from "../authorizedKeys/daemon/repoFiles";
|
|
6
6
|
import { listRepoDir, readRepoFile } from "../authorizedKeys/daemon/repoFiles";
|
|
7
7
|
import { newRevocationId, pairKey, readRevocationFiles, readUnrevokes } from "../authorizedKeys/daemon/revocation";
|
|
@@ -9,10 +9,8 @@ import { runGit } from "../authorizedKeys/daemon/git";
|
|
|
9
9
|
import { ensureRevokeKey } from "../authorizedKeys/daemon/repoFiles";
|
|
10
10
|
import { verifyCheckout } from "../authorizedKeys/daemon/trust";
|
|
11
11
|
import { revokeRepoPath, revokeRepoURL } from "../authorizedKeys/revokeSource";
|
|
12
|
-
import { sourceRepoPath } from "../authorizedKeys/sources";
|
|
13
12
|
import { notify } from "../authorizedKeys/daemon/notify";
|
|
14
13
|
import { areDiscordNotificationsConfigured, configureDiscordNotifications, DEFAULT_WEBHOOK_FILE_PATH } from "../notifications/discord";
|
|
15
|
-
import { unrevokeInEffect } from "./trustState";
|
|
16
14
|
import { spawnPromise } from "../helpers/spawn";
|
|
17
15
|
|
|
18
16
|
// Which machines this system talks to, kept in the same repo as the ssh keys. That repo is already
|
|
@@ -24,9 +22,6 @@ const REVOCATION_REASON = "a machine talked to us from an unapproved IP";
|
|
|
24
22
|
// The revoke repo is pulled at most this often. A check happens per request, and a request must
|
|
25
23
|
// not cost a round trip to github.
|
|
26
24
|
const REVOKE_SYNC_INTERVAL = 60 * 1000;
|
|
27
|
-
// Where a Windows machine is expected to keep the repo, relative to the working directory. There
|
|
28
|
-
// is no daemon there to ask, and no /etc to look in.
|
|
29
|
-
const WINDOWS_REPO_PATH = "../authorized_keys";
|
|
30
25
|
|
|
31
26
|
/** One machine we are willing to talk to, and the addresses it may talk to us from. */
|
|
32
27
|
export type MachineState = {
|
|
@@ -48,27 +43,27 @@ function machineFilePath(repoPath: string, machineId: string) {
|
|
|
48
43
|
return path.join(repoPath, MACHINES_DIR, `${machineId}.json`);
|
|
49
44
|
}
|
|
50
45
|
|
|
51
|
-
/**
|
|
46
|
+
/** Every machine a checkout lists. */
|
|
47
|
+
export async function getMachines(repoPath: string): Promise<MachineState[]> {
|
|
48
|
+
return [...(await readMachines(repoPath)).values()];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Makes a checkout list exactly these machines: those named are written with the addresses given,
|
|
52
|
+
and anything not named is removed. So read them, change what you want, and write the result.
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
machine we would accept anyway, so there is no state where naming one without them means
|
|
57
|
-
anything. Read first, change what you want, write the result.
|
|
54
|
+
The addresses are part of setting rather than a separate step, because a machine with no
|
|
55
|
+
address it may talk from is not a machine that would ever be accepted - there is no state where
|
|
56
|
+
naming one without them means anything.
|
|
58
57
|
|
|
59
|
-
Nothing here signs or commits
|
|
58
|
+
Nothing here signs or commits. The signature is what every other machine checks before
|
|
60
59
|
believing any of this, and it takes the hardware key, so `yarn signfiles git` is still yours to
|
|
61
60
|
run afterwards. */
|
|
62
|
-
export async function
|
|
61
|
+
export async function setMachines(config: {
|
|
63
62
|
repoPath: string;
|
|
64
|
-
machines
|
|
63
|
+
machines: { machineId: string; ips: string[] }[];
|
|
65
64
|
}): Promise<MachineState[]> {
|
|
66
65
|
let { repoPath, machines } = config;
|
|
67
66
|
let existing = await readMachines(repoPath);
|
|
68
|
-
if (!machines) {
|
|
69
|
-
return [...existing.values()];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
67
|
let directory = path.join(repoPath, MACHINES_DIR);
|
|
73
68
|
let written: MachineState[] = [];
|
|
74
69
|
for (let machine of machines) {
|
|
@@ -122,61 +117,6 @@ async function readMachines(repoPath: string) {
|
|
|
122
117
|
return machines;
|
|
123
118
|
}
|
|
124
119
|
|
|
125
|
-
async function isKeysRepo(repoPath: string) {
|
|
126
|
-
return await pathExists(path.join(repoPath, ".git"))
|
|
127
|
-
&& await pathExists(path.join(repoPath, "authorized_keys"));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function originOf(repoPath: string) {
|
|
131
|
-
let origin = await spawnPromise({ command: "git", args: ["remote", "get-url", "origin"], cwd: repoPath });
|
|
132
|
-
let url = origin.stdout.trim();
|
|
133
|
-
if (origin.status !== 0 || !url) {
|
|
134
|
-
throw new Error(`Expected ${repoPath} to have an origin remote, it has none`);
|
|
135
|
-
}
|
|
136
|
-
return url;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/** The keys repo this machine answers from, and the one anything editing the machine list edits.
|
|
140
|
-
|
|
141
|
-
On a host, that is the checkout the daemon already keeps up to date. On Windows there is no
|
|
142
|
-
daemon and no /etc, so the repo is expected beside the working directory, which is where a
|
|
143
|
-
developer working on both would have it.
|
|
144
|
-
|
|
145
|
-
Never the directory the command happens to be run from. Which repo this machine trusts is a
|
|
146
|
-
property of the machine, not of where somebody was standing when they typed something. */
|
|
147
|
-
export async function resolveKeysRepo() {
|
|
148
|
-
if (os.platform() === "win32") {
|
|
149
|
-
let repoPath = path.resolve(WINDOWS_REPO_PATH);
|
|
150
|
-
if (!await isKeysRepo(repoPath)) {
|
|
151
|
-
throw new Error(
|
|
152
|
-
`Expected ${repoPath} to be an authorized_keys repo, it is not.\n`
|
|
153
|
-
+ `On Windows the repo is read from there, so clone it beside this one:\n`
|
|
154
|
-
+ ` git clone <your authorized_keys repo> ${repoPath}`
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
return { repoPath, sourceURL: await originOf(repoPath) };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
let config = await fs.readFile(CONFIG_PATH, "utf8").catch(() => "");
|
|
161
|
-
let sourceURL = config && (JSON.parse(config).repoSources || [])[0] || "";
|
|
162
|
-
if (!sourceURL) {
|
|
163
|
-
throw new Error(
|
|
164
|
-
`Expected this machine to be set up with an authorized_keys repo, ${CONFIG_PATH} names none.\n`
|
|
165
|
-
+ `Set it up first:\n`
|
|
166
|
-
+ ` yarn setupnotify <discord-webhook-url>\n`
|
|
167
|
-
+ ` yarn securessh add <repo-private-key> <repo-url>`
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
let repoPath = sourceRepoPath(sourceURL);
|
|
171
|
-
if (!await isKeysRepo(repoPath)) {
|
|
172
|
-
throw new Error(
|
|
173
|
-
`Expected a checkout of ${sourceURL} at ${repoPath}, there is none.\n`
|
|
174
|
-
+ `Run \`yarn securessh update\` to put it back.`
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
return { repoPath, sourceURL };
|
|
178
|
-
}
|
|
179
|
-
|
|
180
120
|
let lastRevokeSync = 0;
|
|
181
121
|
|
|
182
122
|
/** Pulled at most once a REVOKE_SYNC_INTERVAL, because this is asked per request. A sync that
|
|
@@ -285,7 +225,7 @@ async function recordMachineRevocation(config: {
|
|
|
285
225
|
+ `\n\nIt is frozen everywhere now, and nothing accepts it.`
|
|
286
226
|
+ `\n\nIf this was an attack, remove \`machines/${machineId}.json\` from \`${sourceURL}\` now.`
|
|
287
227
|
+ `\nIf it was legitimate, run \`yarn unrevoke git\` in that repo. It allows ${ip} for that`
|
|
288
|
-
+ ` machine, and takes
|
|
228
|
+
+ ` machine, and takes effect as each machine picks it up.`
|
|
289
229
|
+ `\n\nmachine: \`${machineId}\``
|
|
290
230
|
+ `\nfrozen by: \`${hostLabel}\``
|
|
291
231
|
);
|
|
@@ -299,9 +239,15 @@ async function recordMachineRevocation(config: {
|
|
|
299
239
|
have, is treated as the same kind of event as a stolen ssh key - it is revoked everywhere, and
|
|
300
240
|
stays revoked until an unrevoke allows that machine from that address.
|
|
301
241
|
|
|
242
|
+
Says why when the answer is no, because the three ways to be refused are entirely different
|
|
243
|
+
things to a person reading it: never trusted at all, trusted but frozen, or trusted and talking
|
|
244
|
+
from somewhere it should not be.
|
|
245
|
+
|
|
302
246
|
Throws when the repo itself cannot be read or is not signed, rather than answering false: that
|
|
303
247
|
is a broken installation, not a rejected machine, and the two deserve different handling. */
|
|
304
|
-
export
|
|
248
|
+
export type MachineVerdict = { accepted: boolean; reason: string };
|
|
249
|
+
|
|
250
|
+
export async function isMachineAccepted(config: { machineId: string; ip: string }): Promise<MachineVerdict> {
|
|
305
251
|
let { machineId, ip } = config;
|
|
306
252
|
if (!machineId || !ip) {
|
|
307
253
|
throw new Error(`Expected a machineId and an ip, was ${JSON.stringify(machineId)} and ${JSON.stringify(ip)}`);
|
|
@@ -313,34 +259,36 @@ export async function isMachineAccepted(config: { machineId: string; ip: string
|
|
|
313
259
|
|
|
314
260
|
let machine = (await readMachines(repoPath)).get(machineId);
|
|
315
261
|
if (!machine) {
|
|
316
|
-
return false;
|
|
262
|
+
return { accepted: false, reason: "that machine is not trusted" };
|
|
317
263
|
}
|
|
318
264
|
|
|
319
265
|
await syncRevocations(sourceURL);
|
|
320
266
|
let unrevokes = await readUnrevokes(sourceURL).catch(() => ({ pairs: new Map(), legacyIds: new Map() }));
|
|
321
|
-
// An unrevoke
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
};
|
|
267
|
+
// An unrevoke counts as soon as it is seen. It is signed, so writing one already takes the
|
|
268
|
+
// hardware key, and anyone holding that can sign anything at all - a wait before honouring it
|
|
269
|
+
// guards against an attacker who has no need of it.
|
|
270
|
+
let allowedAgain = (pair: string) => !!unrevokes.pairs.get(pair)?.length;
|
|
326
271
|
let revocations = await readMachineRevocations(sourceURL);
|
|
327
272
|
// Any revocation nothing has undone keeps the machine out, from everywhere, the way a revoked
|
|
328
273
|
// ssh key is out everywhere rather than only from the address it was misused from.
|
|
329
|
-
let
|
|
274
|
+
let frozenFrom = "";
|
|
330
275
|
for (let revocation of revocations) {
|
|
331
276
|
if (revocation.machineId !== machineId) {
|
|
332
277
|
continue;
|
|
333
278
|
}
|
|
334
|
-
if (!
|
|
335
|
-
|
|
279
|
+
if (!allowedAgain(pairKey({ fingerprint: revocation.machineId, ip: revocation.ip }))) {
|
|
280
|
+
frozenFrom = revocation.ip;
|
|
336
281
|
}
|
|
337
282
|
}
|
|
338
|
-
if (
|
|
339
|
-
return
|
|
283
|
+
if (frozenFrom) {
|
|
284
|
+
return {
|
|
285
|
+
accepted: false,
|
|
286
|
+
reason: `that machine is frozen, it was used from ${frozenFrom} which it is not allowed from`,
|
|
287
|
+
};
|
|
340
288
|
}
|
|
341
289
|
|
|
342
290
|
if (machine.ips.includes(ip)) {
|
|
343
|
-
return true;
|
|
291
|
+
return { accepted: true, reason: "" };
|
|
344
292
|
}
|
|
345
293
|
|
|
346
294
|
// Listed, but talking to us from somewhere it should not be. Recorded once for this machine
|
|
@@ -348,8 +296,9 @@ export async function isMachineAccepted(config: { machineId: string; ip: string
|
|
|
348
296
|
let pair = pairKey({ fingerprint: machineId, ip });
|
|
349
297
|
let alreadyRecorded = revocations.some(revocation =>
|
|
350
298
|
pairKey({ fingerprint: revocation.machineId, ip: revocation.ip }) === pair);
|
|
351
|
-
if (!alreadyRecorded && !
|
|
299
|
+
if (!alreadyRecorded && !allowedAgain(pair)) {
|
|
352
300
|
await recordMachineRevocation({ sourceURL, machineId, ip, hostLabel: os.hostname() });
|
|
301
|
+
return { accepted: false, reason: `that machine is not allowed from ${ip}, so it is now frozen everywhere` };
|
|
353
302
|
}
|
|
354
|
-
return false;
|
|
303
|
+
return { accepted: false, reason: `that machine is not allowed from ${ip}` };
|
|
355
304
|
}
|
|
@@ -47,14 +47,16 @@ export function startTrustServer(config: { port: number }) {
|
|
|
47
47
|
// Not a rejection of the machine, a packet that does not prove anything about one.
|
|
48
48
|
return { status: 400, body: { trusted: false, ip, reason: verified.problem } };
|
|
49
49
|
}
|
|
50
|
-
let
|
|
50
|
+
let verdict = await isMachineAccepted({ machineId: packet.machineId, ip });
|
|
51
51
|
return {
|
|
52
52
|
status: 200,
|
|
53
53
|
body: {
|
|
54
|
-
trusted,
|
|
54
|
+
trusted: verdict.accepted,
|
|
55
55
|
machineId: packet.machineId,
|
|
56
56
|
ip,
|
|
57
|
-
|
|
57
|
+
// Whatever the check itself said. It is the only thing that knows which of the
|
|
58
|
+
// ways to be refused this was.
|
|
59
|
+
reason: verdict.reason,
|
|
58
60
|
},
|
|
59
61
|
};
|
|
60
62
|
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
+
//exports.ensureRemoteWebhook = exports.REPLACE_KEYWORD = void 0;
|
|
4
|
+
const discord_1 = require("./discord");
|
|
5
|
+
const remoteSSH_1 = require("../helpers/remoteSSH");
|
|
6
|
+
exports.REPLACE_KEYWORD = "replace";
|
|
7
|
+
const UNPARSEABLE_LABEL = "(unparseable)";
|
|
8
|
+
/** Puts a webhook on a remote host, refusing to clobber a different existing one unless asked.
|
|
9
|
+
Returns what happened, so callers can decide whether to keep going. */
|
|
10
|
+
async function ensureRemoteWebhook(config) {
|
|
11
|
+
let { host, webhookURL, replace } = config;
|
|
12
|
+
let filePath = config.filePath || discord_1.DEFAULT_WEBHOOK_FILE_PATH;
|
|
13
|
+
let replacedURL = "";
|
|
14
|
+
let existingContents = await (0, remoteSSH_1.readRemoteFile)({ host, filePath });
|
|
15
|
+
if (existingContents) {
|
|
16
|
+
// A corrupt existing file still counts as a conflict, so "replace" can repair it instead
|
|
17
|
+
// of the setup dead ending on a parse error.
|
|
18
|
+
let existingURL = UNPARSEABLE_LABEL;
|
|
19
|
+
try {
|
|
20
|
+
existingURL = (0, discord_1.parseWebhookFile)({ contents: existingContents, sourceName: `${host}:${filePath}` });
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
console.error(`${host}:${filePath} exists but could not be parsed. ${e}`);
|
|
24
|
+
}
|
|
25
|
+
if (existingURL === webhookURL) {
|
|
26
|
+
return { outcome: "unchanged", filePath };
|
|
27
|
+
}
|
|
28
|
+
if (!replace) {
|
|
29
|
+
throw new Error(`Expected no conflicting webhook on ${host}, but ${filePath} already holds a different one.\n`
|
|
30
|
+
+ `Existing: ${existingURL}\n`
|
|
31
|
+
+ `New: ${webhookURL}\n`
|
|
32
|
+
+ `Pass "${exports.REPLACE_KEYWORD}" to overwrite it.`);
|
|
33
|
+
}
|
|
34
|
+
replacedURL = existingURL;
|
|
35
|
+
}
|
|
36
|
+
await (0, remoteSSH_1.writeRemoteFile)({
|
|
37
|
+
host,
|
|
38
|
+
filePath,
|
|
39
|
+
contents: (0, discord_1.formatWebhookFile)(webhookURL),
|
|
40
|
+
fileMode: "600",
|
|
41
|
+
directoryMode: "700",
|
|
42
|
+
});
|
|
43
|
+
let writtenContents = await (0, remoteSSH_1.readRemoteFile)({ host, filePath });
|
|
44
|
+
if (!writtenContents) {
|
|
45
|
+
throw new Error(`Expected ${filePath} to exist on ${host} after writing, no such file exists`);
|
|
46
|
+
}
|
|
47
|
+
let writtenURL = (0, discord_1.parseWebhookFile)({ contents: writtenContents, sourceName: `${host}:${filePath}` });
|
|
48
|
+
if (writtenURL !== webhookURL) {
|
|
49
|
+
throw new Error(`Expected ${host}:${filePath} to hold the new webhook, was ${writtenURL}`);
|
|
50
|
+
}
|
|
51
|
+
if (replacedURL && replacedURL !== UNPARSEABLE_LABEL) {
|
|
52
|
+
// The new webhook is redacted, so this channel can identify the replacement without
|
|
53
|
+
// receiving a webhook it could post to.
|
|
54
|
+
try {
|
|
55
|
+
await (0, discord_1.sendToWebhookURL)({
|
|
56
|
+
webhookURL: replacedURL,
|
|
57
|
+
message: `**portsecure**: the Discord webhook for \`${host}\` was replaced with`
|
|
58
|
+
+ ` \`${(0, discord_1.redactWebhookURL)(webhookURL)}\`.`
|
|
59
|
+
+ ` This channel will stop receiving notifications for that host.`,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
// The replacement already happened, so a dead old webhook must not fail the setup.
|
|
64
|
+
console.error(`Could not notify the old webhook that it was replaced. ${e}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// Failing here means the file is in place but the webhook itself does not work, which is
|
|
68
|
+
// exactly what the operator needs to hear about.
|
|
69
|
+
await (0, discord_1.sendToWebhookURL)({
|
|
70
|
+
webhookURL,
|
|
71
|
+
message: `**portsecure**: notifications are now configured for \`${host}\`.`
|
|
72
|
+
+ ` This channel will receive its security notifications.`,
|
|
73
|
+
});
|
|
74
|
+
return { outcome: replacedURL && "replaced" || "created", filePath };
|
|
75
|
+
}
|
|
76
|
+
exports.ensureRemoteWebhook = ensureRemoteWebhook;
|
|
77
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVtb3RlV2ViaG9vay5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJlbW90ZVdlYmhvb2sudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdUNBQStIO0FBQy9ILG9EQUF1RTtBQUUxRCxRQUFBLGVBQWUsR0FBRyxTQUFTLENBQUM7QUFDekMsTUFBTSxpQkFBaUIsR0FBRyxlQUFlLENBQUM7QUFFMUM7MEVBQzBFO0FBQ25FLEtBQUssVUFBVSxtQkFBbUIsQ0FBQyxNQUt6QztJQUNHLElBQUksRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUMzQyxJQUFJLFFBQVEsR0FBRyxNQUFNLENBQUMsUUFBUSxJQUFJLG1DQUF5QixDQUFDO0lBRTVELElBQUksV0FBVyxHQUFHLEVBQUUsQ0FBQztJQUNyQixJQUFJLGdCQUFnQixHQUFHLE1BQU0sSUFBQSwwQkFBYyxFQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDaEUsSUFBSSxnQkFBZ0IsRUFBRSxDQUFDO1FBQ25CLHlGQUF5RjtRQUN6Riw2Q0FBNkM7UUFDN0MsSUFBSSxXQUFXLEdBQUcsaUJBQWlCLENBQUM7UUFDcEMsSUFBSSxDQUFDO1lBQ0QsV0FBVyxHQUFHLElBQUEsMEJBQWdCLEVBQUMsRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBSSxJQUFJLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUN0RyxDQUFDO1FBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztZQUNULE9BQU8sQ0FBQyxLQUFLLENBQUMsR0FBRyxJQUFJLElBQUksUUFBUSxvQ0FBb0MsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUM5RSxDQUFDO1FBQ0QsSUFBSSxXQUFXLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDN0IsT0FBTyxFQUFFLE9BQU8sRUFBRSxXQUFvQixFQUFFLFFBQVEsRUFBRSxDQUFDO1FBQ3ZELENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDWCxNQUFNLElBQUksS0FBSyxDQUNYLHNDQUFzQyxJQUFJLFNBQVMsUUFBUSxtQ0FBbUM7a0JBQzVGLGFBQWEsV0FBVyxJQUFJO2tCQUM1QixhQUFhLFVBQVUsSUFBSTtrQkFDM0IsU0FBUyx1QkFBZSxvQkFBb0IsQ0FDakQsQ0FBQztRQUNOLENBQUM7UUFDRCxXQUFXLEdBQUcsV0FBVyxDQUFDO0lBQzlCLENBQUM7SUFFRCxNQUFNLElBQUEsMkJBQWUsRUFBQztRQUNsQixJQUFJO1FBQ0osUUFBUTtRQUNSLFFBQVEsRUFBRSxJQUFBLDJCQUFpQixFQUFDLFVBQVUsQ0FBQztRQUN2QyxRQUFRLEVBQUUsS0FBSztRQUNmLGFBQWEsRUFBRSxLQUFLO0tBQ3ZCLENBQUMsQ0FBQztJQUVILElBQUksZUFBZSxHQUFHLE1BQU0sSUFBQSwwQkFBYyxFQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDL0QsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMsWUFBWSxRQUFRLGdCQUFnQixJQUFJLHFDQUFxQyxDQUFDLENBQUM7SUFDbkcsQ0FBQztJQUNELElBQUksVUFBVSxHQUFHLElBQUEsMEJBQWdCLEVBQUMsRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLFVBQVUsRUFBRSxHQUFHLElBQUksSUFBSSxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEcsSUFBSSxVQUFVLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FBQyxZQUFZLElBQUksSUFBSSxRQUFRLGlDQUFpQyxVQUFVLEVBQUUsQ0FBQyxDQUFDO0lBQy9GLENBQUM7SUFFRCxJQUFJLFdBQVcsSUFBSSxXQUFXLEtBQUssaUJBQWlCLEVBQUUsQ0FBQztRQUNuRCxvRkFBb0Y7UUFDcEYsd0NBQXdDO1FBQ3hDLElBQUksQ0FBQztZQUNELE1BQU0sSUFBQSwwQkFBZ0IsRUFBQztnQkFDbkIsVUFBVSxFQUFFLFdBQVc7Z0JBQ3ZCLE9BQU8sRUFBRSw2Q0FBNkMsSUFBSSxzQkFBc0I7c0JBQzFFLE1BQU0sSUFBQSwwQkFBZ0IsRUFBQyxVQUFVLENBQUMsS0FBSztzQkFDdkMsZ0VBQWdFO2FBQ3pFLENBQUMsQ0FBQztRQUNQLENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1QsbUZBQW1GO1lBQ25GLE9BQU8sQ0FBQyxLQUFLLENBQUMsMERBQTBELENBQUMsRUFBRSxDQUFDLENBQUM7UUFDakYsQ0FBQztJQUNMLENBQUM7SUFFRCx5RkFBeUY7SUFDekYsaURBQWlEO0lBQ2pELE1BQU0sSUFBQSwwQkFBZ0IsRUFBQztRQUNuQixVQUFVO1FBQ1YsT0FBTyxFQUFFLDBEQUEwRCxJQUFJLEtBQUs7Y0FDdEUsd0RBQXdEO0tBQ2pFLENBQUMsQ0FBQztJQUVILE9BQU8sRUFBRSxPQUFPLEVBQUUsV0FBVyxJQUFJLFVBQW1CLElBQUksU0FBa0IsRUFBRSxRQUFRLEVBQUUsQ0FBQztBQUMzRixDQUFDO0FBNUVELGtEQTRFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERFRkFVTFRfV0VCSE9PS19GSUxFX1BBVEgsIGZvcm1hdFdlYmhvb2tGaWxlLCBwYXJzZVdlYmhvb2tGaWxlLCByZWRhY3RXZWJob29rVVJMLCBzZW5kVG9XZWJob29rVVJMIH0gZnJvbSBcIi4vZGlzY29yZFwiO1xuaW1wb3J0IHsgcmVhZFJlbW90ZUZpbGUsIHdyaXRlUmVtb3RlRmlsZSB9IGZyb20gXCIuLi9oZWxwZXJzL3JlbW90ZVNTSFwiO1xuXG5leHBvcnQgY29uc3QgUkVQTEFDRV9LRVlXT1JEID0gXCJyZXBsYWNlXCI7XG5jb25zdCBVTlBBUlNFQUJMRV9MQUJFTCA9IFwiKHVucGFyc2VhYmxlKVwiO1xuXG4vKiogUHV0cyBhIHdlYmhvb2sgb24gYSByZW1vdGUgaG9zdCwgcmVmdXNpbmcgdG8gY2xvYmJlciBhIGRpZmZlcmVudCBleGlzdGluZyBvbmUgdW5sZXNzIGFza2VkLlxuICAgIFJldHVybnMgd2hhdCBoYXBwZW5lZCwgc28gY2FsbGVycyBjYW4gZGVjaWRlIHdoZXRoZXIgdG8ga2VlcCBnb2luZy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbnN1cmVSZW1vdGVXZWJob29rKGNvbmZpZzoge1xuICAgIGhvc3Q6IHN0cmluZztcbiAgICB3ZWJob29rVVJMOiBzdHJpbmc7XG4gICAgcmVwbGFjZTogYm9vbGVhbjtcbiAgICBmaWxlUGF0aD86IHN0cmluZztcbn0pIHtcbiAgICBsZXQgeyBob3N0LCB3ZWJob29rVVJMLCByZXBsYWNlIH0gPSBjb25maWc7XG4gICAgbGV0IGZpbGVQYXRoID0gY29uZmlnLmZpbGVQYXRoIHx8IERFRkFVTFRfV0VCSE9PS19GSUxFX1BBVEg7XG5cbiAgICBsZXQgcmVwbGFjZWRVUkwgPSBcIlwiO1xuICAgIGxldCBleGlzdGluZ0NvbnRlbnRzID0gYXdhaXQgcmVhZFJlbW90ZUZpbGUoeyBob3N0LCBmaWxlUGF0aCB9KTtcbiAgICBpZiAoZXhpc3RpbmdDb250ZW50cykge1xuICAgICAgICAvLyBBIGNvcnJ1cHQgZXhpc3RpbmcgZmlsZSBzdGlsbCBjb3VudHMgYXMgYSBjb25mbGljdCwgc28gXCJyZXBsYWNlXCIgY2FuIHJlcGFpciBpdCBpbnN0ZWFkXG4gICAgICAgIC8vIG9mIHRoZSBzZXR1cCBkZWFkIGVuZGluZyBvbiBhIHBhcnNlIGVycm9yLlxuICAgICAgICBsZXQgZXhpc3RpbmdVUkwgPSBVTlBBUlNFQUJMRV9MQUJFTDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGV4aXN0aW5nVVJMID0gcGFyc2VXZWJob29rRmlsZSh7IGNvbnRlbnRzOiBleGlzdGluZ0NvbnRlbnRzLCBzb3VyY2VOYW1lOiBgJHtob3N0fToke2ZpbGVQYXRofWAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoYCR7aG9zdH06JHtmaWxlUGF0aH0gZXhpc3RzIGJ1dCBjb3VsZCBub3QgYmUgcGFyc2VkLiAke2V9YCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGV4aXN0aW5nVVJMID09PSB3ZWJob29rVVJMKSB7XG4gICAgICAgICAgICByZXR1cm4geyBvdXRjb21lOiBcInVuY2hhbmdlZFwiIGFzIGNvbnN0LCBmaWxlUGF0aCB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICghcmVwbGFjZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgIGBFeHBlY3RlZCBubyBjb25mbGljdGluZyB3ZWJob29rIG9uICR7aG9zdH0sIGJ1dCAke2ZpbGVQYXRofSBhbHJlYWR5IGhvbGRzIGEgZGlmZmVyZW50IG9uZS5cXG5gXG4gICAgICAgICAgICAgICAgKyBgRXhpc3Rpbmc6ICR7ZXhpc3RpbmdVUkx9XFxuYFxuICAgICAgICAgICAgICAgICsgYE5ldzogICAgICAke3dlYmhvb2tVUkx9XFxuYFxuICAgICAgICAgICAgICAgICsgYFBhc3MgXCIke1JFUExBQ0VfS0VZV09SRH1cIiB0byBvdmVyd3JpdGUgaXQuYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgICByZXBsYWNlZFVSTCA9IGV4aXN0aW5nVVJMO1xuICAgIH1cblxuICAgIGF3YWl0IHdyaXRlUmVtb3RlRmlsZSh7XG4gICAgICAgIGhvc3QsXG4gICAgICAgIGZpbGVQYXRoLFxuICAgICAgICBjb250ZW50czogZm9ybWF0V2ViaG9va0ZpbGUod2ViaG9va1VSTCksXG4gICAgICAgIGZpbGVNb2RlOiBcIjYwMFwiLFxuICAgICAgICBkaXJlY3RvcnlNb2RlOiBcIjcwMFwiLFxuICAgIH0pO1xuXG4gICAgbGV0IHdyaXR0ZW5Db250ZW50cyA9IGF3YWl0IHJlYWRSZW1vdGVGaWxlKHsgaG9zdCwgZmlsZVBhdGggfSk7XG4gICAgaWYgKCF3cml0dGVuQ29udGVudHMpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCAke2ZpbGVQYXRofSB0byBleGlzdCBvbiAke2hvc3R9IGFmdGVyIHdyaXRpbmcsIG5vIHN1Y2ggZmlsZSBleGlzdHNgKTtcbiAgICB9XG4gICAgbGV0IHdyaXR0ZW5VUkwgPSBwYXJzZVdlYmhvb2tGaWxlKHsgY29udGVudHM6IHdyaXR0ZW5Db250ZW50cywgc291cmNlTmFtZTogYCR7aG9zdH06JHtmaWxlUGF0aH1gIH0pO1xuICAgIGlmICh3cml0dGVuVVJMICE9PSB3ZWJob29rVVJMKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgJHtob3N0fToke2ZpbGVQYXRofSB0byBob2xkIHRoZSBuZXcgd2ViaG9vaywgd2FzICR7d3JpdHRlblVSTH1gKTtcbiAgICB9XG5cbiAgICBpZiAocmVwbGFjZWRVUkwgJiYgcmVwbGFjZWRVUkwgIT09IFVOUEFSU0VBQkxFX0xBQkVMKSB7XG4gICAgICAgIC8vIFRoZSBuZXcgd2ViaG9vayBpcyByZWRhY3RlZCwgc28gdGhpcyBjaGFubmVsIGNhbiBpZGVudGlmeSB0aGUgcmVwbGFjZW1lbnQgd2l0aG91dFxuICAgICAgICAvLyByZWNlaXZpbmcgYSB3ZWJob29rIGl0IGNvdWxkIHBvc3QgdG8uXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBzZW5kVG9XZWJob29rVVJMKHtcbiAgICAgICAgICAgICAgICB3ZWJob29rVVJMOiByZXBsYWNlZFVSTCxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgKipwb3J0c2VjdXJlKio6IHRoZSBEaXNjb3JkIHdlYmhvb2sgZm9yIFxcYCR7aG9zdH1cXGAgd2FzIHJlcGxhY2VkIHdpdGhgXG4gICAgICAgICAgICAgICAgICAgICsgYCBcXGAke3JlZGFjdFdlYmhvb2tVUkwod2ViaG9va1VSTCl9XFxgLmBcbiAgICAgICAgICAgICAgICAgICAgKyBgIFRoaXMgY2hhbm5lbCB3aWxsIHN0b3AgcmVjZWl2aW5nIG5vdGlmaWNhdGlvbnMgZm9yIHRoYXQgaG9zdC5gLFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIC8vIFRoZSByZXBsYWNlbWVudCBhbHJlYWR5IGhhcHBlbmVkLCBzbyBhIGRlYWQgb2xkIHdlYmhvb2sgbXVzdCBub3QgZmFpbCB0aGUgc2V0dXAuXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKGBDb3VsZCBub3Qgbm90aWZ5IHRoZSBvbGQgd2ViaG9vayB0aGF0IGl0IHdhcyByZXBsYWNlZC4gJHtlfWApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gRmFpbGluZyBoZXJlIG1lYW5zIHRoZSBmaWxlIGlzIGluIHBsYWNlIGJ1dCB0aGUgd2ViaG9vayBpdHNlbGYgZG9lcyBub3Qgd29yaywgd2hpY2ggaXNcbiAgICAvLyBleGFjdGx5IHdoYXQgdGhlIG9wZXJhdG9yIG5lZWRzIHRvIGhlYXIgYWJvdXQuXG4gICAgYXdhaXQgc2VuZFRvV2ViaG9va1VSTCh7XG4gICAgICAgIHdlYmhvb2tVUkwsXG4gICAgICAgIG1lc3NhZ2U6IGAqKnBvcnRzZWN1cmUqKjogbm90aWZpY2F0aW9ucyBhcmUgbm93IGNvbmZpZ3VyZWQgZm9yIFxcYCR7aG9zdH1cXGAuYFxuICAgICAgICAgICAgKyBgIFRoaXMgY2hhbm5lbCB3aWxsIHJlY2VpdmUgaXRzIHNlY3VyaXR5IG5vdGlmaWNhdGlvbnMuYCxcbiAgICB9KTtcblxuICAgIHJldHVybiB7IG91dGNvbWU6IHJlcGxhY2VkVVJMICYmIFwicmVwbGFjZWRcIiBhcyBjb25zdCB8fCBcImNyZWF0ZWRcIiBhcyBjb25zdCwgZmlsZVBhdGggfTtcbn1cbiJdfQ==
|
|
78
|
+
/* _JS_SOURCE_HASH = "7383d5b5b9fee5c3deb4ea3e75d9c556e64aef84ab8d71e7683a02bc87c5070a"; */
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
|
|
3
|
+
//exports.main = void 0;
|
|
4
|
+
const discord_1 = require("./discord");
|
|
5
|
+
const remoteWebhook_1 = require("./remoteWebhook");
|
|
6
|
+
const remoteSSH_1 = require("../helpers/remoteSSH");
|
|
7
|
+
const USAGE = `Usage: yarn setupnotify [host] <discord-webhook-url> [${remoteWebhook_1.REPLACE_KEYWORD}]
|
|
8
|
+
|
|
9
|
+
With no host it sets the webhook up on this machine.`;
|
|
10
|
+
function parseArgs(argv) {
|
|
11
|
+
let replace = argv.includes(remoteWebhook_1.REPLACE_KEYWORD);
|
|
12
|
+
let positional = argv.filter(arg => arg !== remoteWebhook_1.REPLACE_KEYWORD);
|
|
13
|
+
if (!positional.length || positional.length > 2) {
|
|
14
|
+
throw new Error(`Expected a webhook URL, and optionally a host before it, was ${positional.length}`
|
|
15
|
+
+ ` argument(s): ${positional.join(" ") || "(none)"}\n${USAGE}`);
|
|
16
|
+
}
|
|
17
|
+
// The webhook url is the last one, so whatever comes before it is the host. Without one this
|
|
18
|
+
// machine is the target.
|
|
19
|
+
let webhookURL = positional[positional.length - 1];
|
|
20
|
+
let host = positional.length > 1 && positional[0] || remoteSSH_1.THIS_MACHINE;
|
|
21
|
+
// Validates the URL shape up front, so we never go anywhere with a bad webhook.
|
|
22
|
+
(0, discord_1.parseWebhookFile)({ contents: webhookURL, sourceName: "the command line" });
|
|
23
|
+
return { host, webhookURL, replace };
|
|
24
|
+
}
|
|
25
|
+
async function main() {
|
|
26
|
+
let { host, webhookURL, replace } = parseArgs(process.argv.slice(2));
|
|
27
|
+
let { outcome, filePath } = await (0, remoteWebhook_1.ensureRemoteWebhook)({ host, webhookURL, replace });
|
|
28
|
+
if (outcome === "unchanged") {
|
|
29
|
+
console.log(`${(0, remoteSSH_1.describeHost)(host)} already has this exact webhook in ${filePath}, nothing to do.`);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (outcome === "replaced") {
|
|
33
|
+
console.log(`Replaced the webhook on ${(0, remoteSSH_1.describeHost)(host)} and notified the old one.`);
|
|
34
|
+
}
|
|
35
|
+
console.log(`Wrote ${filePath} on ${(0, remoteSSH_1.describeHost)(host)} (mode 600), and confirmed on the new webhook.`);
|
|
36
|
+
}
|
|
37
|
+
exports.main = main;
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2V0dXBOb3RpZnkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZXR1cE5vdGlmeS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx1Q0FBNkM7QUFDN0MsbURBQXVFO0FBQ3ZFLG9EQUFrRTtBQUVsRSxNQUFNLEtBQUssR0FBRyx5REFBeUQsK0JBQWU7O3FEQUVqQyxDQUFDO0FBRXRELFNBQVMsU0FBUyxDQUFDLElBQWM7SUFDN0IsSUFBSSxPQUFPLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQywrQkFBZSxDQUFDLENBQUM7SUFDN0MsSUFBSSxVQUFVLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsS0FBSywrQkFBZSxDQUFDLENBQUM7SUFDN0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLElBQUksVUFBVSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUM5QyxNQUFNLElBQUksS0FBSyxDQUNYLGdFQUFnRSxVQUFVLENBQUMsTUFBTSxFQUFFO2NBQ2pGLGlCQUFpQixVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLFFBQVEsS0FBSyxLQUFLLEVBQUUsQ0FDbEUsQ0FBQztJQUNOLENBQUM7SUFDRCw2RkFBNkY7SUFDN0YseUJBQXlCO0lBQ3pCLElBQUksVUFBVSxHQUFHLFVBQVUsQ0FBQyxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ25ELElBQUksSUFBSSxHQUFHLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxDQUFDLENBQUMsSUFBSSx3QkFBWSxDQUFDO0lBQ2xFLGdGQUFnRjtJQUNoRixJQUFBLDBCQUFnQixFQUFDLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDO0lBQzNFLE9BQU8sRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxDQUFDO0FBQ3pDLENBQUM7QUFFTSxLQUFLLFVBQVUsSUFBSTtJQUN0QixJQUFJLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsR0FBRyxTQUFTLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNyRSxJQUFJLEVBQUUsT0FBTyxFQUFFLFFBQVEsRUFBRSxHQUFHLE1BQU0sSUFBQSxtQ0FBbUIsRUFBQyxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRixJQUFJLE9BQU8sS0FBSyxXQUFXLEVBQUUsQ0FBQztRQUMxQixPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsSUFBQSx3QkFBWSxFQUFDLElBQUksQ0FBQyxzQ0FBc0MsUUFBUSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ25HLE9BQU87SUFDWCxDQUFDO0lBQ0QsSUFBSSxPQUFPLEtBQUssVUFBVSxFQUFFLENBQUM7UUFDekIsT0FBTyxDQUFDLEdBQUcsQ0FBQywyQkFBMkIsSUFBQSx3QkFBWSxFQUFDLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0lBQzNGLENBQUM7SUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLFNBQVMsUUFBUSxPQUFPLElBQUEsd0JBQVksRUFBQyxJQUFJLENBQUMsZ0RBQWdELENBQUMsQ0FBQztBQUM1RyxDQUFDO0FBWEQsb0JBV0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBwYXJzZVdlYmhvb2tGaWxlIH0gZnJvbSBcIi4vZGlzY29yZFwiO1xuaW1wb3J0IHsgZW5zdXJlUmVtb3RlV2ViaG9vaywgUkVQTEFDRV9LRVlXT1JEIH0gZnJvbSBcIi4vcmVtb3RlV2ViaG9va1wiO1xuaW1wb3J0IHsgZGVzY3JpYmVIb3N0LCBUSElTX01BQ0hJTkUgfSBmcm9tIFwiLi4vaGVscGVycy9yZW1vdGVTU0hcIjtcblxuY29uc3QgVVNBR0UgPSBgVXNhZ2U6IHlhcm4gc2V0dXBub3RpZnkgW2hvc3RdIDxkaXNjb3JkLXdlYmhvb2stdXJsPiBbJHtSRVBMQUNFX0tFWVdPUkR9XVxuXG5XaXRoIG5vIGhvc3QgaXQgc2V0cyB0aGUgd2ViaG9vayB1cCBvbiB0aGlzIG1hY2hpbmUuYDtcblxuZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdKSB7XG4gICAgbGV0IHJlcGxhY2UgPSBhcmd2LmluY2x1ZGVzKFJFUExBQ0VfS0VZV09SRCk7XG4gICAgbGV0IHBvc2l0aW9uYWwgPSBhcmd2LmZpbHRlcihhcmcgPT4gYXJnICE9PSBSRVBMQUNFX0tFWVdPUkQpO1xuICAgIGlmICghcG9zaXRpb25hbC5sZW5ndGggfHwgcG9zaXRpb25hbC5sZW5ndGggPiAyKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBFeHBlY3RlZCBhIHdlYmhvb2sgVVJMLCBhbmQgb3B0aW9uYWxseSBhIGhvc3QgYmVmb3JlIGl0LCB3YXMgJHtwb3NpdGlvbmFsLmxlbmd0aH1gXG4gICAgICAgICAgICArIGAgYXJndW1lbnQocyk6ICR7cG9zaXRpb25hbC5qb2luKFwiIFwiKSB8fCBcIihub25lKVwifVxcbiR7VVNBR0V9YFxuICAgICAgICApO1xuICAgIH1cbiAgICAvLyBUaGUgd2ViaG9vayB1cmwgaXMgdGhlIGxhc3Qgb25lLCBzbyB3aGF0ZXZlciBjb21lcyBiZWZvcmUgaXQgaXMgdGhlIGhvc3QuIFdpdGhvdXQgb25lIHRoaXNcbiAgICAvLyBtYWNoaW5lIGlzIHRoZSB0YXJnZXQuXG4gICAgbGV0IHdlYmhvb2tVUkwgPSBwb3NpdGlvbmFsW3Bvc2l0aW9uYWwubGVuZ3RoIC0gMV07XG4gICAgbGV0IGhvc3QgPSBwb3NpdGlvbmFsLmxlbmd0aCA+IDEgJiYgcG9zaXRpb25hbFswXSB8fCBUSElTX01BQ0hJTkU7XG4gICAgLy8gVmFsaWRhdGVzIHRoZSBVUkwgc2hhcGUgdXAgZnJvbnQsIHNvIHdlIG5ldmVyIGdvIGFueXdoZXJlIHdpdGggYSBiYWQgd2ViaG9vay5cbiAgICBwYXJzZVdlYmhvb2tGaWxlKHsgY29udGVudHM6IHdlYmhvb2tVUkwsIHNvdXJjZU5hbWU6IFwidGhlIGNvbW1hbmQgbGluZVwiIH0pO1xuICAgIHJldHVybiB7IGhvc3QsIHdlYmhvb2tVUkwsIHJlcGxhY2UgfTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7XG4gICAgbGV0IHsgaG9zdCwgd2ViaG9va1VSTCwgcmVwbGFjZSB9ID0gcGFyc2VBcmdzKHByb2Nlc3MuYXJndi5zbGljZSgyKSk7XG4gICAgbGV0IHsgb3V0Y29tZSwgZmlsZVBhdGggfSA9IGF3YWl0IGVuc3VyZVJlbW90ZVdlYmhvb2soeyBob3N0LCB3ZWJob29rVVJMLCByZXBsYWNlIH0pO1xuICAgIGlmIChvdXRjb21lID09PSBcInVuY2hhbmdlZFwiKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke2Rlc2NyaWJlSG9zdChob3N0KX0gYWxyZWFkeSBoYXMgdGhpcyBleGFjdCB3ZWJob29rIGluICR7ZmlsZVBhdGh9LCBub3RoaW5nIHRvIGRvLmApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmIChvdXRjb21lID09PSBcInJlcGxhY2VkXCIpIHtcbiAgICAgICAgY29uc29sZS5sb2coYFJlcGxhY2VkIHRoZSB3ZWJob29rIG9uICR7ZGVzY3JpYmVIb3N0KGhvc3QpfSBhbmQgbm90aWZpZWQgdGhlIG9sZCBvbmUuYCk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBXcm90ZSAke2ZpbGVQYXRofSBvbiAke2Rlc2NyaWJlSG9zdChob3N0KX0gKG1vZGUgNjAwKSwgYW5kIGNvbmZpcm1lZCBvbiB0aGUgbmV3IHdlYmhvb2suYCk7XG59XG4iXX0=
|
|
39
|
+
/* _JS_SOURCE_HASH = "75262294c247703aec2fc4b9dcf81c245e79b0b1566401ca4654e019705f6a40"; */
|
|
@@ -12,6 +12,7 @@ const paths_1 = require("../helpers/paths");
|
|
|
12
12
|
const spawn_1 = require("../helpers/spawn");
|
|
13
13
|
const manifest_1 = require("./manifest");
|
|
14
14
|
const unrevoke_1 = require("../authorizedKeys/unrevoke");
|
|
15
|
+
const keysRepo_1 = require("../authorizedKeys/keysRepo");
|
|
15
16
|
const authorizedKeys_1 = require("../authorizedKeys/authorizedKeys");
|
|
16
17
|
// A hardware backed key is the entire point. A key sitting on disk is compromised the moment the
|
|
17
18
|
// machine is, and then the signature proves nothing, so this is what we make when asked to make one.
|
|
@@ -150,14 +151,11 @@ async function signRepo(config) {
|
|
|
150
151
|
exports.signRepo = signRepo;
|
|
151
152
|
async function main() {
|
|
152
153
|
let { keyPath, pushToGit } = parseArgs(process.argv.slice(2));
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
let repoPath =
|
|
157
|
-
|
|
158
|
-
throw new Error(`Expected the current directory to be inside a git repo, it is not.\n`
|
|
159
|
-
+ `${(topLevel.stdout + topLevel.stderr).trim()}\n${USAGE}`);
|
|
160
|
-
}
|
|
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}`);
|
|
161
159
|
await signRepo({ repoPath, keyPath });
|
|
162
160
|
if (!pushToGit) {
|
|
163
161
|
console.log(`Commit and push ${manifest_1.MANIFEST_NAME} and ${manifest_1.SIGNATURE_NAME} for anything to see them.`);
|
|
@@ -177,5 +175,5 @@ async function main() {
|
|
|
177
175
|
console.log(`Committed and pushed.`);
|
|
178
176
|
}
|
|
179
177
|
exports.main = main;
|
|
180
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbkZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2lnbkZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJEQUE2QjtBQUM3Qiw0Q0FBb0I7QUFDcEIsZ0RBQXdCO0FBQ3hCLCtEQUE0RDtBQUM1RCw0Q0FBOEM7QUFDOUMsNENBQWdEO0FBQ2hELHlDQUEwRztBQUMxRyx5REFBK0Q7QUFDL0QscUVBQWtGO0FBRWxGLGlHQUFpRztBQUNqRyxxR0FBcUc7QUFDckcsTUFBTSxnQkFBZ0IsR0FBRyxZQUFZLENBQUM7QUFDdEMsTUFBTSxnQkFBZ0IsR0FBRyw2QkFBNkIsQ0FBQztBQUN2RCxNQUFNLFdBQVcsR0FBRyxLQUFLLENBQUM7QUFDMUIsTUFBTSxjQUFjLEdBQUcsd0JBQXdCLENBQUM7QUFDaEQsTUFBTSxxQkFBcUIsR0FBRyxHQUFHLENBQUM7QUFDbEMsTUFBTSxLQUFLLEdBQUcsd0NBQXdDLFdBQVc7OztFQUcvRCxnQkFBZ0IsV0FBVyxnQkFBZ0I7T0FDdEMsV0FBVyxzQ0FBc0MsQ0FBQztBQUV6RDswRUFDMEU7QUFDMUUsU0FBUyxLQUFLLENBQUMsS0FBYTtJQUN4QixPQUFPLElBQUksS0FBSyxHQUFHLENBQUM7QUFDeEIsQ0FBQztBQUVELEtBQUssVUFBVSxVQUFVLENBQUMsUUFBZ0I7SUFDdEMsSUFBSSxDQUFDO1FBQ0QsTUFBTSxrQkFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMxQixPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNULE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7QUFDTCxDQUFDO0FBRUQsb0VBQW9FO0FBQ3BFLEtBQUssVUFBVSxnQkFBZ0I7SUFDM0IsSUFBSSxPQUFPLEdBQUcsSUFBQSxrQkFBVSxFQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDM0MsSUFBSSxNQUFNLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxD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QXlCLENBQUMsQ0FBQztRQUM5RixPQUFPO0lBQ1gsQ0FBQztJQUNELE1BQU0sSUFBQSx1QkFBVSxFQUFDLGlCQUFpQixLQUFLLENBQUMsY0FBYyxDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQzlFLE1BQU0sSUFBQSx1QkFBVSxFQUFDLFVBQVUsRUFBRSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDO0lBQ2hELE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztBQUN6QyxDQUFDO0FBL0JELG9CQStCQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBvcyBmcm9tIFwib3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBydW5Qcm9taXNlIH0gZnJvbSBcInNvY2tldC1mdW5jdGlvbi9zcmMvcnVuUHJvbWlzZVwiO1xuaW1wb3J0IHsgZXhwYW5kSG9tZSB9IGZyb20gXCIuLi9oZWxwZXJzL3BhdGhzXCI7XG5pbXBvcnQgeyBzcGF3blByb21pc2UgfSBmcm9tIFwiLi4vaGVscGVycy9zcGF3blwiO1xuaW1wb3J0IHsgYnVpbGRNYW5pZmVzdCwgZm9ybWF0TWFuaWZlc3QsIE1BTklGRVNUX05BTUUsIFNJR05BVFVSRV9OQU1FLCBTSUdOX05BTUVTUEFDRSB9IGZyb20gXCIuL21hbmlmZXN0XCI7XG5pbXBvcnQgeyByZXZva2VkS2V5c0luUmVwbyB9IGZyb20gXCIuLi9hdXRob3JpemVkS2V5cy91bnJldm9rZVwiO1xuaW1wb3J0IHsgZmluZEtleVByb2JsZW1zLCBub3JtYWxpemVLZXlzIH0gZnJvbSBcIi4uL2F1dGhvcml6ZWRLZXlzL2F1dGhvcml6ZWRLZXlzXCI7XG5cbi8vIEEgaGFyZHdhcmUgYmFja2VkIGtleSBpcyB0aGUgZW50aXJlIHBvaW50LiBBIGtleSBzaXR0aW5nIG9uIGRpc2sgaXMgY29tcHJvbWlzZWQgdGhlIG1vbWVudCB0aGVcbi8vIG1hY2hpbmUgaXMsIGFuZCB0aGVuIHRoZSBzaWduYXR1cmUgcHJvdmVzIG5vdGhpbmcsIHNvIHRoaXMgaXMgd2hhdCB3ZSBtYWtlIHdoZW4gYXNrZWQgdG8gbWFrZSBvbmUuXG5jb25zdCBERUZBVUxUX0tFWV9UWVBFID0gXCJlZDI1NTE5LXNrXCI7XG5jb25zdCBERUZBVUxUX0tFWV9QQVRIID0gXCJ+Ly5zc2gvc2lnbmZpbGVzX2VkMjU1MTlfc2tcIjtcbmNvbnN0IEdJVF9LRVlXT1JEID0gXCJnaXRcIjtcbmNvbnN0IENPTU1JVF9NRVNTQUdFID0gXCJkZXBsb3lpbmcgc2lnbmVkIGZpbGVzXCI7XG5jb25zdCBNQVhfRVJST1JfQk9EWV9MRU5HVEggPSA1MDA7XG5jb25zdCBVU0FHRSA9IGBVc2FnZTogeWFybiBzaWduZmlsZXMgW3NpZ25pbmcta2V5XSBbJHtHSVRfS0VZV09SRH1dXG5cblNpZ25zIHRoZSBmaWxlcyBvZiB0aGUgcmVwbyBpbiB0aGUgY3VycmVudCBkaXJlY3RvcnkuIFdpdGggbm8ga2V5LCBhIGhhcmR3YXJlIGJhY2tlZFxuJHtERUZBVUxUX0tFWV9UWVBFfSBrZXkgYXQgJHtERUZBVUxUX0tFWV9QQVRIfSBpcyB1c2VkLCBhbmQgY3JlYXRlZCBpZiBpdCBkb2VzIG5vdCBleGlzdC5cblBhc3MgJHtHSVRfS0VZV09SRH0gdG8gYWxzbyBjb21taXQgYW5kIHB1c2ggdGhlIHJlc3VsdC5gO1xuXG4vKiogcnVuUHJvbWlzZSB0YWtlcyBhIGNvbW1hbmQgbGluZSByYXRoZXIgdGhhbiBhbiBhcmd1bWVudCBsaXN0LCBzbyBhbnl0aGluZyBob2xkaW5nIGEgcGF0aCBoYXMgdG9cbiAgICBzdXJ2aXZlIHRoZSBzaGVsbC4gRG91YmxlIHF1b3RlcyB3b3JrIG9uIGJvdGggY21kIGFuZCBwb3NpeCBzaGVsbHMuICovXG5mdW5jdGlvbiBxdW90ZSh2YWx1ZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGBcIiR7dmFsdWV9XCJgO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwYXRoRXhpc3RzKGZpbGVQYXRoOiBzdHJpbmcpIHtcbiAgICB0cnkge1xuICAgICAgICBhd2FpdCBmcy5hY2Nlc3MoZmlsZVBhdGgpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG59XG5cbi8qKiBDcmVhdGluZyB0aGlzIG5lZWRzIHRoZSBzZWN1cml0eSBrZXkgcGx1Z2dlZCBpbiwgYW5kIGEgdG91Y2guICovXG5hc3luYyBmdW5jdGlvbiBlbnN1cmVEZWZhdWx0S2V5KCkge1xuICAgIGxldCBrZXlQYXRoID0gZXhwYW5kSG9tZShERUZBVUxUX0tFWV9QQVRIKTtcbiAgICBpZiAoYXdhaXQgcGF0aEV4aXN0cyhrZXlQYXRoKSkge1xuICAgICAgICByZXR1cm4ga2V5UGF0aDtcbiAgICB9XG4gICAgY29uc29sZS5sb2coYE5vIHNpZ25pbmcga2V5IGF0ICR7a2V5UGF0aH0sIGNyZWF0aW5nIGFuICR7REVGQVVMVF9LRVlfVFlQRX0gb25lLmApO1xuICAgIGNvbnNvbGUubG9nKGBQbHVnIHlvdXIgc2VjdXJpdHkga2V5IGluIC0geW91IHdpbGwgYmUgYXNrZWQgdG8gdG91Y2ggaXQuYCk7XG4gICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKGtleVBhdGgpLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgbW9kZTogMG83MDAgfSk7XG4gICAgYXdhaXQgcnVuUHJvbWlzZShgc3NoLWtleWdlbiAtdCAke0RFRkFVTFRfS0VZX1RZUEV9IC1mICR7cXVvdGUoa2V5UGF0aCl9IC1OIFwiXCIgLUMgc2lnbmZpbGVzYCk7XG4gICAgcmV0dXJuIGtleVBhdGg7XG59XG5cbi8qKiBUaGUgcHVibGljIGtleSBpbiB0aGUgZm9ybSB0aGUgZGFlbW9uIHJlcG9ydHMgaXQsIHNvIHdoYXQgaXMgcHJpbnRlZCBoZXJlIGNhbiBiZSBjb21wYXJlZFxuICAgIGFnYWluc3Qgd2hhdCBhcnJpdmVzIG9uIERpc2NvcmQuICovXG5hc3luYyBmdW5jdGlvbiBwdWJsaWNLZXlPZihrZXlQYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgY29udGVudHMgPSBhd2FpdCBmcy5yZWFkRmlsZShgJHtrZXlQYXRofS5wdWJgLCBcInV0ZjhcIik7XG4gICAgbGV0IFtrZXlUeXBlLCBrZXlCb2R5XSA9IGNvbnRlbnRzLnRyaW0oKS5zcGxpdCgvXFxzKy8pO1xuICAgIGlmICgha2V5VHlwZSB8fCAha2V5Qm9keSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgcHVibGljIGtleSBpbiAke2tleVBhdGh9LnB1Yiwgd2FzICR7Y29udGVudHMuc2xpY2UoMCwgTUFYX0VSUk9SX0JPRFlfTEVOR1RIKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGAke2tleVR5cGV9ICR7a2V5Qm9keX1gO1xufVxuXG4vKiogQSBrZXlzIHJlcG8gaGFzIHJ1bGVzIHRoZSByZXN0IG9mIHRoaXMgY2Fubm90IGVuZm9yY2UgYWZ0ZXJ3YXJkcywgc28gdGhleSBhcmUgZW5mb3JjZWQgYmVmb3JlIGl0XG4gICAgaXMgc2lnbmVkLiBTaWduaW5nIGFueXRoaW5nIHRoYXQgaXMgbm90IGEga2V5cyByZXBvIGlzIG5vbmUgb2YgdGhpcyBmdW5jdGlvbidzIGJ1c2luZXNzLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVmdXNlVW51c2FibGVLZXlzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgYXV0aG9yaXplZFBhdGggPSBwYXRoLmpvaW4ocmVwb1BhdGgsIFwiYXV0aG9yaXplZF9rZXlzXCIpO1xuICAgIGlmICghYXdhaXQgcGF0aEV4aXN0cyhhdXRob3JpemVkUGF0aCkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgcHJvYmxlbXMgPSBmaW5kS2V5UHJvYmxlbXMobm9ybWFsaXplS2V5cyhhd2FpdCBmcy5yZWFkRmlsZShhdXRob3JpemVkUGF0aCwgXCJ1dGY4XCIpKSk7XG4gICAgaWYgKCFwcm9ibGVtcy5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBFeHBlY3RlZCBldmVyeSBrZXkgaW4gJHthdXRob3JpemVkUGF0aH0gdG8gYmUgcmVzdHJpY3RlZCBhbmQgdG8gYmVsb25nIHRvIG9uZSBwZXJzb24sYFxuICAgICAgICArIGAgZm91bmQgJHtwcm9ibGVtcy5sZW5ndGh9IHByb2JsZW0ocyk6XFxuYFxuICAgICAgICArIHByb2JsZW1zLm1hcChwcm9ibGVtID0+IGAgIC0gJHtwcm9ibGVtfWApLmpvaW4oXCJcXG5cIilcbiAgICAgICAgKyBgXFxuXFxuRXZlcnkga2V5IG5lZWRzIGEgZnJvbT0gbmFtaW5nIHRoZSBhZGRyZXNzZXMgaXQgbWF5IGJlIHVzZWQgZnJvbSwgYW5kIG5vIHR3byBrZXlzIG1heWBcbiAgICAgICAgKyBgXFxubmFtZSB0aGUgc2FtZSBvbmVzLiBSZXZva2luZyBhIGtleSB0aGF0IHNoYXJlcyBpdHMgYWRkcmVzc2VzIHdpdGggYW5vdGhlciBsZWF2ZXMgdGhhdGBcbiAgICAgICAgKyBgXFxub3RoZXIga2V5IHdvcmtpbmcsIHdoaWNoIGRlZmVhdHMgdGhlIHBvaW50IG9mIHJldm9raW5nIGl0LmBcbiAgICApO1xufVxuXG4vKiogU2lnbmluZyBhIGtleXMgcmVwbyB0aGF0IHN0aWxsIGhvbGRzIGEgcmV2b2tlZCBrZXkgd291bGQgcHVibGlzaCBpdCBiYWNrIHRvIGV2ZXJ5IG1hY2hpbmUgdGhhdFxuICAgIHRvb2sgaXQgb3V0LiBPbmx5IGFwcGxpZXMgdG8gYSByZXBvIHRoYXQgaG9sZHMga2V5cyBhbmQgaGFzIGEgcmV2b2tlIHJlcG8gdG8gY2hlY2sgLSBzaWduaW5nXG4gICAgYW55dGhpbmcgZWxzZSBpcyBub25lIG9mIHRoaXMgZnVuY3Rpb24ncyBidXNpbmVzcy4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlZnVzZVJldm9rZWRLZXlzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBpZiAoIWF3YWl0IHBhdGhFeGlzdHMocGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKSkpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICAvLyBSZWFkIGZvciBpdHMgdmFsdWUsIHNvIHN0ZG91dCBoYXMgdG8gYmUgb24gaXRzIG93bi4gcnVuUHJvbWlzZSBqb2lucyBpdCB3aXRoIHN0ZGVyci5cbiAgICBsZXQgb3JpZ2luID0gYXdhaXQgc3Bhd25Qcm9taXNlKHsgY29tbWFuZDogXCJnaXRcIiwgYXJnczogW1wicmVtb3RlXCIsIFwiZ2V0LXVybFwiLCBcIm9yaWdpblwiXSwgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBsZXQgb3JpZ2luVVJMID0gb3JpZ2luLnN0ZG91dC50cmltKCk7XG4gICAgaWYgKG9yaWdpbi5zdGF0dXMgIT09IDAgfHwgIW9yaWdpblVSTCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCByZXZva2VkO1xuICAgIHRyeSB7XG4gICAgICAgIHJldm9rZWQgPSBhd2FpdCByZXZva2VkS2V5c0luUmVwbyh7IHJlcG9QYXRoLCBzb3VyY2VVUkw6IG9yaWdpblVSTCB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIE5vIHJldm9rZSByZXBvLCBvciBubyBhY2Nlc3MgdG8gaXQuIE5vdGhpbmcgaGFzIGJlZW4gcmV2b2tlZCB0aGF0IHdlIGNhbiBzZWUuXG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCFyZXZva2VkLmxlbmd0aCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgYEV4cGVjdGVkICR7cmVwb1BhdGh9IHRvIGhvbGQgbm8gcmV2b2tlZCBrZXlzLCBpdCBob2xkcyAke3Jldm9rZWQubGVuZ3RofTpcXG5gXG4gICAgICAgICsgcmV2b2tlZC5tYXAoZW50cnkgPT4gYCAgJHtlbnRyeS5yZXZvY2F0aW9uLmZpbmdlcnByaW50fSByZXZva2VkIGJ5ICR7ZW50cnkucmV2b2NhdGlvbi5yZXZva2VkQnkgfHwgXCI/XCJ9YFxuICAgICAgICAgICAgKyBgIGFmdGVyIHVzZSBmcm9tICR7ZW50cnkucmV2b2NhdGlvbi5hdHRlbXB0Py5pcCB8fCBcIj9cIn1gKS5qb2luKFwiXFxuXCIpXG4gICAgICAgICsgYFxcbkRlbGV0ZSB0aGVtIGZyb20gYXV0aG9yaXplZF9rZXlzLCBvciBydW4gXCJ5YXJuIHVucmV2b2tlXCIgaGVyZSB0byBhbGxvdyB0aGVtIGFnYWluLmBcbiAgICApO1xufVxuXG5mdW5jdGlvbiBwYXJzZUFyZ3MoYXJndjogc3RyaW5nW10pIHtcbiAgICBsZXQgcHVzaFRvR2l0ID0gYXJndi5pbmNsdWRlcyhHSVRfS0VZV09SRCk7XG4gICAgbGV0IHBvc2l0aW9uYWwgPSBhcmd2LmZpbHRlcihhcmcgPT4gYXJnICE9PSBHSVRfS0VZV09SRCk7XG4gICAgaWYgKHBvc2l0aW9uYWwubGVuZ3RoID4gMSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGF0IG1vc3QgYSBzaWduaW5nIGtleSwgd2FzICR7cG9zaXRpb25hbC5sZW5ndGh9IGFyZ3VtZW50KHMpOiAke3Bvc2l0aW9uYWwuam9pbihcIiBcIil9XFxuJHtVU0FHRX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHsga2V5UGF0aDogcG9zaXRpb25hbFswXSwgcHVzaFRvR2l0IH07XG59XG5cbi8qKiBXcml0ZXMgdGhlIG1hbmlmZXN0IGFuZCBpdHMgc2lnbmF0dXJlIGludG8gYSByZXBvLiBTZXBhcmF0ZSBmcm9tIHRoZSBjb21tYW5kIHNvIGFueXRoaW5nIHRoYXRcbiAgICBjaGFuZ2VzIGEga2V5cyByZXBvIGNhbiBsZWF2ZSBpdCBzaWduZWQsIHJhdGhlciB0aGFuIHRlbGxpbmcgc29tZW9uZSB0byBnbyBhbmQgZG8gaXQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2lnblJlcG8oY29uZmlnOiB7IHJlcG9QYXRoOiBzdHJpbmc7IGtleVBhdGg/OiBzdHJpbmcgfSkge1xuICAgIGxldCB7IHJlcG9QYXRoIH0gPSBjb25maWc7XG4gICAgbGV0IHNpZ25pbmdLZXkgPSBjb25maWcua2V5UGF0aCAmJiBleHBhbmRIb21lKGNvbmZpZy5rZXlQYXRoKSB8fCBhd2FpdCBlbnN1cmVEZWZhdWx0S2V5KCk7XG4gICAgaWYgKCFhd2FpdCBwYXRoRXhpc3RzKHNpZ25pbmdLZXkpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYSBzaWduaW5nIGtleSBhdCAke3NpZ25pbmdLZXl9LCBubyBzdWNoIGZpbGUgZXhpc3RzYCk7XG4gICAgfVxuXG4gICAgYXdhaXQgcmVmdXNlVW51c2FibGVLZXlzKHJlcG9QYXRoKTtcbiAgICBhd2FpdCByZWZ1c2VSZXZva2VkS2V5cyhyZXBvUGF0aCk7XG5cbiAgICBsZXQgbWFuaWZlc3QgPSBhd2FpdCBidWlsZE1hbmlmZXN0KHJlcG9QYXRoKTtcbiAgICBjb25zb2xlLmxvZyhgJHtNQU5JRkVTVF9OQU1FfSBjb3ZlcnMgJHttYW5pZmVzdC5maWxlcy5sZW5ndGh9IGZpbGUocykgaW4gJHtyZXBvUGF0aH1gKTtcblxuICAgIC8vIFRoZSBtYW5pZmVzdCBpcyBidWlsdCBhbmQgc2lnbmVkIGF3YXkgZnJvbSB0aGUgcmVwbywgYW5kIG9ubHkgbW92ZWQgaW4gb25jZSBib3RoIGV4aXN0LlxuICAgIC8vIExhbmRpbmcgYSBuZXcgbWFuaWZlc3QgbmV4dCB0byBhbiBvbGQgc2lnbmF0dXJlIHByb2R1Y2VzIGEgcGFpciB0aGF0IGNhbiBuZXZlciB2ZXJpZnksIGFuZFxuICAgIC8vIHRoZSBkYWVtb24gcmVhZGluZyBpdCBjYW4gb25seSB0cmVhdCB0aGF0IGFzIHRhbXBlcmluZy5cbiAgICBsZXQgc3RhZ2luZ0RpcmVjdG9yeSA9IGF3YWl0IGZzLm1rZHRlbXAocGF0aC5qb2luKG9zLnRtcGRpcigpLCBcInNpZ25maWxlcy1cIikpO1xuICAgIGxldCBzdGFnZWRNYW5pZmVzdCA9IHBhdGguam9pbihzdGFnaW5nRGlyZWN0b3J5LCBNQU5JRkVTVF9OQU1FKTtcbiAgICBsZXQgc3RhZ2VkU2lnbmF0dXJlID0gYCR7c3RhZ2VkTWFuaWZlc3R9LnNpZ2A7XG4gICAgYXdhaXQgZnMud3JpdGVGaWxlKHN0YWdlZE1hbmlmZXN0LCBmb3JtYXRNYW5pZmVzdChtYW5pZmVzdCkpO1xuXG4gICAgLy8gU2lnbmluZyBoYXBwZW5zIGJlZm9yZSBhbnkgZ2l0IHdvcmssIHNvIGEgZmFpbGVkIHB1c2ggbmV2ZXIgY29zdHMgYSBzZWNvbmQgdG91Y2ggb2YgdGhlIGtleS5cbiAgICBhd2FpdCBydW5Qcm9taXNlKGBzc2gta2V5Z2VuIC1ZIHNpZ24gLWYgJHtxdW90ZShzaWduaW5nS2V5KX0gLW4gJHtTSUdOX05BTUVTUEFDRX0gJHtxdW90ZShzdGFnZWRNYW5pZmVzdCl9YCk7XG4gICAgLy8gQ2hlY2tlZCBoZXJlIHJhdGhlciB0aGFuIGxlZnQgZm9yIGEgbWFjaGluZSB0aGF0IGhhcyBhbHJlYWR5IHB1bGxlZCBpdCB0byBkaXNjb3Zlci5cbiAgICBhd2FpdCBydW5Qcm9taXNlKFxuICAgICAgICBgc3NoLWtleWdlbiAtWSBjaGVjay1ub3ZhbGlkYXRlIC1uICR7U0lHTl9OQU1FU1BBQ0V9IC1zICR7cXVvdGUoc3RhZ2VkU2lnbmF0dXJlKX0gPCAke3F1b3RlKHN0YWdlZE1hbmlmZXN0KX1gXG4gICAgKTtcbiAgICBhd2FpdCBmcy5jb3B5RmlsZShzdGFnZWRNYW5pZmVzdCwgcGF0aC5qb2luKHJlcG9QYXRoLCBNQU5JRkVTVF9OQU1FKSk7XG4gICAgYXdhaXQgZnMuY29weUZpbGUoc3RhZ2VkU2lnbmF0dXJlLCBwYXRoLmpvaW4ocmVwb1BhdGgsIFNJR05BVFVSRV9OQU1FKSk7XG4gICAgYXdhaXQgZnMucm0oc3RhZ2luZ0RpcmVjdG9yeSwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIGNvbnNvbGUubG9nKGBTaWduZWQgd2l0aCAke2F3YWl0IHB1YmxpY0tleU9mKHNpZ25pbmdLZXkpfWApO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgICBsZXQgeyBrZXlQYXRoLCBwdXNoVG9HaXQgfSA9IHBhcnNlQXJncyhwcm9jZXNzLmFyZ3Yuc2xpY2UoMikpO1xuXG4gICAgLy8gUmVhZCBmb3IgaXRzIHZhbHVlLCBzbyBzdGRvdXQgaGFzIHRvIGJlIG9uIGl0cyBvd24uIHJ1blByb21pc2Ugam9pbnMgaXQgd2l0aCBzdGRlcnIsIGFuZCBhXG4gICAgLy8gZ2l0IHdhcm5pbmcgZ2x1ZWQgdG8gdGhlIGZyb250IG9mIHRoaXMgYmVjb21lcyBhIGRpcmVjdG9yeSB0aGF0IGRvZXMgbm90IGV4aXN0LlxuICAgIGxldCB0b3BMZXZlbCA9IGF3YWl0IHNwYXduUHJvbWlzZSh7IGNvbW1hbmQ6IFwiZ2l0XCIsIGFyZ3M6IFtcInJldi1wYXJzZVwiLCBcIi0tc2hvdy10b3BsZXZlbFwiXSB9KTtcbiAgICBsZXQgcmVwb1BhdGggPSB0b3BMZXZlbC5zdGRvdXQudHJpbSgpO1xuICAgIGlmICh0b3BMZXZlbC5zdGF0dXMgIT09IDAgfHwgIXJlcG9QYXRoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGBFeHBlY3RlZCB0aGUgY3VycmVudCBkaXJlY3RvcnkgdG8gYmUgaW5zaWRlIGEgZ2l0IHJlcG8sIGl0IGlzIG5vdC5cXG5gXG4gICAgICAgICAgICArIGAkeyh0b3BMZXZlbC5zdGRvdXQgKyB0b3BMZXZlbC5zdGRlcnIpLnRyaW0oKX1cXG4ke1VTQUdFfWBcbiAgICAgICAgKTtcbiAgICB9XG4gICAgYXdhaXQgc2lnblJlcG8oeyByZXBvUGF0aCwga2V5UGF0aCB9KTtcblxuICAgIGlmICghcHVzaFRvR2l0KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBDb21taXQgYW5kIHB1c2ggJHtNQU5JRkVTVF9OQU1FfSBhbmQgJHtTSUdOQVRVUkVfTkFNRX0gZm9yIGFueXRoaW5nIHRvIHNlZSB0aGVtLmApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IHJ1blByb21pc2UoYGdpdCBhZGQgLUFgLCB7IGN3ZDogcmVwb1BhdGggfSk7XG4gICAgLy8gTm90aGluZyBzdGFnZWQgaXMgbm90IHdvcnRoIHN0b3BwaW5nIG9uLiBnaXQgY29tbWl0IGNhbGxzIHRoYXQgYSBmYWlsdXJlLCBidXQgaXQgb25seSBtZWFuc1xuICAgIC8vIHRoZSBzaWduYXR1cmUgbWF0Y2hlcyB0aGUgb25lIGFscmVhZHkgY29tbWl0dGVkLCBzbyB0aGVyZSBpcyBub3RoaW5nIHRvIGRlcGxveS5cbiAgICBsZXQgc3RhdHVzID0gYXdhaXQgc3Bhd25Qcm9taXNlKHsgY29tbWFuZDogXCJnaXRcIiwgYXJnczogW1wic3RhdHVzXCIsIFwiLS1wb3JjZWxhaW5cIl0sIGN3ZDogcmVwb1BhdGggfSk7XG4gICAgbGV0IHN0YWdlZCA9IHN0YXR1cy5zdGRvdXQ7XG4gICAgaWYgKCFzdGFnZWQudHJpbSgpKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBOb3RoaW5nIGNoYW5nZWQsICR7TUFOSUZFU1RfTkFNRX0gYW5kICR7U0lHTkFUVVJFX05BTUV9IGFyZSBhbHJlYWR5IGNvbW1pdHRlZC5gKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgY29tbWl0IC1tICR7cXVvdGUoQ09NTUlUX01FU1NBR0UpfWAsIHsgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgcHVzaGAsIHsgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBjb25zb2xlLmxvZyhgQ29tbWl0dGVkIGFuZCBwdXNoZWQuYCk7XG59XG4iXX0=
|
|
181
|
-
/* _JS_SOURCE_HASH = "
|
|
178
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnbkZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsic2lnbkZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJEQUE2QjtBQUM3Qiw0Q0FBb0I7QUFDcEIsZ0RBQXdCO0FBQ3hCLCtEQUE0RDtBQUM1RCw0Q0FBOEM7QUFDOUMsNENBQWdEO0FBQ2hELHlDQUEwRztBQUMxRyx5REFBK0Q7QUFDL0QseURBQTZEO0FBQzdELHFFQUFrRjtBQUVsRixpR0FBaUc7QUFDakcscUdBQXFHO0FBQ3JHLE1BQU0sZ0JBQWdCLEdBQUcsWUFBWSxDQUFDO0FBQ3RDLE1BQU0sZ0JBQWdCLEdBQUcsNkJBQTZCLENBQUM7QUFDdkQsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDO0FBQzFCLE1BQU0sY0FBYyxHQUFHLHdCQUF3QixDQUFDO0FBQ2hELE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBQ2xDLE1BQU0sS0FBSyxHQUFHLHdDQUF3QyxXQUFXOzs7RUFHL0QsZ0JBQWdCLFdBQVcsZ0JBQWdCO09BQ3RDLFdBQVcsc0NBQXNDLENBQUM7QUFFekQ7MEVBQzBFO0FBQzFFLFNBQVMsS0FBSyxDQUFDLEtBQWE7SUFDeEIsT0FBTyxJQUFJLEtBQUssR0FBRyxDQUFDO0FBQ3hCLENBQUM7QUFFRCxLQUFLLFVBQVUsVUFBVSxDQUFDLFFBQWdCO0lBQ3RDLElBQUksQ0FBQztRQUNELE1BQU0sa0JBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUIsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDVCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0FBQ0wsQ0FBQztBQUVELG9FQUFvRTtBQUNwRSxLQUFLLFVBQVUsZ0JBQWdCO0lBQzNCLElBQUksT0FBTyxHQUFHLElBQUEsa0JBQVUsRUFBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzNDLElBQUksTUFBTSxVQUFVLENBQUMsT0FB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QyxDQUFDO0FBQ3pDLENBQUM7QUExQkQsb0JBMEJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IG9zIGZyb20gXCJvc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IHJ1blByb21pc2UgfSBmcm9tIFwic29ja2V0LWZ1bmN0aW9uL3NyYy9ydW5Qcm9taXNlXCI7XG5pbXBvcnQgeyBleHBhbmRIb21lIH0gZnJvbSBcIi4uL2hlbHBlcnMvcGF0aHNcIjtcbmltcG9ydCB7IHNwYXduUHJvbWlzZSB9IGZyb20gXCIuLi9oZWxwZXJzL3NwYXduXCI7XG5pbXBvcnQgeyBidWlsZE1hbmlmZXN0LCBmb3JtYXRNYW5pZmVzdCwgTUFOSUZFU1RfTkFNRSwgU0lHTkFUVVJFX05BTUUsIFNJR05fTkFNRVNQQUNFIH0gZnJvbSBcIi4vbWFuaWZlc3RcIjtcbmltcG9ydCB7IHJldm9rZWRLZXlzSW5SZXBvIH0gZnJvbSBcIi4uL2F1dGhvcml6ZWRLZXlzL3VucmV2b2tlXCI7XG5pbXBvcnQgeyByZXNvbHZlS2V5c1JlcG8gfSBmcm9tIFwiLi4vYXV0aG9yaXplZEtleXMva2V5c1JlcG9cIjtcbmltcG9ydCB7IGZpbmRLZXlQcm9ibGVtcywgbm9ybWFsaXplS2V5cyB9IGZyb20gXCIuLi9hdXRob3JpemVkS2V5cy9hdXRob3JpemVkS2V5c1wiO1xuXG4vLyBBIGhhcmR3YXJlIGJhY2tlZCBrZXkgaXMgdGhlIGVudGlyZSBwb2ludC4gQSBrZXkgc2l0dGluZyBvbiBkaXNrIGlzIGNvbXByb21pc2VkIHRoZSBtb21lbnQgdGhlXG4vLyBtYWNoaW5lIGlzLCBhbmQgdGhlbiB0aGUgc2lnbmF0dXJlIHByb3ZlcyBub3RoaW5nLCBzbyB0aGlzIGlzIHdoYXQgd2UgbWFrZSB3aGVuIGFza2VkIHRvIG1ha2Ugb25lLlxuY29uc3QgREVGQVVMVF9LRVlfVFlQRSA9IFwiZWQyNTUxOS1za1wiO1xuY29uc3QgREVGQVVMVF9LRVlfUEFUSCA9IFwifi8uc3NoL3NpZ25maWxlc19lZDI1NTE5X3NrXCI7XG5jb25zdCBHSVRfS0VZV09SRCA9IFwiZ2l0XCI7XG5jb25zdCBDT01NSVRfTUVTU0FHRSA9IFwiZGVwbG95aW5nIHNpZ25lZCBmaWxlc1wiO1xuY29uc3QgTUFYX0VSUk9SX0JPRFlfTEVOR1RIID0gNTAwO1xuY29uc3QgVVNBR0UgPSBgVXNhZ2U6IHlhcm4gc2lnbmZpbGVzIFtzaWduaW5nLWtleV0gWyR7R0lUX0tFWVdPUkR9XVxuXG5TaWducyB0aGUgZmlsZXMgb2YgdGhlIHJlcG8gaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5LiBXaXRoIG5vIGtleSwgYSBoYXJkd2FyZSBiYWNrZWRcbiR7REVGQVVMVF9LRVlfVFlQRX0ga2V5IGF0ICR7REVGQVVMVF9LRVlfUEFUSH0gaXMgdXNlZCwgYW5kIGNyZWF0ZWQgaWYgaXQgZG9lcyBub3QgZXhpc3QuXG5QYXNzICR7R0lUX0tFWVdPUkR9IHRvIGFsc28gY29tbWl0IGFuZCBwdXNoIHRoZSByZXN1bHQuYDtcblxuLyoqIHJ1blByb21pc2UgdGFrZXMgYSBjb21tYW5kIGxpbmUgcmF0aGVyIHRoYW4gYW4gYXJndW1lbnQgbGlzdCwgc28gYW55dGhpbmcgaG9sZGluZyBhIHBhdGggaGFzIHRvXG4gICAgc3Vydml2ZSB0aGUgc2hlbGwuIERvdWJsZSBxdW90ZXMgd29yayBvbiBib3RoIGNtZCBhbmQgcG9zaXggc2hlbGxzLiAqL1xuZnVuY3Rpb24gcXVvdGUodmFsdWU6IHN0cmluZykge1xuICAgIHJldHVybiBgXCIke3ZhbHVlfVwiYDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcGF0aEV4aXN0cyhmaWxlUGF0aDogc3RyaW5nKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgYXdhaXQgZnMuYWNjZXNzKGZpbGVQYXRoKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG4vKiogQ3JlYXRpbmcgdGhpcyBuZWVkcyB0aGUgc2VjdXJpdHkga2V5IHBsdWdnZWQgaW4sIGFuZCBhIHRvdWNoLiAqL1xuYXN5bmMgZnVuY3Rpb24gZW5zdXJlRGVmYXVsdEtleSgpIHtcbiAgICBsZXQga2V5UGF0aCA9IGV4cGFuZEhvbWUoREVGQVVMVF9LRVlfUEFUSCk7XG4gICAgaWYgKGF3YWl0IHBhdGhFeGlzdHMoa2V5UGF0aCkpIHtcbiAgICAgICAgcmV0dXJuIGtleVBhdGg7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKGBObyBzaWduaW5nIGtleSBhdCAke2tleVBhdGh9LCBjcmVhdGluZyBhbiAke0RFRkFVTFRfS0VZX1RZUEV9IG9uZS5gKTtcbiAgICBjb25zb2xlLmxvZyhgUGx1ZyB5b3VyIHNlY3VyaXR5IGtleSBpbiAtIHlvdSB3aWxsIGJlIGFza2VkIHRvIHRvdWNoIGl0LmApO1xuICAgIGF3YWl0IGZzLm1rZGlyKHBhdGguZGlybmFtZShrZXlQYXRoKSwgeyByZWN1cnNpdmU6IHRydWUsIG1vZGU6IDBvNzAwIH0pO1xuICAgIGF3YWl0IHJ1blByb21pc2UoYHNzaC1rZXlnZW4gLXQgJHtERUZBVUxUX0tFWV9UWVBFfSAtZiAke3F1b3RlKGtleVBhdGgpfSAtTiBcIlwiIC1DIHNpZ25maWxlc2ApO1xuICAgIHJldHVybiBrZXlQYXRoO1xufVxuXG4vKiogVGhlIHB1YmxpYyBrZXkgaW4gdGhlIGZvcm0gdGhlIGRhZW1vbiByZXBvcnRzIGl0LCBzbyB3aGF0IGlzIHByaW50ZWQgaGVyZSBjYW4gYmUgY29tcGFyZWRcbiAgICBhZ2FpbnN0IHdoYXQgYXJyaXZlcyBvbiBEaXNjb3JkLiAqL1xuYXN5bmMgZnVuY3Rpb24gcHVibGljS2V5T2Yoa2V5UGF0aDogc3RyaW5nKSB7XG4gICAgbGV0IGNvbnRlbnRzID0gYXdhaXQgZnMucmVhZEZpbGUoYCR7a2V5UGF0aH0ucHViYCwgXCJ1dGY4XCIpO1xuICAgIGxldCBba2V5VHlwZSwga2V5Qm9keV0gPSBjb250ZW50cy50cmltKCkuc3BsaXQoL1xccysvKTtcbiAgICBpZiAoIWtleVR5cGUgfHwgIWtleUJvZHkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhIHB1YmxpYyBrZXkgaW4gJHtrZXlQYXRofS5wdWIsIHdhcyAke2NvbnRlbnRzLnNsaWNlKDAsIE1BWF9FUlJPUl9CT0RZX0xFTkdUSCl9YCk7XG4gICAgfVxuICAgIHJldHVybiBgJHtrZXlUeXBlfSAke2tleUJvZHl9YDtcbn1cblxuLyoqIEEga2V5cyByZXBvIGhhcyBydWxlcyB0aGUgcmVzdCBvZiB0aGlzIGNhbm5vdCBlbmZvcmNlIGFmdGVyd2FyZHMsIHNvIHRoZXkgYXJlIGVuZm9yY2VkIGJlZm9yZSBpdFxuICAgIGlzIHNpZ25lZC4gU2lnbmluZyBhbnl0aGluZyB0aGF0IGlzIG5vdCBhIGtleXMgcmVwbyBpcyBub25lIG9mIHRoaXMgZnVuY3Rpb24ncyBidXNpbmVzcy4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlZnVzZVVudXNhYmxlS2V5cyhyZXBvUGF0aDogc3RyaW5nKSB7XG4gICAgbGV0IGF1dGhvcml6ZWRQYXRoID0gcGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKTtcbiAgICBpZiAoIWF3YWl0IHBhdGhFeGlzdHMoYXV0aG9yaXplZFBhdGgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IHByb2JsZW1zID0gZmluZEtleVByb2JsZW1zKG5vcm1hbGl6ZUtleXMoYXdhaXQgZnMucmVhZEZpbGUoYXV0aG9yaXplZFBhdGgsIFwidXRmOFwiKSkpO1xuICAgIGlmICghcHJvYmxlbXMubGVuZ3RoKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICBgRXhwZWN0ZWQgZXZlcnkga2V5IGluICR7YXV0aG9yaXplZFBhdGh9IHRvIGJlIHJlc3RyaWN0ZWQgYW5kIHRvIGJlbG9uZyB0byBvbmUgcGVyc29uLGBcbiAgICAgICAgKyBgIGZvdW5kICR7cHJvYmxlbXMubGVuZ3RofSBwcm9ibGVtKHMpOlxcbmBcbiAgICAgICAgKyBwcm9ibGVtcy5tYXAocHJvYmxlbSA9PiBgICAtICR7cHJvYmxlbX1gKS5qb2luKFwiXFxuXCIpXG4gICAgICAgICsgYFxcblxcbkV2ZXJ5IGtleSBuZWVkcyBhIGZyb209IG5hbWluZyB0aGUgYWRkcmVzc2VzIGl0IG1heSBiZSB1c2VkIGZyb20sIGFuZCBubyB0d28ga2V5cyBtYXlgXG4gICAgICAgICsgYFxcbm5hbWUgdGhlIHNhbWUgb25lcy4gUmV2b2tpbmcgYSBrZXkgdGhhdCBzaGFyZXMgaXRzIGFkZHJlc3NlcyB3aXRoIGFub3RoZXIgbGVhdmVzIHRoYXRgXG4gICAgICAgICsgYFxcbm90aGVyIGtleSB3b3JraW5nLCB3aGljaCBkZWZlYXRzIHRoZSBwb2ludCBvZiByZXZva2luZyBpdC5gXG4gICAgKTtcbn1cblxuLyoqIFNpZ25pbmcgYSBrZXlzIHJlcG8gdGhhdCBzdGlsbCBob2xkcyBhIHJldm9rZWQga2V5IHdvdWxkIHB1Ymxpc2ggaXQgYmFjayB0byBldmVyeSBtYWNoaW5lIHRoYXRcbiAgICB0b29rIGl0IG91dC4gT25seSBhcHBsaWVzIHRvIGEgcmVwbyB0aGF0IGhvbGRzIGtleXMgYW5kIGhhcyBhIHJldm9rZSByZXBvIHRvIGNoZWNrIC0gc2lnbmluZ1xuICAgIGFueXRoaW5nIGVsc2UgaXMgbm9uZSBvZiB0aGlzIGZ1bmN0aW9uJ3MgYnVzaW5lc3MuICovXG5hc3luYyBmdW5jdGlvbiByZWZ1c2VSZXZva2VkS2V5cyhyZXBvUGF0aDogc3RyaW5nKSB7XG4gICAgaWYgKCFhd2FpdCBwYXRoRXhpc3RzKHBhdGguam9pbihyZXBvUGF0aCwgXCJhdXRob3JpemVkX2tleXNcIikpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgLy8gUmVhZCBmb3IgaXRzIHZhbHVlLCBzbyBzdGRvdXQgaGFzIHRvIGJlIG9uIGl0cyBvd24uIHJ1blByb21pc2Ugam9pbnMgaXQgd2l0aCBzdGRlcnIuXG4gICAgbGV0IG9yaWdpbiA9IGF3YWl0IHNwYXduUHJvbWlzZSh7IGNvbW1hbmQ6IFwiZ2l0XCIsIGFyZ3M6IFtcInJlbW90ZVwiLCBcImdldC11cmxcIiwgXCJvcmlnaW5cIl0sIGN3ZDogcmVwb1BhdGggfSk7XG4gICAgbGV0IG9yaWdpblVSTCA9IG9yaWdpbi5zdGRvdXQudHJpbSgpO1xuICAgIGlmIChvcmlnaW4uc3RhdHVzICE9PSAwIHx8ICFvcmlnaW5VUkwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgcmV2b2tlZDtcbiAgICB0cnkge1xuICAgICAgICByZXZva2VkID0gYXdhaXQgcmV2b2tlZEtleXNJblJlcG8oeyByZXBvUGF0aCwgc291cmNlVVJMOiBvcmlnaW5VUkwgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAvLyBObyByZXZva2UgcmVwbywgb3Igbm8gYWNjZXNzIHRvIGl0LiBOb3RoaW5nIGhhcyBiZWVuIHJldm9rZWQgdGhhdCB3ZSBjYW4gc2VlLlxuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghcmV2b2tlZC5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBFeHBlY3RlZCAke3JlcG9QYXRofSB0byBob2xkIG5vIHJldm9rZWQga2V5cywgaXQgaG9sZHMgJHtyZXZva2VkLmxlbmd0aH06XFxuYFxuICAgICAgICArIHJldm9rZWQubWFwKGVudHJ5ID0+IGAgICR7ZW50cnkucmV2b2NhdGlvbi5maW5nZXJwcmludH0gcmV2b2tlZCBieSAke2VudHJ5LnJldm9jYXRpb24ucmV2b2tlZEJ5IHx8IFwiP1wifWBcbiAgICAgICAgICAgICsgYCBhZnRlciB1c2UgZnJvbSAke2VudHJ5LnJldm9jYXRpb24uYXR0ZW1wdD8uaXAgfHwgXCI/XCJ9YCkuam9pbihcIlxcblwiKVxuICAgICAgICArIGBcXG5EZWxldGUgdGhlbSBmcm9tIGF1dGhvcml6ZWRfa2V5cywgb3IgcnVuIFwieWFybiB1bnJldm9rZVwiIGhlcmUgdG8gYWxsb3cgdGhlbSBhZ2Fpbi5gXG4gICAgKTtcbn1cblxuZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdKSB7XG4gICAgbGV0IHB1c2hUb0dpdCA9IGFyZ3YuaW5jbHVkZXMoR0lUX0tFWVdPUkQpO1xuICAgIGxldCBwb3NpdGlvbmFsID0gYXJndi5maWx0ZXIoYXJnID0+IGFyZyAhPT0gR0lUX0tFWVdPUkQpO1xuICAgIGlmIChwb3NpdGlvbmFsLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhdCBtb3N0IGEgc2lnbmluZyBrZXksIHdhcyAke3Bvc2l0aW9uYWwubGVuZ3RofSBhcmd1bWVudChzKTogJHtwb3NpdGlvbmFsLmpvaW4oXCIgXCIpfVxcbiR7VVNBR0V9YCk7XG4gICAgfVxuICAgIHJldHVybiB7IGtleVBhdGg6IHBvc2l0aW9uYWxbMF0sIHB1c2hUb0dpdCB9O1xufVxuXG4vKiogV3JpdGVzIHRoZSBtYW5pZmVzdCBhbmQgaXRzIHNpZ25hdHVyZSBpbnRvIGEgcmVwby4gU2VwYXJhdGUgZnJvbSB0aGUgY29tbWFuZCBzbyBhbnl0aGluZyB0aGF0XG4gICAgY2hhbmdlcyBhIGtleXMgcmVwbyBjYW4gbGVhdmUgaXQgc2lnbmVkLCByYXRoZXIgdGhhbiB0ZWxsaW5nIHNvbWVvbmUgdG8gZ28gYW5kIGRvIGl0LiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpZ25SZXBvKGNvbmZpZzogeyByZXBvUGF0aDogc3RyaW5nOyBrZXlQYXRoPzogc3RyaW5nIH0pIHtcbiAgICBsZXQgeyByZXBvUGF0aCB9ID0gY29uZmlnO1xuICAgIGxldCBzaWduaW5nS2V5ID0gY29uZmlnLmtleVBhdGggJiYgZXhwYW5kSG9tZShjb25maWcua2V5UGF0aCkgfHwgYXdhaXQgZW5zdXJlRGVmYXVsdEtleSgpO1xuICAgIGlmICghYXdhaXQgcGF0aEV4aXN0cyhzaWduaW5nS2V5KSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEgc2lnbmluZyBrZXkgYXQgJHtzaWduaW5nS2V5fSwgbm8gc3VjaCBmaWxlIGV4aXN0c2ApO1xuICAgIH1cblxuICAgIGF3YWl0IHJlZnVzZVVudXNhYmxlS2V5cyhyZXBvUGF0aCk7XG4gICAgYXdhaXQgcmVmdXNlUmV2b2tlZEtleXMocmVwb1BhdGgpO1xuXG4gICAgbGV0IG1hbmlmZXN0ID0gYXdhaXQgYnVpbGRNYW5pZmVzdChyZXBvUGF0aCk7XG4gICAgY29uc29sZS5sb2coYCR7TUFOSUZFU1RfTkFNRX0gY292ZXJzICR7bWFuaWZlc3QuZmlsZXMubGVuZ3RofSBmaWxlKHMpIGluICR7cmVwb1BhdGh9YCk7XG5cbiAgICAvLyBUaGUgbWFuaWZlc3QgaXMgYnVpbHQgYW5kIHNpZ25lZCBhd2F5IGZyb20gdGhlIHJlcG8sIGFuZCBvbmx5IG1vdmVkIGluIG9uY2UgYm90aCBleGlzdC5cbiAgICAvLyBMYW5kaW5nIGEgbmV3IG1hbmlmZXN0IG5leHQgdG8gYW4gb2xkIHNpZ25hdHVyZSBwcm9kdWNlcyBhIHBhaXIgdGhhdCBjYW4gbmV2ZXIgdmVyaWZ5LCBhbmRcbiAgICAvLyB0aGUgZGFlbW9uIHJlYWRpbmcgaXQgY2FuIG9ubHkgdHJlYXQgdGhhdCBhcyB0YW1wZXJpbmcuXG4gICAgbGV0IHN0YWdpbmdEaXJlY3RvcnkgPSBhd2FpdCBmcy5ta2R0ZW1wKHBhdGguam9pbihvcy50bXBkaXIoKSwgXCJzaWduZmlsZXMtXCIpKTtcbiAgICBsZXQgc3RhZ2VkTWFuaWZlc3QgPSBwYXRoLmpvaW4oc3RhZ2luZ0RpcmVjdG9yeSwgTUFOSUZFU1RfTkFNRSk7XG4gICAgbGV0IHN0YWdlZFNpZ25hdHVyZSA9IGAke3N0YWdlZE1hbmlmZXN0fS5zaWdgO1xuICAgIGF3YWl0IGZzLndyaXRlRmlsZShzdGFnZWRNYW5pZmVzdCwgZm9ybWF0TWFuaWZlc3QobWFuaWZlc3QpKTtcblxuICAgIC8vIFNpZ25pbmcgaGFwcGVucyBiZWZvcmUgYW55IGdpdCB3b3JrLCBzbyBhIGZhaWxlZCBwdXNoIG5ldmVyIGNvc3RzIGEgc2Vjb25kIHRvdWNoIG9mIHRoZSBrZXkuXG4gICAgYXdhaXQgcnVuUHJvbWlzZShgc3NoLWtleWdlbiAtWSBzaWduIC1mICR7cXVvdGUoc2lnbmluZ0tleSl9IC1uICR7U0lHTl9OQU1FU1BBQ0V9ICR7cXVvdGUoc3RhZ2VkTWFuaWZlc3QpfWApO1xuICAgIC8vIENoZWNrZWQgaGVyZSByYXRoZXIgdGhhbiBsZWZ0IGZvciBhIG1hY2hpbmUgdGhhdCBoYXMgYWxyZWFkeSBwdWxsZWQgaXQgdG8gZGlzY292ZXIuXG4gICAgYXdhaXQgcnVuUHJvbWlzZShcbiAgICAgICAgYHNzaC1rZXlnZW4gLVkgY2hlY2stbm92YWxpZGF0ZSAtbiAke1NJR05fTkFNRVNQQUNFfSAtcyAke3F1b3RlKHN0YWdlZFNpZ25hdHVyZSl9IDwgJHtxdW90ZShzdGFnZWRNYW5pZmVzdCl9YFxuICAgICk7XG4gICAgYXdhaXQgZnMuY29weUZpbGUoc3RhZ2VkTWFuaWZlc3QsIHBhdGguam9pbihyZXBvUGF0aCwgTUFOSUZFU1RfTkFNRSkpO1xuICAgIGF3YWl0IGZzLmNvcHlGaWxlKHN0YWdlZFNpZ25hdHVyZSwgcGF0aC5qb2luKHJlcG9QYXRoLCBTSUdOQVRVUkVfTkFNRSkpO1xuICAgIGF3YWl0IGZzLnJtKHN0YWdpbmdEaXJlY3RvcnksIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgICBjb25zb2xlLmxvZyhgU2lnbmVkIHdpdGggJHthd2FpdCBwdWJsaWNLZXlPZihzaWduaW5nS2V5KX1gKTtcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG1haW4oKSB7XG4gICAgbGV0IHsga2V5UGF0aCwgcHVzaFRvR2l0IH0gPSBwYXJzZUFyZ3MocHJvY2Vzcy5hcmd2LnNsaWNlKDIpKTtcblxuICAgIC8vIFRoZSBrZXlzIHJlcG8sIHdoaWNoIGlzIHRoaXMgb25lIHdoZW4gaXQgaG9sZHMga2V5cyBhbmQgdGhpcyBtYWNoaW5lJ3Mgb3RoZXJ3aXNlLiBTaWduaW5nXG4gICAgLy8gd2hhdGV2ZXIgcmVwbyB0aGUgdGVybWluYWwgaGFwcGVuZWQgdG8gYmUgaW4gaXMgaG93IHlvdSBlbmQgdXAgc2lnbmluZyBzb21ldGhpbmcgdGhhdCBpcyBub3RcbiAgICAvLyBhIGtleXMgcmVwbyBhdCBhbGwuXG4gICAgbGV0IHsgcmVwb1BhdGggfSA9IGF3YWl0IHJlc29sdmVLZXlzUmVwbygpO1xuICAgIGNvbnNvbGUubG9nKGBTaWduaW5nICR7cmVwb1BhdGh9YCk7XG4gICAgYXdhaXQgc2lnblJlcG8oeyByZXBvUGF0aCwga2V5UGF0aCB9KTtcblxuICAgIGlmICghcHVzaFRvR2l0KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBDb21taXQgYW5kIHB1c2ggJHtNQU5JRkVTVF9OQU1FfSBhbmQgJHtTSUdOQVRVUkVfTkFNRX0gZm9yIGFueXRoaW5nIHRvIHNlZSB0aGVtLmApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGF3YWl0IHJ1blByb21pc2UoYGdpdCBhZGQgLUFgLCB7IGN3ZDogcmVwb1BhdGggfSk7XG4gICAgLy8gTm90aGluZyBzdGFnZWQgaXMgbm90IHdvcnRoIHN0b3BwaW5nIG9uLiBnaXQgY29tbWl0IGNhbGxzIHRoYXQgYSBmYWlsdXJlLCBidXQgaXQgb25seSBtZWFuc1xuICAgIC8vIHRoZSBzaWduYXR1cmUgbWF0Y2hlcyB0aGUgb25lIGFscmVhZHkgY29tbWl0dGVkLCBzbyB0aGVyZSBpcyBub3RoaW5nIHRvIGRlcGxveS5cbiAgICBsZXQgc3RhdHVzID0gYXdhaXQgc3Bhd25Qcm9taXNlKHsgY29tbWFuZDogXCJnaXRcIiwgYXJnczogW1wic3RhdHVzXCIsIFwiLS1wb3JjZWxhaW5cIl0sIGN3ZDogcmVwb1BhdGggfSk7XG4gICAgbGV0IHN0YWdlZCA9IHN0YXR1cy5zdGRvdXQ7XG4gICAgaWYgKCFzdGFnZWQudHJpbSgpKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBOb3RoaW5nIGNoYW5nZWQsICR7TUFOSUZFU1RfTkFNRX0gYW5kICR7U0lHTkFUVVJFX05BTUV9IGFyZSBhbHJlYWR5IGNvbW1pdHRlZC5gKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgY29tbWl0IC1tICR7cXVvdGUoQ09NTUlUX01FU1NBR0UpfWAsIHsgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBhd2FpdCBydW5Qcm9taXNlKGBnaXQgcHVzaGAsIHsgY3dkOiByZXBvUGF0aCB9KTtcbiAgICBjb25zb2xlLmxvZyhgQ29tbWl0dGVkIGFuZCBwdXNoZWQuYCk7XG59XG4iXX0=
|
|
179
|
+
/* _JS_SOURCE_HASH = "e62739f311ed1c2d2b818032186647cfb19cc96beec3178194cb15bda564b243"; */
|
|
@@ -6,6 +6,7 @@ import { expandHome } from "../helpers/paths";
|
|
|
6
6
|
import { spawnPromise } from "../helpers/spawn";
|
|
7
7
|
import { buildManifest, formatManifest, MANIFEST_NAME, SIGNATURE_NAME, SIGN_NAMESPACE } from "./manifest";
|
|
8
8
|
import { revokedKeysInRepo } from "../authorizedKeys/unrevoke";
|
|
9
|
+
import { resolveKeysRepo } from "../authorizedKeys/keysRepo";
|
|
9
10
|
import { findKeyProblems, normalizeKeys } from "../authorizedKeys/authorizedKeys";
|
|
10
11
|
|
|
11
12
|
// A hardware backed key is the entire point. A key sitting on disk is compromised the moment the
|
|
@@ -159,16 +160,11 @@ export async function signRepo(config: { repoPath: string; keyPath?: string }) {
|
|
|
159
160
|
export async function main() {
|
|
160
161
|
let { keyPath, pushToGit } = parseArgs(process.argv.slice(2));
|
|
161
162
|
|
|
162
|
-
//
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
let repoPath =
|
|
166
|
-
|
|
167
|
-
throw new Error(
|
|
168
|
-
`Expected the current directory to be inside a git repo, it is not.\n`
|
|
169
|
-
+ `${(topLevel.stdout + topLevel.stderr).trim()}\n${USAGE}`
|
|
170
|
-
);
|
|
171
|
-
}
|
|
163
|
+
// The keys repo, which is this one when it holds keys and this machine's otherwise. Signing
|
|
164
|
+
// whatever repo the terminal happened to be in is how you end up signing something that is not
|
|
165
|
+
// a keys repo at all.
|
|
166
|
+
let { repoPath } = await resolveKeysRepo();
|
|
167
|
+
console.log(`Signing ${repoPath}`);
|
|
172
168
|
await signRepo({ repoPath, keyPath });
|
|
173
169
|
|
|
174
170
|
if (!pushToGit) {
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import fs from "fs/promises";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { UNREVOKE_DELAY } from "../authorizedKeys/daemon/paths";
|
|
4
|
-
import { keysDir } from "../authorizedKeys/sources";
|
|
5
|
-
import { messageTimestamp } from "../notifications/discord";
|
|
6
|
-
|
|
7
|
-
// When this machine first saw each unrevoke, by unrevoke id.
|
|
8
|
-
//
|
|
9
|
-
// The same rule the ssh keys get, for the same reason: an unrevoke waits an hour before it counts,
|
|
10
|
-
// so a signing key that was itself stolen cannot instantly undo the revocation that shut it out.
|
|
11
|
-
// Counted from when we first saw it, never from a time the file states - whoever wrote the file
|
|
12
|
-
// chooses that, and would choose an hour ago.
|
|
13
|
-
//
|
|
14
|
-
// On disk, because a check runs in whatever process happens to be asking. Measuring from process
|
|
15
|
-
// start would restart the hour on every request and the unrevoke would never arrive. Kept beside
|
|
16
|
-
// the repo keys rather than in the daemon's state, because this has to work on a machine with no
|
|
17
|
-
// daemon, which is most of them.
|
|
18
|
-
const FIRST_SEEN_FILE = "machine-unrevokes.json";
|
|
19
|
-
|
|
20
|
-
function firstSeenPath() {
|
|
21
|
-
return path.join(keysDir(), FIRST_SEEN_FILE);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
async function readFirstSeen(): Promise<{ [unrevokeId: string]: number }> {
|
|
25
|
-
try {
|
|
26
|
-
return JSON.parse(await fs.readFile(firstSeenPath(), "utf8"));
|
|
27
|
-
} catch (e) {
|
|
28
|
-
// Never written, or unreadable. Either way nothing has been seen before now.
|
|
29
|
-
return {};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Whether an unrevoke has waited out its hour, recording the first sighting if this is one.
|
|
34
|
-
|
|
35
|
-
Returns false the first time, which is the point: seeing an unrevoke is not the same as
|
|
36
|
-
honouring it. */
|
|
37
|
-
export async function unrevokeInEffect(unrevokeId: string) {
|
|
38
|
-
let firstSeen = await readFirstSeen();
|
|
39
|
-
let seenAt = firstSeen[unrevokeId];
|
|
40
|
-
if (!seenAt) {
|
|
41
|
-
seenAt = Date.now();
|
|
42
|
-
firstSeen[unrevokeId] = seenAt;
|
|
43
|
-
await fs.mkdir(path.dirname(firstSeenPath()), { recursive: true, mode: 0o700 });
|
|
44
|
-
await fs.writeFile(firstSeenPath(), JSON.stringify(firstSeen, undefined, 4) + "\n");
|
|
45
|
-
}
|
|
46
|
-
if (Date.now() - seenAt < UNREVOKE_DELAY) {
|
|
47
|
-
console.log(
|
|
48
|
-
`Holding the unrevoke ${unrevokeId} until ${messageTimestamp(new Date(seenAt + UNREVOKE_DELAY))}`
|
|
49
|
-
);
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
return true;
|
|
53
|
-
}
|