sliftutils 1.7.133 → 1.7.134

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/bin/addmachine.js +1 -5
  2. package/bin/derivekey.js +2 -7
  3. package/bin/portsecuredaemon.js +1 -8
  4. package/bin/securessh.js +2 -7
  5. package/bin/setupnotify.js +2 -6
  6. package/bin/signfiles.js +2 -7
  7. package/bin/testnotify.js +2 -6
  8. package/bin/unrevoke.js +1 -5
  9. package/misc/dist/ownIPs.ts.cache +2 -2
  10. package/misc/https/dist/certs.ts.cache +12 -9
  11. package/misc/https/dist/persistentLocalStorage.ts.cache +10 -4
  12. package/package.json +1 -1
  13. package/security/authorizedKeys/daemon/daemon.ts +142 -7
  14. package/security/authorizedKeys/daemon/dist/changes.ts.cache +2 -2
  15. package/security/authorizedKeys/daemon/dist/git.ts.cache +26 -8
  16. package/security/authorizedKeys/daemon/dist/notify.ts.cache +2 -2
  17. package/security/authorizedKeys/daemon/dist/paths.ts.cache +2 -2
  18. package/security/authorizedKeys/daemon/dist/repoFiles.ts.cache +4 -6
  19. package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
  20. package/security/authorizedKeys/daemon/dist/sessions.ts.cache +2 -2
  21. package/security/authorizedKeys/daemon/dist/state.ts.cache +2 -2
  22. package/security/authorizedKeys/daemon/dist/trust.ts.cache +85 -265
  23. package/security/authorizedKeys/daemon/git.d.ts +8 -0
  24. package/security/authorizedKeys/daemon/git.ts +22 -4
  25. package/security/authorizedKeys/daemon/repoFiles.ts +2 -4
  26. package/security/authorizedKeys/daemon/trust.d.ts +25 -19
  27. package/security/authorizedKeys/daemon/trust.ts +91 -278
  28. package/security/authorizedKeys/dist/authorizedKeys.ts.cache +2 -2
  29. package/security/authorizedKeys/dist/keysRepo.ts.cache +2 -2
  30. package/security/authorizedKeys/dist/revokeSource.ts.cache +2 -2
  31. package/security/authorizedKeys/dist/sources.ts.cache +2 -2
  32. package/security/authorizedKeys/secureSSH.ts +6 -1
  33. package/security/authorizedKeys/unrevoke.ts +2 -198
  34. package/security/authorizedKeys/unrevokeCli.ts +204 -0
  35. package/security/helpers/dist/paths.ts.cache +2 -2
  36. package/security/helpers/dist/remoteSSH.ts.cache +2 -2
  37. package/security/helpers/dist/spawn.ts.cache +2 -2
  38. package/security/helpers/remoteSSH.d.ts +35 -0
  39. package/security/keys/deriveKey.d.ts +0 -1
  40. package/security/keys/deriveKey.ts +1 -56
  41. package/security/keys/deriveKeyCli.ts +62 -0
  42. package/security/keys/dist/deriveKey.ts.cache +4 -51
  43. package/security/keys/dist/sshKeyFile.ts.cache +5 -3
  44. package/security/machines/addMachine.ts +31 -61
  45. package/security/machines/dist/addMachine.ts.cache +72 -57
  46. package/security/machines/dist/machines.ts.cache +134 -55
  47. package/security/machines/machines.d.ts +11 -0
  48. package/security/machines/machines.ts +134 -57
  49. package/security/notifications/dist/discord.ts.cache +2 -2
  50. package/security/notifications/setupNotify.ts +6 -1
  51. package/security/notifications/testNotify.ts +6 -1
  52. package/security/signedFiles/dist/manifest.ts.cache +2 -2
  53. package/security/signedFiles/dist/sshsig.ts.cache +138 -0
  54. package/security/signedFiles/signFiles.ts +11 -52
  55. package/security/signedFiles/signFilesCli.ts +54 -0
  56. package/security/signedFiles/sshsig.d.ts +13 -0
  57. package/security/signedFiles/sshsig.ts +141 -0
  58. package/storage/dist/backblaze.ts.cache +10 -2
@@ -1,295 +1,115 @@
1
- "use strict";
1
+ "use strict"; var console = (function shimConsole() { let baseConsole = globalThis.console; if (typeof window !== "undefined") return baseConsole; let name = __filename.replaceAll("\\", "/").split("/").pop(); let dirName = __dirname.replaceAll("\\", "/").split("/").pop(); let context = { __FILE__: __filename, __DIR__: __dirname, __NAME__: name, __DIRNAME__: dirName }; let newConsole = { ...baseConsole }; for (let shim of ["log", "info", "warn", "error"]) { newConsole[shim] = (...args) => { args.push(context); baseConsole[shim](...args); }; } newConsole.__context = context; return newConsole; })(); "use strict";
2
2
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
- //exports.resolveSourceKeys = exports.describeSigner = exports.verifyCheckout = exports.readCheckoutKeys = exports.publicKeyFromSignature = void 0;
6
+ //exports.readSignedRepo = exports.SignedRepoError = exports.UNSIGNED = void 0;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
8
  const promises_1 = __importDefault(require("fs/promises"));
9
9
  const path_1 = __importDefault(require("path"));
10
- const spawn_1 = require("../../helpers/spawn");
11
- const authorizedKeys_1 = require("../authorizedKeys");
12
- const sources_1 = require("../sources");
13
10
  const manifest_1 = require("../../signedFiles/manifest");
14
- const paths_1 = require("./paths");
15
- const notify_1 = require("./notify");
16
- const state_1 = require("./state");
11
+ const sshsig_1 = require("../../signedFiles/sshsig");
17
12
  // A source that has never been signed reads as this, so losing a signature counts as a change of
18
13
  // signer rather than as something to wave through.
19
- const UNSIGNED = "";
14
+ exports.UNSIGNED = "";
20
15
  // What fixes both of the signature problems we report, so the message can say so rather than
21
16
  // leaving someone to work it out.
22
17
  const SIGN_COMMAND = "yarn signfiles git";
23
- async function pathExists(filePath) {
24
- try {
25
- await promises_1.default.access(filePath);
26
- return true;
27
- }
28
- catch (e) {
29
- return false;
18
+ /** A repo that cannot be trusted, with the message ready for whoever asked. Not every caller
19
+ treats these the same - a source keeps its last keys, a machine list is just refused - so the
20
+ kind is carried rather than acted on here. */
21
+ class SignedRepoError extends Error {
22
+ constructor(problem, headline, body) {
23
+ super(`${headline}. ${body}`);
24
+ this.problem = problem;
25
+ this.headline = headline;
26
+ this.body = body;
30
27
  }
31
28
  }
32
- function readSSHString(buffer, offset) {
33
- let length = buffer.readUInt32BE(offset);
34
- return buffer.subarray(offset + 4, offset + 4 + length);
35
- }
36
- /** The signature carries the public key that made it, so the key itself can be reported rather
37
- than only a fingerprint. Returns it in the usual "type base64" form. */
38
- function publicKeyFromSignature(signatureText) {
39
- let body = signatureText.split("\n").filter(line => line && !line.startsWith("-----")).join("");
40
- let blob = Buffer.from(body, "base64");
41
- if (blob.subarray(0, 6).toString() !== "SSHSIG") {
42
- throw new Error(`Expected an SSHSIG signature, started with ${blob.subarray(0, 6).toString()}`);
43
- }
44
- // The magic, then a uint32 version, then the public key.
45
- let publicKey = readSSHString(blob, 6 + 4);
46
- let keyType = readSSHString(publicKey, 0).toString();
47
- let fingerprint = "SHA256:" + crypto_1.default.createHash("sha256").update(publicKey).digest("base64").replace(/=+$/, "");
48
- return { publicKey: `${keyType} ${publicKey.toString("base64")}`, fingerprint };
49
- }
50
- exports.publicKeyFromSignature = publicKeyFromSignature;
51
- /** Reads one checkout's keys. Prefers a top level authorized_keys file and otherwise concatenates
52
- every .pub at the top level. */
53
- async function readCheckoutKeys(repoPath) {
54
- let combinedPath = path_1.default.join(repoPath, "authorized_keys");
55
- if (await pathExists(combinedPath)) {
56
- return (0, authorizedKeys_1.normalizeKeys)(await promises_1.default.readFile(combinedPath, "utf8"));
57
- }
58
- let pubFiles = (await promises_1.default.readdir(repoPath)).filter(name => name.endsWith(".pub")).sort();
59
- if (!pubFiles.length) {
60
- throw new Error(`Expected authorized_keys or at least one .pub file in ${repoPath}, found neither`);
29
+ exports.SignedRepoError = SignedRepoError;
30
+ /** Everything a signed checkout vouches for, in one call: who signed it, and the contents of every
31
+ file the signature actually covers.
32
+
33
+ UNSIGNED with no files when there is no signature at all. Throws a SignedRepoError when a
34
+ signature is present but does not hold up, or when a file it signed for was changed or removed
35
+ without re-signing - either way the caller keeps whatever it last accepted rather than believing
36
+ a repo that no longer matches what was signed. A file not in the manifest is just unsigned, so
37
+ it is left out and warned about rather than treated as tampering. */
38
+ async function readSignedRepo(repoPath) {
39
+ let manifestBytes = await promises_1.default.readFile(path_1.default.join(repoPath, manifest_1.MANIFEST_NAME)).catch(() => undefined);
40
+ let signatureBytes = await promises_1.default.readFile(path_1.default.join(repoPath, manifest_1.SIGNATURE_NAME)).catch(() => undefined);
41
+ let manifestHash = manifestBytes && crypto_1.default.createHash("sha256").update(manifestBytes).digest("hex") || "";
42
+ let signatureHash = signatureBytes && crypto_1.default.createHash("sha256").update(signatureBytes).digest("hex") || "";
43
+ if (!manifestBytes && !signatureBytes) {
44
+ console.log(`${repoPath} is not signed, ignoring all of its files`);
45
+ return { signer: exports.UNSIGNED, manifestHash, signatureHash, files: new Map() };
46
+ }
47
+ let broken = (detail) => new SignedRepoError("corrupt", `KEY REPO SIGNATURE IS BROKEN`, `The signature on ${repoPath} does not check out, so everything in it is being ignored and`
48
+ + ` this machine keeps using what it last accepted.\n\n${detail}`
49
+ + `\n\nTo replace the signature, run in that repo:\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``);
50
+ if (!manifestBytes || !signatureBytes) {
51
+ throw broken(`Only one of ${manifest_1.MANIFEST_NAME} and ${manifest_1.SIGNATURE_NAME} is present.`);
61
52
  }
62
- let keys = [];
63
- for (let name of pubFiles) {
64
- keys.push(...(0, authorizedKeys_1.normalizeKeys)(await promises_1.default.readFile(path_1.default.join(repoPath, name), "utf8")));
53
+ let signer;
54
+ try {
55
+ // The signature covers the normalised bytes, so a checkout that arrived with CRLF still
56
+ // verifies rather than looking like tampering.
57
+ signer = (0, sshsig_1.verifySSHSIG)({
58
+ signature: signatureBytes.toString("utf8"),
59
+ message: (0, manifest_1.normalizeContent)(manifestBytes),
60
+ namespace: manifest_1.SIGN_NAMESPACE,
61
+ }).publicKey;
65
62
  }
66
- return keys;
67
- }
68
- exports.readCheckoutKeys = readCheckoutKeys;
69
- /** Every file in a checkout, other than git's own directory and the signature files, which cannot
70
- describe themselves. */
71
- async function listCheckoutFiles(repoPath, prefix) {
72
- let files = [];
73
- for (let entry of await promises_1.default.readdir(path_1.default.join(repoPath, prefix || ""), { withFileTypes: true })) {
74
- let relativePath = prefix && `${prefix}/${entry.name}` || entry.name;
75
- if (entry.name === ".git") {
76
- continue;
77
- }
78
- if (!prefix && (entry.name === manifest_1.MANIFEST_NAME || entry.name === manifest_1.SIGNATURE_NAME)) {
79
- continue;
80
- }
81
- if (entry.isDirectory()) {
82
- files.push(...await listCheckoutFiles(repoPath, relativePath));
83
- continue;
63
+ catch (e) {
64
+ throw broken(`${e}`);
65
+ }
66
+ let stale = (detail) => new SignedRepoError("stale", `KEY REPO CHANGED WITHOUT BEING SIGNED`, `${detail}, so the repo is being ignored and this machine keeps using what it last accepted.`
67
+ + `\n\nTo make the change take effect, run in that repo:\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``);
68
+ // Every file on disk, other than git's own directory and the two signature files, which cannot
69
+ // describe themselves.
70
+ let listCheckoutFiles = async (prefix) => {
71
+ let found = [];
72
+ for (let entry of await promises_1.default.readdir(path_1.default.join(repoPath, prefix || ""), { withFileTypes: true })) {
73
+ let relativePath = prefix && `${prefix}/${entry.name}` || entry.name;
74
+ if (entry.name === ".git")
75
+ continue;
76
+ if (!prefix && (entry.name === manifest_1.MANIFEST_NAME || entry.name === manifest_1.SIGNATURE_NAME))
77
+ continue;
78
+ if (entry.isDirectory()) {
79
+ found.push(...await listCheckoutFiles(relativePath));
80
+ continue;
81
+ }
82
+ found.push(relativePath);
84
83
  }
85
- files.push(relativePath);
86
- }
87
- return files.sort();
88
- }
89
- /** The signature only covers the manifest, so the manifest has to be checked against what is
90
- actually on disk. Both directions matter: a missing file changes what the keys mean, and an
91
- extra unlisted file could add keys nobody signed for. */
92
- async function verifyManifestMatchesFiles(repoPath) {
93
- let manifest = JSON.parse(await promises_1.default.readFile(path_1.default.join(repoPath, manifest_1.MANIFEST_NAME), "utf8"));
84
+ return found.sort();
85
+ };
86
+ let manifest = JSON.parse(manifestBytes.toString("utf8"));
94
87
  let listed = new Map((manifest.files || []).map((file) => [file.path, file]));
95
- let actual = await listCheckoutFiles(repoPath);
96
- let missing = [...listed.keys()].filter(filePath => !actual.includes(filePath));
97
- if (missing.length) {
98
- throw new Error(`Expected the signed files to be present, ${missing.length} missing, first ${missing[0]}`);
99
- }
100
- let extra = actual.filter(filePath => !listed.has(filePath));
101
- if (extra.length) {
102
- throw new Error(`Expected only signed files to be present, ${extra.length} extra, first ${extra[0]}`);
103
- }
104
- for (let filePath of actual) {
88
+ let files = new Map();
89
+ for (let filePath of await listCheckoutFiles()) {
105
90
  let expected = listed.get(filePath);
91
+ // A file the signature never mentioned is not tampering, it is just unsigned - left out
92
+ // rather than trusted. An extra file in a working tree is ordinary, so it is only a note.
106
93
  if (!expected) {
94
+ console.log(`Ignoring ${path_1.default.join(repoPath, filePath)}, it is not in the signed manifest`);
107
95
  continue;
108
96
  }
109
97
  let contents = (0, manifest_1.normalizeContent)(await promises_1.default.readFile(path_1.default.join(repoPath, filePath)));
110
- if (contents.length !== expected.size) {
111
- throw new Error(`Expected ${filePath} to be ${expected.size} bytes, was ${contents.length}`);
112
- }
113
98
  let hash = crypto_1.default.createHash("sha256").update(contents).digest("hex");
114
- if (hash !== expected.sha256) {
115
- throw new Error(`Expected ${filePath} to hash to ${expected.sha256}, was ${hash}`);
116
- }
117
- }
118
- }
119
- /** The manifest and signature as they stand, whether or not they are any good. The hashes are
120
- what tell a signature that was never updated apart from one that is broken. */
121
- async function readSignatureFiles(repoPath) {
122
- let manifestPath = path_1.default.join(repoPath, manifest_1.MANIFEST_NAME);
123
- let signaturePath = path_1.default.join(repoPath, manifest_1.SIGNATURE_NAME);
124
- let manifest = await pathExists(manifestPath) && await promises_1.default.readFile(manifestPath) || undefined;
125
- let signature = await pathExists(signaturePath) && await promises_1.default.readFile(signaturePath) || undefined;
126
- return {
127
- manifest,
128
- signature,
129
- manifestHash: manifest && crypto_1.default.createHash("sha256").update(manifest).digest("hex") || "",
130
- signatureHash: signature && crypto_1.default.createHash("sha256").update(signature).digest("hex") || "",
131
- };
132
- }
133
- /** Who signed this checkout. Returns UNSIGNED when there is no signature at all, and throws when
134
- there is one that does not hold up - an unverifiable signature is never treated as an identity,
135
- so it can never become something we accept. */
136
- async function verifyCheckoutSigner(config) {
137
- let { repoPath, files } = config;
138
- if (!files.manifest && !files.signature) {
139
- return UNSIGNED;
140
- }
141
- if (!files.manifest || !files.signature) {
142
- throw new Error(`Expected both ${manifest_1.MANIFEST_NAME} and ${manifest_1.SIGNATURE_NAME}, only one is present`);
143
- }
144
- let result = await (0, spawn_1.spawnPromise)({
145
- command: "ssh-keygen",
146
- args: ["-Y", "check-novalidate", "-n", manifest_1.SIGN_NAMESPACE, "-s", path_1.default.join(repoPath, manifest_1.SIGNATURE_NAME)],
147
- // The signature covers the normalised bytes, so a checkout that arrived with CRLF still
148
- // verifies rather than looking like tampering.
149
- input: (0, manifest_1.normalizeContent)(files.manifest).toString("utf8"),
150
- });
151
- if (result.status !== 0) {
152
- throw new Error(`the signature over ${manifest_1.MANIFEST_NAME} does not verify: `
153
- + `${(result.stdout + result.stderr).trim().slice(0, paths_1.MAX_ERROR_BODY_LENGTH)}`);
154
- }
155
- let reported = `${result.stdout} ${result.stderr}`.match(/(SHA256:[A-Za-z0-9+/=]+)/);
156
- if (!reported) {
157
- throw new Error(`ssh-keygen reported no signer fingerprint, said ${result.stdout.slice(0, paths_1.MAX_ERROR_BODY_LENGTH)}`);
158
- }
159
- let { publicKey, fingerprint } = publicKeyFromSignature(files.signature.toString("utf8"));
160
- // The key we read out of the signature has to be the one ssh-keygen just checked against,
161
- // otherwise we would be reporting an identity that did not sign anything.
162
- if (fingerprint !== reported[1]) {
163
- throw new Error(`the signing key reads as ${fingerprint} but ssh-keygen verified ${reported[1]}`);
164
- }
165
- await verifyManifestMatchesFiles(repoPath);
166
- return publicKey;
167
- }
168
- /** Proves a checkout on disk was signed, and that the files in it are the ones that were signed.
169
- Returns the signer, and throws if anything about that does not hold.
170
-
171
- Anything reading a repo for something other than ssh keys goes through this first: the whole
172
- checkout is covered by one manifest, so a machine list is exactly as trustworthy as the keys
173
- beside it, and neither is worth reading unsigned. */
174
- async function verifyCheckout(repoPath) {
175
- return await verifyCheckoutSigner({ repoPath, files: await readSignatureFiles(repoPath) });
176
- }
177
- exports.verifyCheckout = verifyCheckout;
178
- function describeSigner(signer) {
179
- return signer === UNSIGNED && "<no public key>" || signer;
180
- }
181
- exports.describeSigner = describeSigner;
182
- /** Reports a problem with a source's signature, but only when it is not the same problem we
183
- already reported, so a fault that persists does not repeat every check. */
184
- async function reportProblem(config) {
185
- let { repoURL, problem, headline, body } = config;
186
- let sourceStateValue = (0, state_1.sourceState)(repoURL);
187
- if (sourceStateValue.reportedProblem === problem) {
188
- return;
189
- }
190
- sourceStateValue.reportedProblem = problem;
191
- await (0, state_1.saveState)();
192
- await (0, notify_1.notify)(headline, body);
193
- }
194
- /** The keys a source is allowed to contribute right now. A source signed by someone we have not
195
- accepted keeps contributing the keys we last accepted, until the delay has passed. */
196
- async function resolveSourceKeys(repoURL) {
197
- let sourceStateValue = (0, state_1.sourceState)(repoURL);
198
- let repoPath = (0, sources_1.sourceRepoPath)(repoURL);
199
- let files = await readSignatureFiles(repoPath);
200
- let signer;
201
- try {
202
- signer = await verifyCheckoutSigner({ repoPath, files });
203
- }
204
- catch (e) {
205
- // Nothing here is trustworthy, so nothing here is used. Which of the two problems it is
206
- // depends on whether the signature is simply the one we already accepted.
207
- let unchanged = files.manifestHash === sourceStateValue.acceptedManifestHash
208
- && files.signatureHash === sourceStateValue.acceptedSignatureHash;
209
- if (unchanged) {
210
- await reportProblem({
211
- repoURL,
212
- problem: "stale",
213
- headline: `KEY REPO CHANGED WITHOUT BEING SIGNED`,
214
- body: `\`${repoURL}\` changed, but nobody signed the change, so it is being ignored`
215
- + ` and this machine is still using the keys signed by`
216
- + ` \`${describeSigner(sourceStateValue.acceptedSigner)}\`.`
217
- + `\n\nTo make the change take effect, run this in that repo:`
218
- + `\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``,
219
- });
220
- }
221
- else {
222
- await reportProblem({
223
- repoURL,
224
- problem: "corrupt",
225
- headline: `KEY REPO SIGNATURE IS BROKEN`,
226
- body: `The signature on \`${repoURL}\` does not check out, so everything in it is`
227
- + ` being ignored and this machine is still using the keys signed by`
228
- + ` \`${describeSigner(sourceStateValue.acceptedSigner)}\`.`
229
- + `\n\n${e}`
230
- + `\n\nTo replace the signature, run this in that repo:`
231
- + `\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``,
232
- });
99
+ // A file the manifest DOES name, but whose content no longer matches, is a signed file
100
+ // changed without re-signing - the repo being edited out from under its signature.
101
+ if (contents.length !== expected.size || hash !== expected.sha256) {
102
+ throw stale(`${path_1.default.join(repoPath, filePath)} was changed after it was signed`);
233
103
  }
234
- return sourceStateValue.acceptedKeys;
104
+ files.set(filePath, contents);
235
105
  }
236
- if (sourceStateValue.reportedProblem) {
237
- sourceStateValue.reportedProblem = "";
238
- await (0, state_1.saveState)();
239
- }
240
- let checkoutKeys = await readCheckoutKeys(repoPath);
241
- let accept = async () => {
242
- sourceStateValue.accepted = true;
243
- sourceStateValue.acceptedSigner = signer;
244
- sourceStateValue.acceptedKeys = checkoutKeys;
245
- sourceStateValue.acceptedManifestHash = files.manifestHash;
246
- sourceStateValue.acceptedSignatureHash = files.signatureHash;
247
- sourceStateValue.pendingSigner = UNSIGNED;
248
- sourceStateValue.pendingSince = 0;
249
- await (0, state_1.saveState)();
250
- return checkoutKeys;
251
- };
252
- // Nothing has ever been accepted from this source, so this is what we start trusting.
253
- if (!sourceStateValue.accepted) {
254
- console.log(`Trusting ${repoURL} as signed by ${describeSigner(signer)}`);
255
- return await accept();
256
- }
257
- if (signer === sourceStateValue.acceptedSigner) {
258
- // Back to the signer we already trust, so anything we were waiting on is moot.
259
- if (sourceStateValue.pendingSince) {
260
- console.log(`${repoURL} is signed by its accepted key again, dropping the pending change`);
106
+ for (let filePath of listed.keys()) {
107
+ if (!files.has(filePath)) {
108
+ throw stale(`${path_1.default.join(repoPath, filePath)} is signed for but missing`);
261
109
  }
262
- return await accept();
263
- }
264
- // Going from nothing to something signed is only ever an improvement, so it does not wait.
265
- if (sourceStateValue.acceptedSigner === UNSIGNED) {
266
- await (0, notify_1.notify)(`KEY REPO IS NOW SIGNED`, `\`${repoURL}\` was not signed at all before, so this is an improvement and its keys`
267
- + ` are being applied right away.`
268
- + `\n\nsigned by: \`${signer}\``);
269
- return await accept();
270
- }
271
- // A signer we have not accepted. Anything new restarts the wait, so publishing twice in a row
272
- // gains an attacker nothing. pendingSince is what marks a wait as running, because an unsigned
273
- // checkout is itself a signer value and cannot double as "nothing pending".
274
- if (!sourceStateValue.pendingSince || signer !== sourceStateValue.pendingSigner) {
275
- sourceStateValue.pendingSigner = signer;
276
- sourceStateValue.pendingSince = Date.now();
277
- await (0, state_1.saveState)();
278
- await (0, notify_1.notify)(`KEY REPO SIGNED BY A DIFFERENT KEY`, `Somebody else is signing \`${repoURL}\` now. Its keys are NOT being applied, and this`
279
- + ` machine is still using the ones it already had. If nothing changes, the new signer`
280
- + ` is accepted in 24 hours.`
281
- + `\n\nIf that was not you, fix the repo before the 24 hours are up.`
282
- + `\n\nsigned by now: \`${describeSigner(signer)}\``
283
- + `\nsigned by before: \`${describeSigner(sourceStateValue.acceptedSigner)}\``);
284
- return sourceStateValue.acceptedKeys;
285
- }
286
- if (Date.now() - sourceStateValue.pendingSince < paths_1.SIGNER_CHANGE_DELAY) {
287
- return sourceStateValue.acceptedKeys;
288
110
  }
289
- // Same new signer, 24 hours later, and nobody stopped it.
290
- console.log(`Accepting ${describeSigner(signer)} for ${repoURL} after the ${paths_1.SIGNER_CHANGE_DELAY}ms wait`);
291
- return await accept();
111
+ return { signer, manifestHash, signatureHash, files };
292
112
  }
293
- exports.resolveSourceKeys = resolveSourceKeys;
294
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJ1c3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0cnVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUN4QiwrQ0FBbUQ7QUFDbkQsc0RBQWtEO0FBQ2xELHdDQUE0QztBQUM1Qyx5REFBNkc7QUFDN0csbUNBQXFFO0FBQ3JFLHFDQUFrQztBQUNsQyxtQ0FBaUQ7QUFFakQsaUdBQWlHO0FBQ2pHLG1EQUFtRDtBQUNuRCxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUM7QUFDcEIsNkZBQTZGO0FBQzdGLGtDQUFrQztBQUNsQyxNQUFNLFlBQVksR0FBRyxvQkFBb0IsQ0FBQztBQUUxQyxLQUFLLFVBQVUsVUFBVSxDQUFDLFFBQWdCO0lBQ3RDLElBQUksQ0FBQztRQUNELE1BQU0sa0JBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUIsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDVCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFDLE1BQWMsRUFBRSxNQUFjO0lBQ2pELElBQUksTUFBTSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDekMsT0FBTyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsTUFBTSxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsQ0FBQztBQUM1RCxDQUFDO0FBRUQ7MkVBQzJFO0FBQzNFLFNBQWdCLHNCQUFzQixDQUFDLGFBQXFCO0lBQ3hELElBQUksSUFBSSxHQUFHLGFBQWEsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FB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QUMzQyxNQUFNLElBQUEsaUJBQVMsR0FBRSxDQUFDO1FBQ2xCLE1BQU0sSUFBQSxlQUFNLEVBQUMsb0NBQW9DLEVBQzdDLDhCQUE4QixPQUFPLGtEQUFrRDtjQUNyRixxRkFBcUY7Y0FDckYsMkJBQTJCO2NBQzNCLG1FQUFtRTtjQUNuRSx3QkFBd0IsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJO2NBQ2xELHlCQUF5QixjQUFjLENBQUMsZ0JBQWdCLENBQUMsY0FBYyxDQUFDLElBQUksQ0FDakYsQ0FBQztRQUNGLE9BQU8sZ0JBQWdCLENBQUMsWUFBWSxDQUFDO0lBQ3pDLENBQUM7SUFFRCxJQUFJLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLEdBQUcsMkJBQW1CLEVBQUUsQ0FBQztRQUNuRSxPQUFPLGdCQUFnQixDQUFDLFlBQVksQ0FBQztJQUN6QyxDQUFDO0lBRUQsMERBQTBEO0lBQzFELE9BQU8sQ0FBQyxHQUFHLENBQUMsYUFBYSxjQUFjLENBQUMsTUFBTSxDQUFDLFFBQVEsT0FBTyxjQUFjLDJCQUFtQixTQUFTLENBQUMsQ0FBQztJQUMxRyxPQUFPLE1BQU0sTUFBTSxFQUFFLENBQUM7QUFDMUIsQ0FBQztBQTFHRCw4Q0EwR0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY3J5cHRvIGZyb20gXCJjcnlwdG9cIjtcbmltcG9ydCBmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBzcGF3blByb21pc2UgfSBmcm9tIFwiLi4vLi4vaGVscGVycy9zcGF3blwiO1xuaW1wb3J0IHsgbm9ybWFsaXplS2V5cyB9IGZyb20gXCIuLi9hdXRob3JpemVkS2V5c1wiO1xuaW1wb3J0IHsgc291cmNlUmVwb1BhdGggfSBmcm9tIFwiLi4vc291cmNlc1wiO1xuaW1wb3J0IHsgTUFOSUZFU1RfTkFNRSwgbm9ybWFsaXplQ29udGVudCwgU0lHTl9OQU1FU1BBQ0UsIFNJR05BVFVSRV9OQU1FIH0gZnJvbSBcIi4uLy4uL3NpZ25lZEZpbGVzL21hbmlmZXN0XCI7XG5pbXBvcnQgeyBNQVhfRVJST1JfQk9EWV9MRU5HVEgsIFNJR05FUl9DSEFOR0VfREVMQVkgfSBmcm9tIFwiLi9wYXRoc1wiO1xuaW1wb3J0IHsgbm90aWZ5IH0gZnJvbSBcIi4vbm90aWZ5XCI7XG5pbXBvcnQgeyBzYXZlU3RhdGUsIHNvdXJjZVN0YXRlIH0gZnJvbSBcIi4vc3RhdGVcIjtcblxuLy8gQSBzb3VyY2UgdGhhdCBoYXMgbmV2ZXIgYmVlbiBzaWduZWQgcmVhZHMgYXMgdGhpcywgc28gbG9zaW5nIGEgc2lnbmF0dXJlIGNvdW50cyBhcyBhIGNoYW5nZSBvZlxuLy8gc2lnbmVyIHJhdGhlciB0aGFuIGFzIHNvbWV0aGluZyB0byB3YXZlIHRocm91Z2guXG5jb25zdCBVTlNJR05FRCA9IFwiXCI7XG4vLyBXaGF0IGZpeGVzIGJvdGggb2YgdGhlIHNpZ25hdHVyZSBwcm9ibGVtcyB3ZSByZXBvcnQsIHNvIHRoZSBtZXNzYWdlIGNhbiBzYXkgc28gcmF0aGVyIHRoYW5cbi8vIGxlYXZpbmcgc29tZW9uZSB0byB3b3JrIGl0IG91dC5cbmNvbnN0IFNJR05fQ09NTUFORCA9IFwieWFybiBzaWduZmlsZXMgZ2l0XCI7XG5cbmFzeW5jIGZ1bmN0aW9uIHBhdGhFeGlzdHMoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZzLmFjY2VzcyhmaWxlUGF0aCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gcmVhZFNTSFN0cmluZyhidWZmZXI6IEJ1ZmZlciwgb2Zmc2V0OiBudW1iZXIpIHtcbiAgICBsZXQgbGVuZ3RoID0gYnVmZmVyLnJlYWRVSW50MzJCRShvZmZzZXQpO1xuICAgIHJldHVybiBidWZmZXIuc3ViYXJyYXkob2Zmc2V0ICsgNCwgb2Zmc2V0ICsgNCArIGxlbmd0aCk7XG59XG5cbi8qKiBUaGUgc2lnbmF0dXJlIGNhcnJpZXMgdGhlIHB1YmxpYyBrZXkgdGhhdCBtYWRlIGl0LCBzbyB0aGUga2V5IGl0c2VsZiBjYW4gYmUgcmVwb3J0ZWQgcmF0aGVyXG4gICAgdGhhbiBvbmx5IGEgZmluZ2VycHJpbnQuIFJldHVybnMgaXQgaW4gdGhlIHVzdWFsIFwidHlwZSBiYXNlNjRcIiBmb3JtLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHB1YmxpY0tleUZyb21TaWduYXR1cmUoc2lnbmF0dXJlVGV4dDogc3RyaW5nKSB7XG4gICAgbGV0IGJvZHkgPSBzaWduYXR1cmVUZXh0LnNwbGl0KFwiXFxuXCIpLmZpbHRlcihsaW5lID0+IGxpbmUgJiYgIWxpbmUuc3RhcnRzV2l0aChcIi0tLS0tXCIpKS5qb2luKFwiXCIpO1xuICAgIGxldCBibG9iID0gQnVmZmVyLmZyb20oYm9keSwgXCJiYXNlNjRcIik7XG4gICAgaWYgKGJsb2Iuc3ViYXJyYXkoMCwgNikudG9TdHJpbmcoKSAhPT0gXCJTU0hTSUdcIikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGFuIFNTSFNJRyBzaWduYXR1cmUsIHN0YXJ0ZWQgd2l0aCAke2Jsb2Iuc3ViYXJyYXkoMCwgNikudG9TdHJpbmcoKX1gKTtcbiAgICB9XG4gICAgLy8gVGhlIG1hZ2ljLCB0aGVuIGEgdWludDMyIHZlcnNpb24sIHRoZW4gdGhlIHB1YmxpYyBrZXkuXG4gICAgbGV0IHB1YmxpY0tleSA9IHJlYWRTU0hTdHJpbmcoYmxvYiwgNiArIDQpO1xuICAgIGxldCBrZXlUeXBlID0gcmVhZFNTSFN0cmluZyhwdWJsaWNLZXksIDApLnRvU3RyaW5nKCk7XG4gICAgbGV0IGZpbmdlcnByaW50ID0gXCJTSEEyNTY6XCIgKyBjcnlwdG8uY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUocHVibGljS2V5KS5kaWdlc3QoXCJiYXNlNjRcIikucmVwbGFjZSgvPSskLywgXCJcIik7XG4gICAgcmV0dXJuIHsgcHVibGljS2V5OiBgJHtrZXlUeXBlfSAke3B1YmxpY0tleS50b1N0cmluZyhcImJhc2U2NFwiKX1gLCBmaW5nZXJwcmludCB9O1xufVxuXG4vKiogUmVhZHMgb25lIGNoZWNrb3V0J3Mga2V5cy4gUHJlZmVycyBhIHRvcCBsZXZlbCBhdXRob3JpemVkX2tleXMgZmlsZSBhbmQgb3RoZXJ3aXNlIGNvbmNhdGVuYXRlc1xuICAgIGV2ZXJ5IC5wdWIgYXQgdGhlIHRvcCBsZXZlbC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkQ2hlY2tvdXRLZXlzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgY29tYmluZWRQYXRoID0gcGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKTtcbiAgICBpZiAoYXdhaXQgcGF0aEV4aXN0cyhjb21iaW5lZFBhdGgpKSB7XG4gICAgICAgIHJldHVybiBub3JtYWxpemVLZXlzKGF3YWl0IGZzLnJlYWRGaWxlKGNvbWJpbmVkUGF0aCwgXCJ1dGY4XCIpKTtcbiAgICB9XG4gICAgbGV0IHB1YkZpbGVzID0gKGF3YWl0IGZzLnJlYWRkaXIocmVwb1BhdGgpKS5maWx0ZXIobmFtZSA9PiBuYW1lLmVuZHNXaXRoKFwiLnB1YlwiKSkuc29ydCgpO1xuICAgIGlmICghcHViRmlsZXMubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYXV0aG9yaXplZF9rZXlzIG9yIGF0IGxlYXN0IG9uZSAucHViIGZpbGUgaW4gJHtyZXBvUGF0aH0sIGZvdW5kIG5laXRoZXJgKTtcbiAgICB9XG4gICAgbGV0IGtleXM6IHN0cmluZ1tdID0gW107XG4gICAgZm9yIChsZXQgbmFtZSBvZiBwdWJGaWxlcykge1xuICAgICAgICBrZXlzLnB1c2goLi4ubm9ybWFsaXplS2V5cyhhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4ocmVwb1BhdGgsIG5hbWUpLCBcInV0ZjhcIikpKTtcbiAgICB9XG4gICAgcmV0dXJuIGtleXM7XG59XG5cbi8qKiBFdmVyeSBmaWxlIGluIGEgY2hlY2tvdXQsIG90aGVyIHRoYW4gZ2l0J3Mgb3duIGRpcmVjdG9yeSBhbmQgdGhlIHNpZ25hdHVyZSBmaWxlcywgd2hpY2ggY2Fubm90XG4gICAgZGVzY3JpYmUgdGhlbXNlbHZlcy4gKi9cbmFzeW5jIGZ1bmN0aW9uIGxpc3RDaGVja291dEZpbGVzKHJlcG9QYXRoOiBzdHJpbmcsIHByZWZpeD86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgICBsZXQgZmlsZXM6IHN0cmluZ1tdID0gW107XG4gICAgZm9yIChsZXQgZW50cnkgb2YgYXdhaXQgZnMucmVhZGRpcihwYXRoLmpvaW4ocmVwb1BhdGgsIHByZWZpeCB8fCBcIlwiKSwgeyB3aXRoRmlsZVR5cGVzOiB0cnVlIH0pKSB7XG4gICAgICAgIGxldCByZWxhdGl2ZVBhdGggPSBwcmVmaXggJiYgYCR7cHJlZml4fS8ke2VudHJ5Lm5hbWV9YCB8fCBlbnRyeS5uYW1lO1xuICAgICAgICBpZiAoZW50cnkubmFtZSA9PT0gXCIuZ2l0XCIpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghcHJlZml4ICYmIChlbnRyeS5uYW1lID09PSBNQU5JRkVTVF9OQU1FIHx8IGVudHJ5Lm5hbWUgPT09IFNJR05BVFVSRV9OQU1FKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHtcbiAgICAgICAgICAgIGZpbGVzLnB1c2goLi4uYXdhaXQgbGlzdENoZWNrb3V0RmlsZXMocmVwb1BhdGgsIHJlbGF0aXZlUGF0aCkpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgZmlsZXMucHVzaChyZWxhdGl2ZVBhdGgpO1xuICAgIH1cbiAgICByZXR1cm4gZmlsZXMuc29ydCgpO1xufVxuXG4vKiogVGhlIHNpZ25hdHVyZSBvbmx5IGNvdmVycyB0aGUgbWFuaWZlc3QsIHNvIHRoZSBtYW5pZmVzdCBoYXMgdG8gYmUgY2hlY2tlZCBhZ2FpbnN0IHdoYXQgaXNcbiAgICBhY3R1YWxseSBvbiBkaXNrLiBCb3RoIGRpcmVjdGlvbnMgbWF0dGVyOiBhIG1pc3NpbmcgZmlsZSBjaGFuZ2VzIHdoYXQgdGhlIGtleXMgbWVhbiwgYW5kIGFuXG4gICAgZXh0cmEgdW5saXN0ZWQgZmlsZSBjb3VsZCBhZGQga2V5cyBub2JvZHkgc2lnbmVkIGZvci4gKi9cbmFzeW5jIGZ1bmN0aW9uIHZlcmlmeU1hbmlmZXN0TWF0Y2hlc0ZpbGVzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgbWFuaWZlc3QgPSBKU09OLnBhcnNlKGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgTUFOSUZFU1RfTkFNRSksIFwidXRmOFwiKSk7XG4gICAgbGV0IGxpc3RlZCA9IG5ldyBNYXA8c3RyaW5nLCB7IHBhdGg6IHN0cmluZzsgc2l6ZTogbnVtYmVyOyBzaGEyNTY6IHN0cmluZyB9PihcbiAgICAgICAgKG1hbmlmZXN0LmZpbGVzIHx8IFtdKS5tYXAoKGZpbGU6IHsgcGF0aDogc3RyaW5nIH0pID0+IFtmaWxlLnBhdGgsIGZpbGVdKVxuICAgICk7XG4gICAgbGV0IGFjdHVhbCA9IGF3YWl0IGxpc3RDaGVja291dEZpbGVzKHJlcG9QYXRoKTtcblxuICAgIGxldCBtaXNzaW5nID0gWy4uLmxpc3RlZC5rZXlzKCldLmZpbHRlcihmaWxlUGF0aCA9PiAhYWN0dWFsLmluY2x1ZGVzKGZpbGVQYXRoKSk7XG4gICAgaWYgKG1pc3NpbmcubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgdGhlIHNpZ25lZCBmaWxlcyB0byBiZSBwcmVzZW50LCAke21pc3NpbmcubGVuZ3RofSBtaXNzaW5nLCBmaXJzdCAke21pc3NpbmdbMF19YCk7XG4gICAgfVxuICAgIGxldCBleHRyYSA9IGFjdHVhbC5maWx0ZXIoZmlsZVBhdGggPT4gIWxpc3RlZC5oYXMoZmlsZVBhdGgpKTtcbiAgICBpZiAoZXh0cmEubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb25seSBzaWduZWQgZmlsZXMgdG8gYmUgcHJlc2VudCwgJHtleHRyYS5sZW5ndGh9IGV4dHJhLCBmaXJzdCAke2V4dHJhWzBdfWApO1xuICAgIH1cbiAgICBmb3IgKGxldCBmaWxlUGF0aCBvZiBhY3R1YWwpIHtcbiAgICAgICAgbGV0IGV4cGVjdGVkID0gbGlzdGVkLmdldChmaWxlUGF0aCk7XG4gICAgICAgIGlmICghZXhwZWN0ZWQpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGxldCBjb250ZW50cyA9IG5vcm1hbGl6ZUNvbnRlbnQoYXdhaXQgZnMucmVhZEZpbGUocGF0aC5qb2luKHJlcG9QYXRoLCBmaWxlUGF0aCkpKTtcbiAgICAgICAgaWYgKGNvbnRlbnRzLmxlbmd0aCAhPT0gZXhwZWN0ZWQuc2l6ZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCAke2ZpbGVQYXRofSB0byBiZSAke2V4cGVjdGVkLnNpemV9IGJ5dGVzLCB3YXMgJHtjb250ZW50cy5sZW5ndGh9YCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUoY29udGVudHMpLmRpZ2VzdChcImhleFwiKTtcbiAgICAgICAgaWYgKGhhc2ggIT09IGV4cGVjdGVkLnNoYTI1Nikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCAke2ZpbGVQYXRofSB0byBoYXNoIHRvICR7ZXhwZWN0ZWQuc2hhMjU2fSwgd2FzICR7aGFzaH1gKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqIFRoZSBtYW5pZmVzdCBhbmQgc2lnbmF0dXJlIGFzIHRoZXkgc3RhbmQsIHdoZXRoZXIgb3Igbm90IHRoZXkgYXJlIGFueSBnb29kLiBUaGUgaGFzaGVzIGFyZVxuICAgIHdoYXQgdGVsbCBhIHNpZ25hdHVyZSB0aGF0IHdhcyBuZXZlciB1cGRhdGVkIGFwYXJ0IGZyb20gb25lIHRoYXQgaXMgYnJva2VuLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVhZFNpZ25hdHVyZUZpbGVzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgbWFuaWZlc3RQYXRoID0gcGF0aC5qb2luKHJlcG9QYXRoLCBNQU5JRkVTVF9OQU1FKTtcbiAgICBsZXQgc2lnbmF0dXJlUGF0aCA9IHBhdGguam9pbihyZXBvUGF0aCwgU0lHTkFUVVJFX05BTUUpO1xuICAgIGxldCBtYW5pZmVzdCA9IGF3YWl0IHBhdGhFeGlzdHMobWFuaWZlc3RQYXRoKSAmJiBhd2FpdCBmcy5yZWFkRmlsZShtYW5pZmVzdFBhdGgpIHx8IHVuZGVmaW5lZDtcbiAgICBsZXQgc2lnbmF0dXJlID0gYXdhaXQgcGF0aEV4aXN0cyhzaWduYXR1cmVQYXRoKSAmJiBhd2FpdCBmcy5yZWFkRmlsZShzaWduYXR1cmVQYXRoKSB8fCB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbWFuaWZlc3QsXG4gICAgICAgIHNpZ25hdHVyZSxcbiAgICAgICAgbWFuaWZlc3RIYXNoOiBtYW5pZmVzdCAmJiBjcnlwdG8uY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUobWFuaWZlc3QpLmRpZ2VzdChcImhleFwiKSB8fCBcIlwiLFxuICAgICAgICBzaWduYXR1cmVIYXNoOiBzaWduYXR1cmUgJiYgY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKHNpZ25hdHVyZSkuZGlnZXN0KFwiaGV4XCIpIHx8IFwiXCIsXG4gICAgfTtcbn1cblxuLyoqIFdobyBzaWduZWQgdGhpcyBjaGVja291dC4gUmV0dXJucyBVTlNJR05FRCB3aGVuIHRoZXJlIGlzIG5vIHNpZ25hdHVyZSBhdCBhbGwsIGFuZCB0aHJvd3Mgd2hlblxuICAgIHRoZXJlIGlzIG9uZSB0aGF0IGRvZXMgbm90IGhvbGQgdXAgLSBhbiB1bnZlcmlmaWFibGUgc2lnbmF0dXJlIGlzIG5ldmVyIHRyZWF0ZWQgYXMgYW4gaWRlbnRpdHksXG4gICAgc28gaXQgY2FuIG5ldmVyIGJlY29tZSBzb21ldGhpbmcgd2UgYWNjZXB0LiAqL1xuYXN5bmMgZnVuY3Rpb24gdmVyaWZ5Q2hlY2tvdXRTaWduZXIoY29uZmlnOiB7XG4gICAgcmVwb1BhdGg6IHN0cmluZztcbiAgICBmaWxlczogeyBtYW5pZmVzdD86IEJ1ZmZlcjsgc2lnbmF0dXJlPzogQnVmZmVyIH07XG59KSB7XG4gICAgbGV0IHsgcmVwb1BhdGgsIGZpbGVzIH0gPSBjb25maWc7XG4gICAgaWYgKCFmaWxlcy5tYW5pZmVzdCAmJiAhZmlsZXMuc2lnbmF0dXJlKSB7XG4gICAgICAgIHJldHVybiBVTlNJR05FRDtcbiAgICB9XG4gICAgaWYgKCFmaWxlcy5tYW5pZmVzdCB8fCAhZmlsZXMuc2lnbmF0dXJlKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYm90aCAke01BTklGRVNUX05BTUV9IGFuZCAke1NJR05BVFVSRV9OQU1FfSwgb25seSBvbmUgaXMgcHJlc2VudGApO1xuICAgIH1cbiAgICBsZXQgcmVzdWx0ID0gYXdhaXQgc3Bhd25Qcm9taXNlKHtcbiAgICAgICAgY29tbWFuZDogXCJzc2gta2V5Z2VuXCIsXG4gICAgICAgIGFyZ3M6IFtcIi1ZXCIsIFwiY2hlY2stbm92YWxpZGF0ZVwiLCBcIi1uXCIsIFNJR05fTkFNRVNQQUNFLCBcIi1zXCIsIHBhdGguam9pbihyZXBvUGF0aCwgU0lHTkFUVVJFX05BTUUpXSxcbiAgICAgICAgLy8gVGhlIHNpZ25hdHVyZSBjb3ZlcnMgdGhlIG5vcm1hbGlzZWQgYnl0ZXMsIHNvIGEgY2hlY2tvdXQgdGhhdCBhcnJpdmVkIHdpdGggQ1JMRiBzdGlsbFxuICAgICAgICAvLyB2ZXJpZmllcyByYXRoZXIgdGhhbiBsb29raW5nIGxpa2UgdGFtcGVyaW5nLlxuICAgICAgICBpbnB1dDogbm9ybWFsaXplQ29udGVudChmaWxlcy5tYW5pZmVzdCkudG9TdHJpbmcoXCJ1dGY4XCIpLFxuICAgIH0pO1xuICAgIGlmIChyZXN1bHQuc3RhdHVzICE9PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICAgICAgIGB0aGUgc2lnbmF0dXJlIG92ZXIgJHtNQU5JRkVTVF9OQU1FfSBkb2VzIG5vdCB2ZXJpZnk6IGBcbiAgICAgICAgICAgICsgYCR7KHJlc3VsdC5zdGRvdXQgKyByZXN1bHQuc3RkZXJyKS50cmltKCkuc2xpY2UoMCwgTUFYX0VSUk9SX0JPRFlfTEVOR1RIKX1gXG4gICAgICAgICk7XG4gICAgfVxuICAgIGxldCByZXBvcnRlZCA9IGAke3Jlc3VsdC5zdGRvdXR9ICR7cmVzdWx0LnN0ZGVycn1gLm1hdGNoKC8oU0hBMjU2OltBLVphLXowLTkrLz1dKykvKTtcbiAgICBpZiAoIXJlcG9ydGVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgc3NoLWtleWdlbiByZXBvcnRlZCBubyBzaWduZXIgZmluZ2VycHJpbnQsIHNhaWQgJHtyZXN1bHQuc3Rkb3V0LnNsaWNlKDAsIE1BWF9FUlJPUl9CT0RZX0xFTkdUSCl9YCk7XG4gICAgfVxuICAgIGxldCB7IHB1YmxpY0tleSwgZmluZ2VycHJpbnQgfSA9IHB1YmxpY0tleUZyb21TaWduYXR1cmUoZmlsZXMuc2lnbmF0dXJlLnRvU3RyaW5nKFwidXRmOFwiKSk7XG4gICAgLy8gVGhlIGtleSB3ZSByZWFkIG91dCBvZiB0aGUgc2lnbmF0dXJlIGhhcyB0byBiZSB0aGUgb25lIHNzaC1rZXlnZW4ganVzdCBjaGVja2VkIGFnYWluc3QsXG4gICAgLy8gb3RoZXJ3aXNlIHdlIHdvdWxkIGJlIHJlcG9ydGluZyBhbiBpZGVudGl0eSB0aGF0IGRpZCBub3Qgc2lnbiBhbnl0aGluZy5cbiAgICBpZiAoZmluZ2VycHJpbnQgIT09IHJlcG9ydGVkWzFdKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdGhlIHNpZ25pbmcga2V5IHJlYWRzIGFzICR7ZmluZ2VycHJpbnR9IGJ1dCBzc2gta2V5Z2VuIHZlcmlmaWVkICR7cmVwb3J0ZWRbMV19YCk7XG4gICAgfVxuICAgIGF3YWl0IHZlcmlmeU1hbmlmZXN0TWF0Y2hlc0ZpbGVzKHJlcG9QYXRoKTtcbiAgICByZXR1cm4gcHVibGljS2V5O1xufVxuXG4vKiogUHJvdmVzIGEgY2hlY2tvdXQgb24gZGlzayB3YXMgc2lnbmVkLCBhbmQgdGhhdCB0aGUgZmlsZXMgaW4gaXQgYXJlIHRoZSBvbmVzIHRoYXQgd2VyZSBzaWduZWQuXG4gICAgUmV0dXJucyB0aGUgc2lnbmVyLCBhbmQgdGhyb3dzIGlmIGFueXRoaW5nIGFib3V0IHRoYXQgZG9lcyBub3QgaG9sZC5cblxuICAgIEFueXRoaW5nIHJlYWRpbmcgYSByZXBvIGZvciBzb21ldGhpbmcgb3RoZXIgdGhhbiBzc2gga2V5cyBnb2VzIHRocm91Z2ggdGhpcyBmaXJzdDogdGhlIHdob2xlXG4gICAgY2hlY2tvdXQgaXMgY292ZXJlZCBieSBvbmUgbWFuaWZlc3QsIHNvIGEgbWFjaGluZSBsaXN0IGlzIGV4YWN0bHkgYXMgdHJ1c3R3b3J0aHkgYXMgdGhlIGtleXNcbiAgICBiZXNpZGUgaXQsIGFuZCBuZWl0aGVyIGlzIHdvcnRoIHJlYWRpbmcgdW5zaWduZWQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdmVyaWZ5Q2hlY2tvdXQocmVwb1BhdGg6IHN0cmluZykge1xuICAgIHJldHVybiBhd2FpdCB2ZXJpZnlDaGVja291dFNpZ25lcih7IHJlcG9QYXRoLCBmaWxlczogYXdhaXQgcmVhZFNpZ25hdHVyZUZpbGVzKHJlcG9QYXRoKSB9KTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlc2NyaWJlU2lnbmVyKHNpZ25lcjogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHNpZ25lciA9PT0gVU5TSUdORUQgJiYgXCI8bm8gcHVibGljIGtleT5cIiB8fCBzaWduZXI7XG59XG5cbi8qKiBSZXBvcnRzIGEgcHJvYmxlbSB3aXRoIGEgc291cmNlJ3Mgc2lnbmF0dXJlLCBidXQgb25seSB3aGVuIGl0IGlzIG5vdCB0aGUgc2FtZSBwcm9ibGVtIHdlXG4gICAgYWxyZWFkeSByZXBvcnRlZCwgc28gYSBmYXVsdCB0aGF0IHBlcnNpc3RzIGRvZXMgbm90IHJlcGVhdCBldmVyeSBjaGVjay4gKi9cbmFzeW5jIGZ1bmN0aW9uIHJlcG9ydFByb2JsZW0oY29uZmlnOiB7IHJlcG9VUkw6IHN0cmluZzsgcHJvYmxlbTogc3RyaW5nOyBoZWFkbGluZTogc3RyaW5nOyBib2R5OiBzdHJpbmcgfSkge1xuICAgIGxldCB7IHJlcG9VUkwsIHByb2JsZW0sIGhlYWRsaW5lLCBib2R5IH0gPSBjb25maWc7XG4gICAgbGV0IHNvdXJjZVN0YXRlVmFsdWUgPSBzb3VyY2VTdGF0ZShyZXBvVVJMKTtcbiAgICBpZiAoc291cmNlU3RhdGVWYWx1ZS5yZXBvcnRlZFByb2JsZW0gPT09IHByb2JsZW0pIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBzb3VyY2VTdGF0ZVZhbHVlLnJlcG9ydGVkUHJvYmxlbSA9IHByb2JsZW07XG4gICAgYXdhaXQgc2F2ZVN0YXRlKCk7XG4gICAgYXdhaXQgbm90aWZ5KGhlYWRsaW5lLCBib2R5KTtcbn1cblxuLyoqIFRoZSBrZXlzIGEgc291cmNlIGlzIGFsbG93ZWQgdG8gY29udHJpYnV0ZSByaWdodCBub3cuIEEgc291cmNlIHNpZ25lZCBieSBzb21lb25lIHdlIGhhdmUgbm90XG4gICAgYWNjZXB0ZWQga2VlcHMgY29udHJpYnV0aW5nIHRoZSBrZXlzIHdlIGxhc3QgYWNjZXB0ZWQsIHVudGlsIHRoZSBkZWxheSBoYXMgcGFzc2VkLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlc29sdmVTb3VyY2VLZXlzKHJlcG9VUkw6IHN0cmluZykge1xuICAgIGxldCBzb3VyY2VTdGF0ZVZhbHVlID0gc291cmNlU3RhdGUocmVwb1VSTCk7XG4gICAgbGV0IHJlcG9QYXRoID0gc291cmNlUmVwb1BhdGgocmVwb1VSTCk7XG4gICAgbGV0IGZpbGVzID0gYXdhaXQgcmVhZFNpZ25hdHVyZUZpbGVzKHJlcG9QYXRoKTtcblxuICAgIGxldCBzaWduZXI6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgICBzaWduZXIgPSBhd2FpdCB2ZXJpZnlDaGVja291dFNpZ25lcih7IHJlcG9QYXRoLCBmaWxlcyB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIE5vdGhpbmcgaGVyZSBpcyB0cnVzdHdvcnRoeSwgc28gbm90aGluZyBoZXJlIGlzIHVzZWQuIFdoaWNoIG9mIHRoZSB0d28gcHJvYmxlbXMgaXQgaXNcbiAgICAgICAgLy8gZGVwZW5kcyBvbiB3aGV0aGVyIHRoZSBzaWduYXR1cmUgaXMgc2ltcGx5IHRoZSBvbmUgd2UgYWxyZWFkeSBhY2NlcHRlZC5cbiAgICAgICAgbGV0IHVuY2hhbmdlZCA9IGZpbGVzLm1hbmlmZXN0SGFzaCA9PT0gc291cmNlU3RhdGVWYWx1ZS5hY2NlcHRlZE1hbmlmZXN0SGFzaFxuICAgICAgICAgICAgJiYgZmlsZXMuc2lnbmF0dXJlSGFzaCA9PT0gc291cmNlU3RhdGVWYWx1ZS5hY2NlcHRlZFNpZ25hdHVyZUhhc2g7XG4gICAgICAgIGlmICh1bmNoYW5nZWQpIHtcbiAgICAgICAgICAgIGF3YWl0IHJlcG9ydFByb2JsZW0oe1xuICAgICAgICAgICAgICAgIHJlcG9VUkwsXG4gICAgICAgICAgICAgICAgcHJvYmxlbTogXCJzdGFsZVwiLFxuICAgICAgICAgICAgICAgIGhlYWRsaW5lOiBgS0VZIFJFUE8gQ0hBTkdFRCBXSVRIT1VUIEJFSU5HIFNJR05FRGAsXG4gICAgICAgICAgICAgICAgYm9keTogYFxcYCR7cmVwb1VSTH1cXGAgY2hhbmdlZCwgYnV0IG5vYm9keSBzaWduZWQgdGhlIGNoYW5nZSwgc28gaXQgaXMgYmVpbmcgaWdub3JlZGBcbiAgICAgICAgICAgICAgICAgICAgKyBgIGFuZCB0aGlzIG1hY2hpbmUgaXMgc3RpbGwgdXNpbmcgdGhlIGtleXMgc2lnbmVkIGJ5YFxuICAgICAgICAgICAgICAgICAgICArIGAgXFxgJHtkZXNjcmliZVNpZ25lcihzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkU2lnbmVyKX1cXGAuYFxuICAgICAgICAgICAgICAgICAgICArIGBcXG5cXG5UbyBtYWtlIHRoZSBjaGFuZ2UgdGFrZSBlZmZlY3QsIHJ1biB0aGlzIGluIHRoYXQgcmVwbzpgXG4gICAgICAgICAgICAgICAgICAgICsgYFxcblxcYFxcYFxcYFxcbiR7U0lHTl9DT01NQU5EfVxcblxcYFxcYFxcYGAsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IHJlcG9ydFByb2JsZW0oe1xuICAgICAgICAgICAgICAgIHJlcG9VUkwsXG4gICAgICAgICAgICAgICAgcHJvYmxlbTogXCJjb3JydXB0XCIsXG4gICAgICAgICAgICAgICAgaGVhZGxpbmU6IGBLRVkgUkVQTyBTSUdOQVRVUkUgSVMgQlJPS0VOYCxcbiAgICAgICAgICAgICAgICBib2R5OiBgVGhlIHNpZ25hdHVyZSBvbiBcXGAke3JlcG9VUkx9XFxgIGRvZXMgbm90IGNoZWNrIG91dCwgc28gZXZlcnl0aGluZyBpbiBpdCBpc2BcbiAgICAgICAgICAgICAgICAgICAgKyBgIGJlaW5nIGlnbm9yZWQgYW5kIHRoaXMgbWFjaGluZSBpcyBzdGlsbCB1c2luZyB0aGUga2V5cyBzaWduZWQgYnlgXG4gICAgICAgICAgICAgICAgICAgICsgYCBcXGAke2Rlc2NyaWJlU2lnbmVyKHNvdXJjZVN0YXRlVmFsdWUuYWNjZXB0ZWRTaWduZXIpfVxcYC5gXG4gICAgICAgICAgICAgICAgICAgICsgYFxcblxcbiR7ZX1gXG4gICAgICAgICAgICAgICAgICAgICsgYFxcblxcblRvIHJlcGxhY2UgdGhlIHNpZ25hdHVyZSwgcnVuIHRoaXMgaW4gdGhhdCByZXBvOmBcbiAgICAgICAgICAgICAgICAgICAgKyBgXFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYCxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkS2V5cztcbiAgICB9XG4gICAgaWYgKHNvdXJjZVN0YXRlVmFsdWUucmVwb3J0ZWRQcm9ibGVtKSB7XG4gICAgICAgIHNvdXJjZVN0YXRlVmFsdWUucmVwb3J0ZWRQcm9ibGVtID0gXCJcIjtcbiAgICAgICAgYXdhaXQgc2F2ZVN0YXRlKCk7XG4gICAgfVxuICAgIGxldCBjaGVja291dEtleXMgPSBhd2FpdCByZWFkQ2hlY2tvdXRLZXlzKHJlcG9QYXRoKTtcblxuICAgIGxldCBhY2NlcHQgPSBhc3luYyAoKSA9PiB7XG4gICAgICAgIHNvdXJjZVN0YXRlVmFsdWUuYWNjZXB0ZWQgPSB0cnVlO1xuICAgICAgICBzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkU2lnbmVyID0gc2lnbmVyO1xuICAgICAgICBzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkS2V5cyA9IGNoZWNrb3V0S2V5cztcbiAgICAgICAgc291cmNlU3RhdGVWYWx1ZS5hY2NlcHRlZE1hbmlmZXN0SGFzaCA9IGZpbGVzLm1hbmlmZXN0SGFzaDtcbiAgICAgICAgc291cmNlU3RhdGVWYWx1ZS5hY2NlcHRlZFNpZ25hdHVyZUhhc2ggPSBmaWxlcy5zaWduYXR1cmVIYXNoO1xuICAgICAgICBzb3VyY2VTdGF0ZVZhbHVlLnBlbmRpbmdTaWduZXIgPSBVTlNJR05FRDtcbiAgICAgICAgc291cmNlU3RhdGVWYWx1ZS5wZW5kaW5nU2luY2UgPSAwO1xuICAgICAgICBhd2FpdCBzYXZlU3RhdGUoKTtcbiAgICAgICAgcmV0dXJuIGNoZWNrb3V0S2V5cztcbiAgICB9O1xuXG4gICAgLy8gTm90aGluZyBoYXMgZXZlciBiZWVuIGFjY2VwdGVkIGZyb20gdGhpcyBzb3VyY2UsIHNvIHRoaXMgaXMgd2hhdCB3ZSBzdGFydCB0cnVzdGluZy5cbiAgICBpZiAoIXNvdXJjZVN0YXRlVmFsdWUuYWNjZXB0ZWQpIHtcbiAgICAgICAgY29uc29sZS5sb2coYFRydXN0aW5nICR7cmVwb1VSTH0gYXMgc2lnbmVkIGJ5ICR7ZGVzY3JpYmVTaWduZXIoc2lnbmVyKX1gKTtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGFjY2VwdCgpO1xuICAgIH1cblxuICAgIGlmIChzaWduZXIgPT09IHNvdXJjZVN0YXRlVmFsdWUuYWNjZXB0ZWRTaWduZXIpIHtcbiAgICAgICAgLy8gQmFjayB0byB0aGUgc2lnbmVyIHdlIGFscmVhZHkgdHJ1c3QsIHNvIGFueXRoaW5nIHdlIHdlcmUgd2FpdGluZyBvbiBpcyBtb290LlxuICAgICAgICBpZiAoc291cmNlU3RhdGVWYWx1ZS5wZW5kaW5nU2luY2UpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGAke3JlcG9VUkx9IGlzIHNpZ25lZCBieSBpdHMgYWNjZXB0ZWQga2V5IGFnYWluLCBkcm9wcGluZyB0aGUgcGVuZGluZyBjaGFuZ2VgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYXdhaXQgYWNjZXB0KCk7XG4gICAgfVxuXG4gICAgLy8gR29pbmcgZnJvbSBub3RoaW5nIHRvIHNvbWV0aGluZyBzaWduZWQgaXMgb25seSBldmVyIGFuIGltcHJvdmVtZW50LCBzbyBpdCBkb2VzIG5vdCB3YWl0LlxuICAgIGlmIChzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkU2lnbmVyID09PSBVTlNJR05FRCkge1xuICAgICAgICBhd2FpdCBub3RpZnkoYEtFWSBSRVBPIElTIE5PVyBTSUdORURgLFxuICAgICAgICAgICAgYFxcYCR7cmVwb1VSTH1cXGAgd2FzIG5vdCBzaWduZWQgYXQgYWxsIGJlZm9yZSwgc28gdGhpcyBpcyBhbiBpbXByb3ZlbWVudCBhbmQgaXRzIGtleXNgXG4gICAgICAgICAgICArIGAgYXJlIGJlaW5nIGFwcGxpZWQgcmlnaHQgYXdheS5gXG4gICAgICAgICAgICArIGBcXG5cXG5zaWduZWQgYnk6IFxcYCR7c2lnbmVyfVxcYGBcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGFjY2VwdCgpO1xuICAgIH1cblxuICAgIC8vIEEgc2lnbmVyIHdlIGhhdmUgbm90IGFjY2VwdGVkLiBBbnl0aGluZyBuZXcgcmVzdGFydHMgdGhlIHdhaXQsIHNvIHB1Ymxpc2hpbmcgdHdpY2UgaW4gYSByb3dcbiAgICAvLyBnYWlucyBhbiBhdHRhY2tlciBub3RoaW5nLiBwZW5kaW5nU2luY2UgaXMgd2hhdCBtYXJrcyBhIHdhaXQgYXMgcnVubmluZywgYmVjYXVzZSBhbiB1bnNpZ25lZFxuICAgIC8vIGNoZWNrb3V0IGlzIGl0c2VsZiBhIHNpZ25lciB2YWx1ZSBhbmQgY2Fubm90IGRvdWJsZSBhcyBcIm5vdGhpbmcgcGVuZGluZ1wiLlxuICAgIGlmICghc291cmNlU3RhdGVWYWx1ZS5wZW5kaW5nU2luY2UgfHwgc2lnbmVyICE9PSBzb3VyY2VTdGF0ZVZhbHVlLnBlbmRpbmdTaWduZXIpIHtcbiAgICAgICAgc291cmNlU3RhdGVWYWx1ZS5wZW5kaW5nU2lnbmVyID0gc2lnbmVyO1xuICAgICAgICBzb3VyY2VTdGF0ZVZhbHVlLnBlbmRpbmdTaW5jZSA9IERhdGUubm93KCk7XG4gICAgICAgIGF3YWl0IHNhdmVTdGF0ZSgpO1xuICAgICAgICBhd2FpdCBub3RpZnkoYEtFWSBSRVBPIFNJR05FRCBCWSBBIERJRkZFUkVOVCBLRVlgLFxuICAgICAgICAgICAgYFNvbWVib2R5IGVsc2UgaXMgc2lnbmluZyBcXGAke3JlcG9VUkx9XFxgIG5vdy4gSXRzIGtleXMgYXJlIE5PVCBiZWluZyBhcHBsaWVkLCBhbmQgdGhpc2BcbiAgICAgICAgICAgICsgYCBtYWNoaW5lIGlzIHN0aWxsIHVzaW5nIHRoZSBvbmVzIGl0IGFscmVhZHkgaGFkLiBJZiBub3RoaW5nIGNoYW5nZXMsIHRoZSBuZXcgc2lnbmVyYFxuICAgICAgICAgICAgKyBgIGlzIGFjY2VwdGVkIGluIDI0IGhvdXJzLmBcbiAgICAgICAgICAgICsgYFxcblxcbklmIHRoYXQgd2FzIG5vdCB5b3UsIGZpeCB0aGUgcmVwbyBiZWZvcmUgdGhlIDI0IGhvdXJzIGFyZSB1cC5gXG4gICAgICAgICAgICArIGBcXG5cXG5zaWduZWQgYnkgbm93OiBcXGAke2Rlc2NyaWJlU2lnbmVyKHNpZ25lcil9XFxgYFxuICAgICAgICAgICAgKyBgXFxuc2lnbmVkIGJ5IGJlZm9yZTogXFxgJHtkZXNjcmliZVNpZ25lcihzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkU2lnbmVyKX1cXGBgXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybiBzb3VyY2VTdGF0ZVZhbHVlLmFjY2VwdGVkS2V5cztcbiAgICB9XG5cbiAgICBpZiAoRGF0ZS5ub3coKSAtIHNvdXJjZVN0YXRlVmFsdWUucGVuZGluZ1NpbmNlIDwgU0lHTkVSX0NIQU5HRV9ERUxBWSkge1xuICAgICAgICByZXR1cm4gc291cmNlU3RhdGVWYWx1ZS5hY2NlcHRlZEtleXM7XG4gICAgfVxuXG4gICAgLy8gU2FtZSBuZXcgc2lnbmVyLCAyNCBob3VycyBsYXRlciwgYW5kIG5vYm9keSBzdG9wcGVkIGl0LlxuICAgIGNvbnNvbGUubG9nKGBBY2NlcHRpbmcgJHtkZXNjcmliZVNpZ25lcihzaWduZXIpfSBmb3IgJHtyZXBvVVJMfSBhZnRlciB0aGUgJHtTSUdORVJfQ0hBTkdFX0RFTEFZfW1zIHdhaXRgKTtcbiAgICByZXR1cm4gYXdhaXQgYWNjZXB0KCk7XG59XG4iXX0=
295
- /* _JS_SOURCE_HASH = "2791d2b7398a863c4757a111c3f83e155ece380b6fa541c5bb7384f2c2829041"; */
113
+ exports.readSignedRepo = readSignedRepo;
114
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJ1c3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0cnVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUN4Qix5REFBNkc7QUFDN0cscURBQXdEO0FBRXhELGlHQUFpRztBQUNqRyxtREFBbUQ7QUFDdEMsUUFBQSxRQUFRLEdBQUcsRUFBRSxDQUFDO0FBQzNCLDZGQUE2RjtBQUM3RixrQ0FBa0M7QUFDbEMsTUFBTSxZQUFZLEdBQUcsb0JBQW9CLENBQUM7QUFFMUM7O2lEQUVpRDtBQUNqRCxNQUFhLGVBQWdCLFNBQVEsS0FBSztJQUN0QyxZQUFtQixPQUFlLEVBQVMsUUFBZ0IsRUFBUyxJQUFZO1FBQzVFLEtBQUssQ0FBQyxHQUFHLFFBQVEsS0FBSyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRGYsWUFBTyxHQUFQLE9BQU8sQ0FBUTtRQUFTLGFBQVEsR0FBUixRQUFRLENBQVE7UUFBUyxTQUFJLEdBQUosSUFBSSxDQUFRO0lBRWhGLENBQUM7Q0FDSjtBQUpELDBDQUlDO0FBRUQ7Ozs7Ozs7d0VBT3dFO0FBQ2pFLEtBQUssVUFBVSxjQUFjLENBQUMsUUFBZ0I7SUFNakQsSUFBSSxhQUFhLEdBQUcsTUFBTSxrQkFBRSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSx3QkFBYSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDakcsSUFBSSxjQUFjLEdBQUcsTUFBTSxrQkFBRSxDQUFDLFFBQVEsQ0FBQyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSx5QkFBYyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDbkcsSUFBSSxZQUFZLEdBQUcsYUFBYSxJQUFJLGdCQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxD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QUMsSUFBSSxJQUFJLElBQUksS0FBSyxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEUsTUFBTSxLQUFLLENBQUMsR0FBRyxjQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsa0NBQWtDLENBQUMsQ0FBQztRQUNwRixDQUFDO1FBQ0QsS0FBSyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUNELEtBQUssSUFBSSxRQUFRLElBQUksTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7UUFDakMsSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUN2QixNQUFNLEtBQUssQ0FBQyxHQUFHLGNBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO1FBQzlFLENBQUM7SUFDTCxDQUFDO0lBRUQsT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsYUFBYSxFQUFFLEtBQUssRUFBRSxDQUFDO0FBQzFELENBQUM7QUE5RkQsd0NBOEZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgTUFOSUZFU1RfTkFNRSwgbm9ybWFsaXplQ29udGVudCwgU0lHTl9OQU1FU1BBQ0UsIFNJR05BVFVSRV9OQU1FIH0gZnJvbSBcIi4uLy4uL3NpZ25lZEZpbGVzL21hbmlmZXN0XCI7XG5pbXBvcnQgeyB2ZXJpZnlTU0hTSUcgfSBmcm9tIFwiLi4vLi4vc2lnbmVkRmlsZXMvc3Noc2lnXCI7XG5cbi8vIEEgc291cmNlIHRoYXQgaGFzIG5ldmVyIGJlZW4gc2lnbmVkIHJlYWRzIGFzIHRoaXMsIHNvIGxvc2luZyBhIHNpZ25hdHVyZSBjb3VudHMgYXMgYSBjaGFuZ2Ugb2Zcbi8vIHNpZ25lciByYXRoZXIgdGhhbiBhcyBzb21ldGhpbmcgdG8gd2F2ZSB0aHJvdWdoLlxuZXhwb3J0IGNvbnN0IFVOU0lHTkVEID0gXCJcIjtcbi8vIFdoYXQgZml4ZXMgYm90aCBvZiB0aGUgc2lnbmF0dXJlIHByb2JsZW1zIHdlIHJlcG9ydCwgc28gdGhlIG1lc3NhZ2UgY2FuIHNheSBzbyByYXRoZXIgdGhhblxuLy8gbGVhdmluZyBzb21lb25lIHRvIHdvcmsgaXQgb3V0LlxuY29uc3QgU0lHTl9DT01NQU5EID0gXCJ5YXJuIHNpZ25maWxlcyBnaXRcIjtcblxuLyoqIEEgcmVwbyB0aGF0IGNhbm5vdCBiZSB0cnVzdGVkLCB3aXRoIHRoZSBtZXNzYWdlIHJlYWR5IGZvciB3aG9ldmVyIGFza2VkLiBOb3QgZXZlcnkgY2FsbGVyXG4gICAgdHJlYXRzIHRoZXNlIHRoZSBzYW1lIC0gYSBzb3VyY2Uga2VlcHMgaXRzIGxhc3Qga2V5cywgYSBtYWNoaW5lIGxpc3QgaXMganVzdCByZWZ1c2VkIC0gc28gdGhlXG4gICAga2luZCBpcyBjYXJyaWVkIHJhdGhlciB0aGFuIGFjdGVkIG9uIGhlcmUuICovXG5leHBvcnQgY2xhc3MgU2lnbmVkUmVwb0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuICAgIGNvbnN0cnVjdG9yKHB1YmxpYyBwcm9ibGVtOiBzdHJpbmcsIHB1YmxpYyBoZWFkbGluZTogc3RyaW5nLCBwdWJsaWMgYm9keTogc3RyaW5nKSB7XG4gICAgICAgIHN1cGVyKGAke2hlYWRsaW5lfS4gJHtib2R5fWApO1xuICAgIH1cbn1cblxuLyoqIEV2ZXJ5dGhpbmcgYSBzaWduZWQgY2hlY2tvdXQgdm91Y2hlcyBmb3IsIGluIG9uZSBjYWxsOiB3aG8gc2lnbmVkIGl0LCBhbmQgdGhlIGNvbnRlbnRzIG9mIGV2ZXJ5XG4gICAgZmlsZSB0aGUgc2lnbmF0dXJlIGFjdHVhbGx5IGNvdmVycy5cblxuICAgIFVOU0lHTkVEIHdpdGggbm8gZmlsZXMgd2hlbiB0aGVyZSBpcyBubyBzaWduYXR1cmUgYXQgYWxsLiBUaHJvd3MgYSBTaWduZWRSZXBvRXJyb3Igd2hlbiBhXG4gICAgc2lnbmF0dXJlIGlzIHByZXNlbnQgYnV0IGRvZXMgbm90IGhvbGQgdXAsIG9yIHdoZW4gYSBmaWxlIGl0IHNpZ25lZCBmb3Igd2FzIGNoYW5nZWQgb3IgcmVtb3ZlZFxuICAgIHdpdGhvdXQgcmUtc2lnbmluZyAtIGVpdGhlciB3YXkgdGhlIGNhbGxlciBrZWVwcyB3aGF0ZXZlciBpdCBsYXN0IGFjY2VwdGVkIHJhdGhlciB0aGFuIGJlbGlldmluZ1xuICAgIGEgcmVwbyB0aGF0IG5vIGxvbmdlciBtYXRjaGVzIHdoYXQgd2FzIHNpZ25lZC4gQSBmaWxlIG5vdCBpbiB0aGUgbWFuaWZlc3QgaXMganVzdCB1bnNpZ25lZCwgc29cbiAgICBpdCBpcyBsZWZ0IG91dCBhbmQgd2FybmVkIGFib3V0IHJhdGhlciB0aGFuIHRyZWF0ZWQgYXMgdGFtcGVyaW5nLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRTaWduZWRSZXBvKHJlcG9QYXRoOiBzdHJpbmcpOiBQcm9taXNlPHtcbiAgICBzaWduZXI6IHN0cmluZztcbiAgICBtYW5pZmVzdEhhc2g6IHN0cmluZztcbiAgICBzaWduYXR1cmVIYXNoOiBzdHJpbmc7XG4gICAgZmlsZXM6IE1hcDxzdHJpbmcsIEJ1ZmZlcj47XG59PiB7XG4gICAgbGV0IG1hbmlmZXN0Qnl0ZXMgPSBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4ocmVwb1BhdGgsIE1BTklGRVNUX05BTUUpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGxldCBzaWduYXR1cmVCeXRlcyA9IGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgU0lHTkFUVVJFX05BTUUpKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuICAgIGxldCBtYW5pZmVzdEhhc2ggPSBtYW5pZmVzdEJ5dGVzICYmIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShtYW5pZmVzdEJ5dGVzKS5kaWdlc3QoXCJoZXhcIikgfHwgXCJcIjtcbiAgICBsZXQgc2lnbmF0dXJlSGFzaCA9IHNpZ25hdHVyZUJ5dGVzICYmIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShzaWduYXR1cmVCeXRlcykuZGlnZXN0KFwiaGV4XCIpIHx8IFwiXCI7XG5cbiAgICBpZiAoIW1hbmlmZXN0Qnl0ZXMgJiYgIXNpZ25hdHVyZUJ5dGVzKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGAke3JlcG9QYXRofSBpcyBub3Qgc2lnbmVkLCBpZ25vcmluZyBhbGwgb2YgaXRzIGZpbGVzYCk7XG4gICAgICAgIHJldHVybiB7IHNpZ25lcjogVU5TSUdORUQsIG1hbmlmZXN0SGFzaCwgc2lnbmF0dXJlSGFzaCwgZmlsZXM6IG5ldyBNYXAoKSB9O1xuICAgIH1cblxuICAgIGxldCBicm9rZW4gPSAoZGV0YWlsOiBzdHJpbmcpID0+IG5ldyBTaWduZWRSZXBvRXJyb3IoXG4gICAgICAgIFwiY29ycnVwdFwiLFxuICAgICAgICBgS0VZIFJFUE8gU0lHTkFUVVJFIElTIEJST0tFTmAsXG4gICAgICAgIGBUaGUgc2lnbmF0dXJlIG9uICR7cmVwb1BhdGh9IGRvZXMgbm90IGNoZWNrIG91dCwgc28gZXZlcnl0aGluZyBpbiBpdCBpcyBiZWluZyBpZ25vcmVkIGFuZGBcbiAgICAgICAgKyBgIHRoaXMgbWFjaGluZSBrZWVwcyB1c2luZyB3aGF0IGl0IGxhc3QgYWNjZXB0ZWQuXFxuXFxuJHtkZXRhaWx9YFxuICAgICAgICArIGBcXG5cXG5UbyByZXBsYWNlIHRoZSBzaWduYXR1cmUsIHJ1biBpbiB0aGF0IHJlcG86XFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYFxuICAgICk7XG4gICAgaWYgKCFtYW5pZmVzdEJ5dGVzIHx8ICFzaWduYXR1cmVCeXRlcykge1xuICAgICAgICB0aHJvdyBicm9rZW4oYE9ubHkgb25lIG9mICR7TUFOSUZFU1RfTkFNRX0gYW5kICR7U0lHTkFUVVJFX05BTUV9IGlzIHByZXNlbnQuYCk7XG4gICAgfVxuXG4gICAgbGV0IHNpZ25lcjogc3RyaW5nO1xuICAgIHRyeSB7XG4gICAgICAgIC8vIFRoZSBzaWduYXR1cmUgY292ZXJzIHRoZSBub3JtYWxpc2VkIGJ5dGVzLCBzbyBhIGNoZWNrb3V0IHRoYXQgYXJyaXZlZCB3aXRoIENSTEYgc3RpbGxcbiAgICAgICAgLy8gdmVyaWZpZXMgcmF0aGVyIHRoYW4gbG9va2luZyBsaWtlIHRhbXBlcmluZy5cbiAgICAgICAgc2lnbmVyID0gdmVyaWZ5U1NIU0lHKHtcbiAgICAgICAgICAgIHNpZ25hdHVyZTogc2lnbmF0dXJlQnl0ZXMudG9TdHJpbmcoXCJ1dGY4XCIpLFxuICAgICAgICAgICAgbWVzc2FnZTogbm9ybWFsaXplQ29udGVudChtYW5pZmVzdEJ5dGVzKSxcbiAgICAgICAgICAgIG5hbWVzcGFjZTogU0lHTl9OQU1FU1BBQ0UsXG4gICAgICAgIH0pLnB1YmxpY0tleTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHRocm93IGJyb2tlbihgJHtlfWApO1xuICAgIH1cblxuICAgIGxldCBzdGFsZSA9IChkZXRhaWw6IHN0cmluZykgPT4gbmV3IFNpZ25lZFJlcG9FcnJvcihcbiAgICAgICAgXCJzdGFsZVwiLFxuICAgICAgICBgS0VZIFJFUE8gQ0hBTkdFRCBXSVRIT1VUIEJFSU5HIFNJR05FRGAsXG4gICAgICAgIGAke2RldGFpbH0sIHNvIHRoZSByZXBvIGlzIGJlaW5nIGlnbm9yZWQgYW5kIHRoaXMgbWFjaGluZSBrZWVwcyB1c2luZyB3aGF0IGl0IGxhc3QgYWNjZXB0ZWQuYFxuICAgICAgICArIGBcXG5cXG5UbyBtYWtlIHRoZSBjaGFuZ2UgdGFrZSBlZmZlY3QsIHJ1biBpbiB0aGF0IHJlcG86XFxuXFxgXFxgXFxgXFxuJHtTSUdOX0NPTU1BTkR9XFxuXFxgXFxgXFxgYFxuICAgICk7XG5cbiAgICAvLyBFdmVyeSBmaWxlIG9uIGRpc2ssIG90aGVyIHRoYW4gZ2l0J3Mgb3duIGRpcmVjdG9yeSBhbmQgdGhlIHR3byBzaWduYXR1cmUgZmlsZXMsIHdoaWNoIGNhbm5vdFxuICAgIC8vIGRlc2NyaWJlIHRoZW1zZWx2ZXMuXG4gICAgbGV0IGxpc3RDaGVja291dEZpbGVzID0gYXN5bmMgKHByZWZpeD86IHN0cmluZyk6IFByb21pc2U8c3RyaW5nW10+ID0+IHtcbiAgICAgICAgbGV0IGZvdW5kOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBmb3IgKGxldCBlbnRyeSBvZiBhd2FpdCBmcy5yZWFkZGlyKHBhdGguam9pbihyZXBvUGF0aCwgcHJlZml4IHx8IFwiXCIpLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHtcbiAgICAgICAgICAgIGxldCByZWxhdGl2ZVBhdGggPSBwcmVmaXggJiYgYCR7cHJlZml4fS8ke2VudHJ5Lm5hbWV9YCB8fCBlbnRyeS5uYW1lO1xuICAgICAgICAgICAgaWYgKGVudHJ5Lm5hbWUgPT09IFwiLmdpdFwiKSBjb250aW51ZTtcbiAgICAgICAgICAgIGlmICghcHJlZml4ICYmIChlbnRyeS5uYW1lID09PSBNQU5JRkVTVF9OQU1FIHx8IGVudHJ5Lm5hbWUgPT09IFNJR05BVFVSRV9OQU1FKSkgY29udGludWU7XG4gICAgICAgICAgICBpZiAoZW50cnkuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgICAgICAgICAgIGZvdW5kLnB1c2goLi4uYXdhaXQgbGlzdENoZWNrb3V0RmlsZXMocmVsYXRpdmVQYXRoKSk7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3VuZC5wdXNoKHJlbGF0aXZlUGF0aCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZvdW5kLnNvcnQoKTtcbiAgICB9O1xuXG4gICAgbGV0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShtYW5pZmVzdEJ5dGVzLnRvU3RyaW5nKFwidXRmOFwiKSk7XG4gICAgbGV0IGxpc3RlZCA9IG5ldyBNYXA8c3RyaW5nLCB7IHNpemU6IG51bWJlcjsgc2hhMjU2OiBzdHJpbmcgfT4oXG4gICAgICAgIChtYW5pZmVzdC5maWxlcyB8fCBbXSkubWFwKChmaWxlOiB7IHBhdGg6IHN0cmluZzsgc2l6ZTogbnVtYmVyOyBzaGEyNTY6IHN0cmluZyB9KSA9PiBbZmlsZS5wYXRoLCBmaWxlXSlcbiAgICApO1xuXG4gICAgbGV0IGZpbGVzID0gbmV3IE1hcDxzdHJpbmcsIEJ1ZmZlcj4oKTtcbiAgICBmb3IgKGxldCBmaWxlUGF0aCBvZiBhd2FpdCBsaXN0Q2hlY2tvdXRGaWxlcygpKSB7XG4gICAgICAgIGxldCBleHBlY3RlZCA9IGxpc3RlZC5nZXQoZmlsZVBhdGgpO1xuICAgICAgICAvLyBBIGZpbGUgdGhlIHNpZ25hdHVyZSBuZXZlciBtZW50aW9uZWQgaXMgbm90IHRhbXBlcmluZywgaXQgaXMganVzdCB1bnNpZ25lZCAtIGxlZnQgb3V0XG4gICAgICAgIC8vIHJhdGhlciB0aGFuIHRydXN0ZWQuIEFuIGV4dHJhIGZpbGUgaW4gYSB3b3JraW5nIHRyZWUgaXMgb3JkaW5hcnksIHNvIGl0IGlzIG9ubHkgYSBub3RlLlxuICAgICAgICBpZiAoIWV4cGVjdGVkKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgSWdub3JpbmcgJHtwYXRoLmpvaW4ocmVwb1BhdGgsIGZpbGVQYXRoKX0sIGl0IGlzIG5vdCBpbiB0aGUgc2lnbmVkIG1hbmlmZXN0YCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBsZXQgY29udGVudHMgPSBub3JtYWxpemVDb250ZW50KGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpKSk7XG4gICAgICAgIGxldCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goXCJzaGEyNTZcIikudXBkYXRlKGNvbnRlbnRzKS5kaWdlc3QoXCJoZXhcIik7XG4gICAgICAgIC8vIEEgZmlsZSB0aGUgbWFuaWZlc3QgRE9FUyBuYW1lLCBidXQgd2hvc2UgY29udGVudCBubyBsb25nZXIgbWF0Y2hlcywgaXMgYSBzaWduZWQgZmlsZVxuICAgICAgICAvLyBjaGFuZ2VkIHdpdGhvdXQgcmUtc2lnbmluZyAtIHRoZSByZXBvIGJlaW5nIGVkaXRlZCBvdXQgZnJvbSB1bmRlciBpdHMgc2lnbmF0dXJlLlxuICAgICAgICBpZiAoY29udGVudHMubGVuZ3RoICE9PSBleHBlY3RlZC5zaXplIHx8IGhhc2ggIT09IGV4cGVjdGVkLnNoYTI1Nikge1xuICAgICAgICAgICAgdGhyb3cgc3RhbGUoYCR7cGF0aC5qb2luKHJlcG9QYXRoLCBmaWxlUGF0aCl9IHdhcyBjaGFuZ2VkIGFmdGVyIGl0IHdhcyBzaWduZWRgKTtcbiAgICAgICAgfVxuICAgICAgICBmaWxlcy5zZXQoZmlsZVBhdGgsIGNvbnRlbnRzKTtcbiAgICB9XG4gICAgZm9yIChsZXQgZmlsZVBhdGggb2YgbGlzdGVkLmtleXMoKSkge1xuICAgICAgICBpZiAoIWZpbGVzLmhhcyhmaWxlUGF0aCkpIHtcbiAgICAgICAgICAgIHRocm93IHN0YWxlKGAke3BhdGguam9pbihyZXBvUGF0aCwgZmlsZVBhdGgpfSBpcyBzaWduZWQgZm9yIGJ1dCBtaXNzaW5nYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4geyBzaWduZXIsIG1hbmlmZXN0SGFzaCwgc2lnbmF0dXJlSGFzaCwgZmlsZXMgfTtcbn1cbiJdfQ==
115
+ /* _JS_SOURCE_HASH = "7efe11ad80e1fd0da4255a229551a7973443a58b48163d836cf32e330cced446"; */
@@ -25,6 +25,14 @@ export declare function currentBranch(config: {
25
25
  repoPath: string;
26
26
  keyPath: string;
27
27
  }): Promise<string>;
28
+ /** Forces a checkout's working tree to a ref. Anything local - an edited file, or a stray untracked
29
+ one - is staged and stashed rather than deleted, so the tree comes out clean but nothing is lost
30
+ for good: it sits in a stash if it is ever wanted. */
31
+ export declare function setGitRef(config: {
32
+ repoPath: string;
33
+ gitRef: string;
34
+ keyPath: string;
35
+ }): Promise<void>;
28
36
  /** Returns what changed, so the caller can report it. A rewritten history is called out
29
37
  separately - it means the remote no longer contains the commits we already had. */
30
38
  export declare function syncRepo(repoURL: string): Promise<{
@@ -66,6 +66,25 @@ export async function currentBranch(config: { repoPath: string; keyPath: string
66
66
  return (await runGit({ args: ["rev-parse", "--abbrev-ref", "HEAD"], ...config })).stdout.trim();
67
67
  }
68
68
 
69
+ /** Forces a checkout's working tree to a ref. Anything local - an edited file, or a stray untracked
70
+ one - is staged and stashed rather than deleted, so the tree comes out clean but nothing is lost
71
+ for good: it sits in a stash if it is ever wanted. */
72
+ export async function setGitRef(config: { repoPath: string; gitRef: string; keyPath: string }) {
73
+ let { repoPath, gitRef, keyPath } = config;
74
+ // Staging the untracked files first is what lets the stash carry them off, so the reset lands
75
+ // on a genuinely clean tree.
76
+ await runGit({ args: ["add", "--all"], cwd: repoPath, keyPath, allowFailure: true });
77
+ // A checkout with nothing to stash makes git stash exit non-zero, which is harmless here - the
78
+ // reset below is what actually forces the tree.
79
+ await runGit({ args: ["stash"], cwd: repoPath, keyPath, allowFailure: true });
80
+ await runGit({ args: ["fetch", "--prune", "origin"], cwd: repoPath, keyPath });
81
+ await runGit({ args: ["reset", "--hard", gitRef], cwd: repoPath, keyPath });
82
+ // Drops objects nothing references any more, so a file committed by mistake cannot bloat the
83
+ // checkout forever. Reflogs keep the just-replaced commit reachable, so a history rewrite is
84
+ // still detectable right after this.
85
+ await runGit({ args: ["prune"], cwd: repoPath, keyPath, allowFailure: true });
86
+ }
87
+
69
88
  async function ensureSourceRepo(repoURL: string) {
70
89
  let repoPath = sourceRepoPath(repoURL);
71
90
  let keyPath = await findSourceKey(repoURL) || sourceKeyPath(repoURL);
@@ -97,10 +116,11 @@ export async function syncRepo(repoURL: string) {
97
116
  return { changed: false, historyRewritten: false, remoteSha, previousSha: localSha };
98
117
  }
99
118
 
100
- await runGit({ args: ["fetch", "--prune", "origin", branch], cwd: repoPath, keyPath });
119
+ // The remote has moved, or we have not applied it yet, so force the checkout to it.
120
+ let previousSha = sourceState(repoURL).lastSha || localSha;
121
+ await setGitRef({ repoPath, gitRef: `origin/${branch}`, keyPath });
101
122
  remoteSha = (await runGit({ args: ["rev-parse", `origin/${branch}`], cwd: repoPath, keyPath })).stdout.trim();
102
123
 
103
- let previousSha = sourceState(repoURL).lastSha || localSha;
104
124
  let historyRewritten = false;
105
125
  if (previousSha && previousSha !== remoteSha) {
106
126
  // If what we already had is no longer an ancestor of the remote tip, commits were removed
@@ -113,7 +133,5 @@ export async function syncRepo(repoURL: string) {
113
133
  });
114
134
  historyRewritten = ancestry.status !== 0;
115
135
  }
116
- await runGit({ args: ["reset", "--hard", `origin/${branch}`], cwd: repoPath, keyPath });
117
- await runGit({ args: ["clean", "-fdx"], cwd: repoPath, keyPath });
118
136
  return { changed: true, historyRewritten, remoteSha, previousSha };
119
137
  }
@@ -2,7 +2,7 @@ import fs from "fs/promises";
2
2
  import path from "path";
3
3
  import { deriveRevokeKey, findRevokeKey, REVOKE_KEY_LABEL, revokeKeyPath, revokeRepoPath, revokeRepoURL } from "../revokeSource";
4
4
  import { findSourceKey, sourceKeyPath, sourceRepoPath } from "../sources";
5
- import { cloneRepo, repoIsUsable, runGit } from "./git";
5
+ import { cloneRepo, repoIsUsable, runGit, setGitRef } from "./git";
6
6
 
7
7
  /** Reading a repo, made to look like reading a directory. A caller asks for a file and gets its
8
8
  contents; keeping a checkout on disk, cloning it once and pulling it since, is this module's
@@ -84,9 +84,7 @@ export async function syncRepoFiles(repo: RepoRef) {
84
84
  if (remoteSha && remoteSha === localHead.stdout.trim()) {
85
85
  return;
86
86
  }
87
- await runGit({ args: ["fetch", "--prune", "origin"], cwd: repoPath, keyPath });
88
- await runGit({ args: ["reset", "--hard", `origin/${branch}`], cwd: repoPath, keyPath });
89
- await runGit({ args: ["clean", "-fdx"], cwd: repoPath, keyPath });
87
+ await setGitRef({ repoPath, gitRef: `origin/${branch}`, keyPath });
90
88
  }
91
89
 
92
90
  /** Throws when there is no checkout at all. "I have never managed to read this repo" and "this