sliftutils 1.7.127 → 1.7.129

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 (54) hide show
  1. package/bin/addmachine.js +9 -0
  2. package/bin/machineclient.js +9 -0
  3. package/bin/machineserver.js +10 -0
  4. package/index.d.ts +15 -0
  5. package/misc/dist/ownIPs.ts.cache +43 -0
  6. package/misc/dist/strings.ts.cache +2 -2
  7. package/misc/https/dist/certs.ts.cache +2 -2
  8. package/misc/https/dist/persistentLocalStorage.ts.cache +2 -2
  9. package/misc/ownIPs.d.ts +11 -0
  10. package/misc/ownIPs.ts +34 -0
  11. package/package.json +9 -3
  12. package/security/authorizedKeys/authorizedKeys.ts +34 -0
  13. package/security/authorizedKeys/daemon/authLog.ts +12 -5
  14. package/security/authorizedKeys/daemon/changes.ts +16 -1
  15. package/security/authorizedKeys/daemon/daemon.ts +50 -40
  16. package/security/authorizedKeys/daemon/dist/changes.ts.cache +40 -0
  17. package/security/authorizedKeys/daemon/dist/git.ts.cache +121 -0
  18. package/security/authorizedKeys/daemon/dist/notify.ts.cache +39 -0
  19. package/security/authorizedKeys/daemon/dist/paths.ts.cache +29 -0
  20. package/security/authorizedKeys/daemon/dist/repoFiles.ts.cache +114 -0
  21. package/security/authorizedKeys/daemon/dist/revocation.ts.cache +0 -0
  22. package/security/authorizedKeys/daemon/dist/sessions.ts.cache +147 -0
  23. package/security/authorizedKeys/daemon/dist/state.ts.cache +74 -0
  24. package/security/authorizedKeys/daemon/dist/trust.ts.cache +295 -0
  25. package/security/authorizedKeys/daemon/git.ts +3 -3
  26. package/security/authorizedKeys/daemon/notify.ts +8 -2
  27. package/security/authorizedKeys/daemon/repoFiles.ts +118 -0
  28. package/security/authorizedKeys/daemon/revocation.ts +0 -0
  29. package/security/authorizedKeys/daemon/rootKeys.ts +77 -10
  30. package/security/authorizedKeys/daemon/state.ts +25 -7
  31. package/security/authorizedKeys/daemon/trust.ts +37 -16
  32. package/security/authorizedKeys/daemon/userKeys.ts +5 -4
  33. package/security/authorizedKeys/dist/authorizedKeys.ts.cache +37 -3
  34. package/security/authorizedKeys/dist/revokeSource.ts.cache +17 -4
  35. package/security/authorizedKeys/dist/sources.ts.cache +52 -8
  36. package/security/authorizedKeys/dist/unrevoke.ts.cache +113 -17
  37. package/security/authorizedKeys/revokeSource.ts +12 -2
  38. package/security/authorizedKeys/secureSSH.ts +66 -12
  39. package/security/authorizedKeys/sources.ts +47 -5
  40. package/security/authorizedKeys/unrevoke.ts +176 -16
  41. package/security/helpers/dist/remoteSSH.ts.cache +19 -9
  42. package/security/machines/addMachine.ts +83 -0
  43. package/security/machines/dist/addMachine.ts.cache +88 -0
  44. package/security/machines/dist/identity.ts.cache +176 -0
  45. package/security/machines/dist/machines.ts.cache +322 -0
  46. package/security/machines/dist/trustClient.ts.cache +48 -0
  47. package/security/machines/dist/trustState.ts.cache +57 -0
  48. package/security/machines/identity.ts +199 -0
  49. package/security/machines/machines.ts +355 -0
  50. package/security/machines/trustClient.ts +51 -0
  51. package/security/machines/trustServer.ts +85 -0
  52. package/security/machines/trustState.ts +53 -0
  53. package/security/notifications/discord.ts +14 -5
  54. package/security/notifications/dist/discord.ts.cache +17 -8
@@ -1,7 +1,7 @@
1
1
  import fs from "fs/promises";
2
2
  import os from "os";
3
3
  import { configureDiscordNotifications, DEFAULT_WEBHOOK_FILE_PATH } from "../../notifications/discord";
4
- import { sourceKeyPath, sourceRepoPath } from "../sources";
4
+ import { findSourceKey, legacySourceKeyPath, sourceKeyPath, sourceRepoPath } from "../sources";
5
5
  import { cloneRepo, syncRepo } from "./git";
6
6
  import {
7
7
  CHECK_INTERVAL,
@@ -15,7 +15,9 @@ import { enforceSSHDConfig } from "./sshdConfig";
15
15
  import { getState, loadState, saveState, sourceState } from "./state";
16
16
  import { resolveSourceKeys } from "./trust";
17
17
  import { parseAuthLog, readNewAuthLog, watchAuthLog } from "./authLog";
18
- import { absorbRevocations, applyUnrevokes, recordRevocation, removeRevokedKeys, syncRevokeRepo } from "./revocation";
18
+ import { absorbRevocations, applyUnrevokes, pairKey, recordRevocation, removeRevokedKeys } from "./revocation";
19
+ import { revokeRepo, syncRepoFiles } from "./repoFiles";
20
+ import { revokeRepoURL } from "../revokeSource";
19
21
  import { keyFingerprint } from "../authorizedKeys";
20
22
  import { addChangeReason } from "./changes";
21
23
  import { checkOtherUserKeys, seedUserKeys } from "./userKeys";
@@ -42,6 +44,8 @@ import { checkOtherUserKeys, seedUserKeys } from "./userKeys";
42
44
  // 7. A source changed without its signature being updated, so the change is ignored.
43
45
  // 8. A source has a corrupted signature, so its contents are ignored.
44
46
  // 9. The webhook file itself changed, reported to the webhook being replaced.
47
+ // 10. A trusted machine talked to us from an address it is not allowed from, so it was frozen
48
+ // everywhere. Sent by whichever machine wrote that revocation, from machines.ts.
45
49
 
46
50
  export type DaemonConfig = {
47
51
  repoSources: string[];
@@ -74,10 +78,11 @@ async function loadConfig(): Promise<DaemonConfig> {
74
78
  process.exit(1);
75
79
  }
76
80
  for (let repoURL of parsed.repoSources) {
77
- try {
78
- await fs.access(sourceKeyPath(repoURL));
79
- } catch (e) {
80
- console.error(`portsecure: expected the private key for ${repoURL} at ${sourceKeyPath(repoURL)}, ${e}`);
81
+ if (!await findSourceKey(repoURL)) {
82
+ console.error(
83
+ `portsecure: expected the private key for ${repoURL} at ${sourceKeyPath(repoURL)}`
84
+ + ` or ${legacySourceKeyPath(repoURL)}, neither exists`
85
+ );
81
86
  process.exit(1);
82
87
  }
83
88
  }
@@ -137,11 +142,13 @@ async function queueRefusedKeys(allowedKeys: string[]) {
137
142
  }
138
143
  let state = getState();
139
144
  for (let found of parseAuthLog(contents)) {
140
- // One key is revoked once, no matter how many addresses it was tried from.
141
- if (state.revocations[found.fingerprint]) {
145
+ // A key and the address it was used from. The same pair twice is one revocation, but the
146
+ // same key from somewhere else is a new event, whatever was forgiven before.
147
+ let pair = pairKey({ fingerprint: found.fingerprint, ip: found.attempt.ip });
148
+ if (Object.values(state.revocations).some(revocation => pairKey(revocation) === pair)) {
142
149
  continue;
143
150
  }
144
- if (state.pendingRevocations.some(pending => pending.fingerprint === found.fingerprint)) {
151
+ if (state.pendingRevocations.some(pending => pairKey({ fingerprint: pending.fingerprint, ip: pending.attempt.ip }) === pair)) {
145
152
  continue;
146
153
  }
147
154
  let sourceURL = sourceOfFingerprint(found.fingerprint);
@@ -174,11 +181,13 @@ async function writeQueuedRevocations() {
174
181
  try {
175
182
  let remaining = [];
176
183
  for (let pending of state.pendingRevocations) {
177
- if (state.revocations[pending.fingerprint]) {
184
+ let known = () => Object.values(state.revocations)
185
+ .some(revocation => pairKey(revocation) === pairKey({ fingerprint: pending.fingerprint, ip: pending.attempt.ip }));
186
+ if (known()) {
178
187
  continue;
179
188
  }
180
189
  let recorded = await recordRevocation({ ...pending, hostLabel: config.hostLabel });
181
- if (!recorded && !state.revocations[pending.fingerprint]) {
190
+ if (!recorded && !known()) {
182
191
  remaining.push(pending);
183
192
  }
184
193
  }
@@ -213,7 +222,7 @@ async function pollSource(repoURL: string) {
213
222
  // Availability over tidiness: throw the working copy away and start again.
214
223
  console.log(`Discarding the checkout of ${repoURL} and cloning from scratch`);
215
224
  try {
216
- await cloneRepo({ repoURL, repoPath: sourceRepoPath(repoURL), keyPath: sourceKeyPath(repoURL) });
225
+ await cloneRepo({ repoURL, repoPath: sourceRepoPath(repoURL), keyPath: await findSourceKey(repoURL) || sourceKeyPath(repoURL) });
217
226
  repoFailureCounts[repoURL] = 0;
218
227
  return true;
219
228
  } catch (cloneError) {
@@ -223,10 +232,11 @@ async function pollSource(repoURL: string) {
223
232
  }
224
233
 
225
234
  if (result.historyRewritten) {
226
- await notify(
227
- `the history of \`${repoURL}\` was rewritten. Commit \`${result.previousSha.slice(0, 12)}\` is no`
228
- + ` longer an ancestor of \`${result.remoteSha.slice(0, 12)}\`, so history was force pushed or`
229
- + ` tampered with. The new state has been applied.`
235
+ await notify(`KEY REPO HISTORY REWRITTEN`,
236
+ `Commits that used to be in \`${repoURL}\` are gone, so somebody force pushed over it`
237
+ + ` or tampered with it. Whatever it says now has been applied.`
238
+ + `\n\nwas at: \`${result.previousSha.slice(0, 12)}\``
239
+ + `\nnow at: \`${result.remoteSha.slice(0, 12)}\``
230
240
  );
231
241
  }
232
242
  if (!result.changed) {
@@ -234,11 +244,18 @@ async function pollSource(repoURL: string) {
234
244
  }
235
245
  // Said when the file is written, and only if it came out different. A commit that does not
236
246
  // touch the keys is not worth telling anyone about.
237
- addChangeReason(`\`${repoURL}\` moved to \`${result.remoteSha.slice(0, 12)}\`.`);
247
+ addChangeReason(`The key repo \`${repoURL}\` moved to \`${result.remoteSha.slice(0, 12)}\`.`);
238
248
  sourceState(repoURL).lastSha = result.remoteSha;
239
249
  return true;
240
250
  }
241
251
 
252
+ /** The one loop. Every repo this machine reads is brought up to date here: each source, and the
253
+ revoke repo beside it that says which of its keys are no longer accepted.
254
+
255
+ A repo that cannot be read is reported and skipped, and nothing downstream may read that as an
256
+ answer. An unreachable source keeps the keys it last gave us, and an unreachable revoke repo
257
+ keeps the revocations we already know - the alternative is one network failure emptying
258
+ authorized_keys, or handing a revoked key back to every machine. */
242
259
  async function everyCheck() {
243
260
  let anyChanged = false;
244
261
  for (let repoURL of config.repoSources) {
@@ -246,17 +263,20 @@ async function everyCheck() {
246
263
  try {
247
264
  anyChanged = await pollSource(repoURL) || anyChanged;
248
265
  } catch (e) {
249
- console.log(`Polling ${repoURL} failed. ${e && (e as Error).stack || e}`);
266
+ console.error(`Polling ${repoURL} failed, its last known keys stay in place. ${e && (e as Error).stack || e}`);
267
+ }
268
+ try {
269
+ await syncRepoFiles(revokeRepo(repoURL));
270
+ } catch (e) {
271
+ console.error(
272
+ `Could not read ${revokeRepoURL(repoURL)}, the revocations already known stay in place. ${e}`
273
+ );
250
274
  }
251
275
  }
252
276
  if (anyChanged) {
253
277
  await saveState();
254
278
  }
255
279
 
256
- // What other machines have revoked, and anything published to undo a revocation.
257
- for (let repoURL of config.repoSources) {
258
- await syncRevokeRepo(repoURL);
259
- }
260
280
  await absorbRevocations(config.repoSources);
261
281
  await applyUnrevokes(config.repoSources);
262
282
 
@@ -298,28 +318,18 @@ export async function main() {
298
318
 
299
319
  console.log(`Starting, ${config.repoSources.length} source(s), keys applied to ${ROOT_AUTHORIZED_KEYS}`);
300
320
 
301
- // A first pass has to happen before the intervals, so a machine is correct immediately after
302
- // boot rather than a minute later.
303
- for (let repoURL of config.repoSources) {
304
- try {
305
- sourceState(repoURL).lastSha = (await syncRepo(repoURL)).remoteSha;
306
- } catch (e) {
307
- console.log(`Initial sync of ${repoURL} failed, continuing with whatever is on disk. ${e}`);
308
- }
309
- }
310
- await saveState();
321
+ // Whatever other users already have, before the first check, so what is there at startup is
322
+ // not reported as somebody having just changed it.
311
323
  await seedUserKeys();
312
324
 
313
- for (let repoURL of config.repoSources) {
314
- await syncRevokeRepo(repoURL);
315
- }
316
- await absorbRevocations(config.repoSources);
317
- await enforceRootKeys(await removeRevokedKeys(await readAllowedKeys()));
318
- await enforceSSHDConfig();
319
-
320
325
  // configureDiscordNotifications watches the webhook file on its own, so there is nothing to
321
326
  // schedule for it here.
322
- startInterval({ name: "check", intervalTime: CHECK_INTERVAL, run: everyCheck });
327
+ let runCheck = startInterval({ name: "check", intervalTime: CHECK_INTERVAL, run: everyCheck });
328
+ // The same check as every other, run once now rather than a minute from now: a machine has to
329
+ // be correct immediately after boot. Running the one function, rather than a startup copy of
330
+ // it, is what keeps a step from being left out of one of them - the copy here had no
331
+ // applyUnrevokes, so every restart re-applied a revocation that had already been undone.
332
+ await runCheck();
323
333
 
324
334
  // A refused login is acted on when sshd writes it. The one pass here covers anything written
325
335
  // while the daemon was not running.
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ // Why root's authorized_keys is about to change, collected as it happens.
3
+ //
4
+ // Nothing announces itself at the moment it decides something. A revocation arriving, a key being
5
+ // revoked here, an unrevoke taking effect, a repo moving on: each of those says what it is and
6
+ // leaves it here. The file is then written, and only if it actually came out different does any of
7
+ // it get reported, in one message.
8
+ //
9
+ // Doing it the other way round is what produced several messages for one event, and messages about
10
+ // removing a key that had already gone.
11
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
12
+ //exports.takeChangeReasons = exports.addLeadingChangeReason = exports.addChangeReason = void 0;
13
+ let reasons = [];
14
+ let leadingReasons = [];
15
+ function addChangeReason(reason) {
16
+ // The same reason twice in one pass says nothing the once did not.
17
+ if (!reasons.includes(reason)) {
18
+ reasons.push(reason);
19
+ }
20
+ }
21
+ exports.addChangeReason = addChangeReason;
22
+ /** For the one thing worth reading before anything else: somebody using a key from an address it
23
+ is not allowed from. */
24
+ function addLeadingChangeReason(reason) {
25
+ if (!leadingReasons.some(existing => existing.headline === reason.headline)) {
26
+ leadingReasons.push(reason);
27
+ }
28
+ }
29
+ exports.addLeadingChangeReason = addLeadingChangeReason;
30
+ /** The reasons gathered since the last write, and clears them. Called whether or not anything
31
+ changed, so reasons that came to nothing cannot show up against some later change. */
32
+ function takeChangeReasons() {
33
+ let taken = { leading: leadingReasons, reasons };
34
+ leadingReasons = [];
35
+ reasons = [];
36
+ return taken;
37
+ }
38
+ exports.takeChangeReasons = takeChangeReasons;
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhbmdlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNoYW5nZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDBFQUEwRTtBQUMxRSxFQUFFO0FBQ0Ysa0dBQWtHO0FBQ2xHLCtGQUErRjtBQUMvRixtR0FBbUc7QUFDbkcsbUNBQW1DO0FBQ25DLEVBQUU7QUFDRixtR0FBbUc7QUFDbkcsd0NBQXdDOzs7QUFPeEMsSUFBSSxPQUFPLEdBQWEsRUFBRSxDQUFDO0FBQzNCLElBQUksY0FBYyxHQUFvQixFQUFFLENBQUM7QUFFekMsU0FBZ0IsZUFBZSxDQUFDLE1BQWM7SUFDMUMsbUVBQW1FO0lBQ25FLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFDNUIsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN6QixDQUFDO0FBQ0wsQ0FBQztBQUxELDBDQUtDO0FBRUQ7MkJBQzJCO0FBQzNCLFNBQWdCLHNCQUFzQixDQUFDLE1BQXFCO0lBQ3hELElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLFFBQVEsS0FBSyxNQUFNLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztRQUMxRSxjQUFjLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2hDLENBQUM7QUFDTCxDQUFDO0FBSkQsd0RBSUM7QUFFRDt5RkFDeUY7QUFDekYsU0FBZ0IsaUJBQWlCO0lBQzdCLElBQUksS0FBSyxHQUFHLEVBQUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxPQUFPLEVBQUUsQ0FBQztJQUNqRCxjQUFjLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLE9BQU8sR0FBRyxFQUFFLENBQUM7SUFDYixPQUFPLEtBQUssQ0FBQztBQUNqQixDQUFDO0FBTEQsOENBS0MiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBXaHkgcm9vdCdzIGF1dGhvcml6ZWRfa2V5cyBpcyBhYm91dCB0byBjaGFuZ2UsIGNvbGxlY3RlZCBhcyBpdCBoYXBwZW5zLlxuLy9cbi8vIE5vdGhpbmcgYW5ub3VuY2VzIGl0c2VsZiBhdCB0aGUgbW9tZW50IGl0IGRlY2lkZXMgc29tZXRoaW5nLiBBIHJldm9jYXRpb24gYXJyaXZpbmcsIGEga2V5IGJlaW5nXG4vLyByZXZva2VkIGhlcmUsIGFuIHVucmV2b2tlIHRha2luZyBlZmZlY3QsIGEgcmVwbyBtb3Zpbmcgb246IGVhY2ggb2YgdGhvc2Ugc2F5cyB3aGF0IGl0IGlzIGFuZFxuLy8gbGVhdmVzIGl0IGhlcmUuIFRoZSBmaWxlIGlzIHRoZW4gd3JpdHRlbiwgYW5kIG9ubHkgaWYgaXQgYWN0dWFsbHkgY2FtZSBvdXQgZGlmZmVyZW50IGRvZXMgYW55IG9mXG4vLyBpdCBnZXQgcmVwb3J0ZWQsIGluIG9uZSBtZXNzYWdlLlxuLy9cbi8vIERvaW5nIGl0IHRoZSBvdGhlciB3YXkgcm91bmQgaXMgd2hhdCBwcm9kdWNlZCBzZXZlcmFsIG1lc3NhZ2VzIGZvciBvbmUgZXZlbnQsIGFuZCBtZXNzYWdlcyBhYm91dFxuLy8gcmVtb3ZpbmcgYSBrZXkgdGhhdCBoYWQgYWxyZWFkeSBnb25lLlxuXG4vKiogQSByZWFzb24gaW1wb3J0YW50IGVub3VnaCB0byBuYW1lIHRoZSB3aG9sZSBtZXNzYWdlLiBJdHMgaGVhZGxpbmUgcmVwbGFjZXMgdGhlIG9uZSB0aGUgY2hhbmdlXG4gICAgaXRzZWxmIHdvdWxkIGhhdmUgZ290LCBiZWNhdXNlIFwic29tZWJvZHkgaXMgdXNpbmcgYSBrZXkgdGhleSBzaG91bGQgbm90XCIgb3V0cmFua3MgXCJ0aGUga2V5c1xuICAgIGNoYW5nZWRcIiBpbiB0aGUgb25lIGxpbmUgYSBwaG9uZSBzaG93cy4gKi9cbmV4cG9ydCB0eXBlIExlYWRpbmdSZWFzb24gPSB7IGhlYWRsaW5lOiBzdHJpbmc7IGJvZHk6IHN0cmluZyB9O1xuXG5sZXQgcmVhc29uczogc3RyaW5nW10gPSBbXTtcbmxldCBsZWFkaW5nUmVhc29uczogTGVhZGluZ1JlYXNvbltdID0gW107XG5cbmV4cG9ydCBmdW5jdGlvbiBhZGRDaGFuZ2VSZWFzb24ocmVhc29uOiBzdHJpbmcpIHtcbiAgICAvLyBUaGUgc2FtZSByZWFzb24gdHdpY2UgaW4gb25lIHBhc3Mgc2F5cyBub3RoaW5nIHRoZSBvbmNlIGRpZCBub3QuXG4gICAgaWYgKCFyZWFzb25zLmluY2x1ZGVzKHJlYXNvbikpIHtcbiAgICAgICAgcmVhc29ucy5wdXNoKHJlYXNvbik7XG4gICAgfVxufVxuXG4vKiogRm9yIHRoZSBvbmUgdGhpbmcgd29ydGggcmVhZGluZyBiZWZvcmUgYW55dGhpbmcgZWxzZTogc29tZWJvZHkgdXNpbmcgYSBrZXkgZnJvbSBhbiBhZGRyZXNzIGl0XG4gICAgaXMgbm90IGFsbG93ZWQgZnJvbS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGRMZWFkaW5nQ2hhbmdlUmVhc29uKHJlYXNvbjogTGVhZGluZ1JlYXNvbikge1xuICAgIGlmICghbGVhZGluZ1JlYXNvbnMuc29tZShleGlzdGluZyA9PiBleGlzdGluZy5oZWFkbGluZSA9PT0gcmVhc29uLmhlYWRsaW5lKSkge1xuICAgICAgICBsZWFkaW5nUmVhc29ucy5wdXNoKHJlYXNvbik7XG4gICAgfVxufVxuXG4vKiogVGhlIHJlYXNvbnMgZ2F0aGVyZWQgc2luY2UgdGhlIGxhc3Qgd3JpdGUsIGFuZCBjbGVhcnMgdGhlbS4gQ2FsbGVkIHdoZXRoZXIgb3Igbm90IGFueXRoaW5nXG4gICAgY2hhbmdlZCwgc28gcmVhc29ucyB0aGF0IGNhbWUgdG8gbm90aGluZyBjYW5ub3Qgc2hvdyB1cCBhZ2FpbnN0IHNvbWUgbGF0ZXIgY2hhbmdlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHRha2VDaGFuZ2VSZWFzb25zKCkge1xuICAgIGxldCB0YWtlbiA9IHsgbGVhZGluZzogbGVhZGluZ1JlYXNvbnMsIHJlYXNvbnMgfTtcbiAgICBsZWFkaW5nUmVhc29ucyA9IFtdO1xuICAgIHJlYXNvbnMgPSBbXTtcbiAgICByZXR1cm4gdGFrZW47XG59XG4iXX0=
40
+ /* _JS_SOURCE_HASH = "6d0282fa2244057d7a106dc14b6b13dd37ddc1ba1ecc4a44b33dfd51c3e409a5"; */
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.syncRepo = exports.currentBranch = exports.cloneRepo = exports.repoIsUsable = exports.runGit = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const spawn_1 = require("../../helpers/spawn");
10
+ const sources_1 = require("../sources");
11
+ const paths_1 = require("./paths");
12
+ const state_1 = require("./state");
13
+ async function pathExists(filePath) {
14
+ try {
15
+ await promises_1.default.access(filePath);
16
+ return true;
17
+ }
18
+ catch (e) {
19
+ return false;
20
+ }
21
+ }
22
+ /** core.sshCommand keeps the key selection with the command instead of in the environment. */
23
+ async function runGit(config) {
24
+ let { args, cwd, keyPath, allowFailure } = config;
25
+ let sshCommand = `ssh -i ${keyPath} -o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=accept-new`;
26
+ let result = await (0, spawn_1.spawnPromise)({
27
+ command: "git",
28
+ args: ["-c", `core.sshCommand=${sshCommand}`, ...args],
29
+ cwd,
30
+ timeoutTime: paths_1.GIT_TIMEOUT,
31
+ });
32
+ if (result.error) {
33
+ throw new Error(`Expected git ${args.join(" ")} to run, failed with ${result.error.message}`);
34
+ }
35
+ if (result.status !== 0 && !allowFailure) {
36
+ throw new Error(`Expected git ${args.join(" ")} to exit 0, was ${result.status}. `
37
+ + `${(result.stdout + result.stderr).trim().slice(0, paths_1.MAX_ERROR_BODY_LENGTH)}`);
38
+ }
39
+ return result;
40
+ }
41
+ exports.runGit = runGit;
42
+ async function repoIsUsable(config) {
43
+ let { repoPath, keyPath } = config;
44
+ if (!await pathExists(path_1.default.join(repoPath, ".git"))) {
45
+ return false;
46
+ }
47
+ let result = await runGit({ args: ["rev-parse", "--git-dir"], cwd: repoPath, keyPath, allowFailure: true });
48
+ if (result.status !== 0) {
49
+ console.log(`Repo at ${repoPath} is not usable. ${(result.stdout + result.stderr).trim()}`);
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+ exports.repoIsUsable = repoIsUsable;
55
+ /** Cloned beside the old checkout and swapped in, so a clone that fails leaves the copy we are
56
+ already using untouched rather than deleting the only keys we have. */
57
+ async function cloneRepo(config) {
58
+ let { repoURL, repoPath, keyPath } = config;
59
+ let incomingPath = `${repoPath}.incoming`;
60
+ await promises_1.default.rm(incomingPath, { recursive: true, force: true });
61
+ await promises_1.default.mkdir(path_1.default.dirname(repoPath), { recursive: true });
62
+ await runGit({ args: ["clone", repoURL, incomingPath], keyPath });
63
+ await promises_1.default.rm(repoPath, { recursive: true, force: true });
64
+ await promises_1.default.rename(incomingPath, repoPath);
65
+ console.log(`Cloned ${repoURL} into ${repoPath}`);
66
+ }
67
+ exports.cloneRepo = cloneRepo;
68
+ async function currentBranch(config) {
69
+ return (await runGit({ args: ["rev-parse", "--abbrev-ref", "HEAD"], ...config })).stdout.trim();
70
+ }
71
+ exports.currentBranch = currentBranch;
72
+ async function ensureSourceRepo(repoURL) {
73
+ let repoPath = (0, sources_1.sourceRepoPath)(repoURL);
74
+ let keyPath = await (0, sources_1.findSourceKey)(repoURL) || (0, sources_1.sourceKeyPath)(repoURL);
75
+ if (!await repoIsUsable({ repoPath, keyPath })) {
76
+ await cloneRepo({ repoURL, repoPath, keyPath });
77
+ }
78
+ if (!(0, state_1.sourceState)(repoURL).branch) {
79
+ (0, state_1.sourceState)(repoURL).branch = await currentBranch({ repoPath, keyPath });
80
+ }
81
+ }
82
+ /** Returns what changed, so the caller can report it. A rewritten history is called out
83
+ separately - it means the remote no longer contains the commits we already had. */
84
+ async function syncRepo(repoURL) {
85
+ await ensureSourceRepo(repoURL);
86
+ let repoPath = (0, sources_1.sourceRepoPath)(repoURL);
87
+ let keyPath = await (0, sources_1.findSourceKey)(repoURL) || (0, sources_1.sourceKeyPath)(repoURL);
88
+ let branch = (0, state_1.sourceState)(repoURL).branch;
89
+ let localSha = (await runGit({ args: ["rev-parse", "HEAD"], cwd: repoPath, keyPath })).stdout.trim();
90
+ // A ref listing is a few hundred bytes and no objects, so the usual case of nothing having
91
+ // changed costs almost nothing and we only fetch when there is something to fetch.
92
+ let listing = (await runGit({ args: ["ls-remote", "origin", branch], cwd: repoPath, keyPath })).stdout;
93
+ let remoteSha = (listing.split(/\s+/)[0] || "").trim();
94
+ if (!remoteSha) {
95
+ throw new Error(`Expected origin to report a sha for ${branch}, listed ${listing.slice(0, paths_1.MAX_ERROR_BODY_LENGTH)}`);
96
+ }
97
+ if (remoteSha === localSha && remoteSha === (0, state_1.sourceState)(repoURL).lastSha) {
98
+ return { changed: false, historyRewritten: false, remoteSha, previousSha: localSha };
99
+ }
100
+ await runGit({ args: ["fetch", "--prune", "origin", branch], cwd: repoPath, keyPath });
101
+ remoteSha = (await runGit({ args: ["rev-parse", `origin/${branch}`], cwd: repoPath, keyPath })).stdout.trim();
102
+ let previousSha = (0, state_1.sourceState)(repoURL).lastSha || localSha;
103
+ let historyRewritten = false;
104
+ if (previousSha && previousSha !== remoteSha) {
105
+ // If what we already had is no longer an ancestor of the remote tip, commits were removed
106
+ // or rewritten rather than added.
107
+ let ancestry = await runGit({
108
+ args: ["merge-base", "--is-ancestor", previousSha, remoteSha],
109
+ cwd: repoPath,
110
+ keyPath,
111
+ allowFailure: true,
112
+ });
113
+ historyRewritten = ancestry.status !== 0;
114
+ }
115
+ await runGit({ args: ["reset", "--hard", `origin/${branch}`], cwd: repoPath, keyPath });
116
+ await runGit({ args: ["clean", "-fdx"], cwd: repoPath, keyPath });
117
+ return { changed: true, historyRewritten, remoteSha, previousSha };
118
+ }
119
+ exports.syncRepo = syncRepo;
120
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZ2l0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJEQUE2QjtBQUM3QixnREFBd0I7QUFDeEIsK0NBQW1EO0FBQ25ELHdDQUEwRTtBQUMxRSxtQ0FBNkQ7QUFDN0QsbUNBQXNDO0FBRXRDLEtBQUssVUFBVSxVQUFVLENBQUMsUUFBZ0I7SUFDdEMsSUFBSSxDQUFDO1FBQ0QsTUFBTSxrQkFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMxQixPQUFPLElBQUksQ0FBQztJQUNoQixDQUFDO0lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNULE9BQU8sS0FBSyxDQUFDO0lBQ2pCLENBQUM7QUFDTCxDQUFDO0FBRUQsOEZBQThGO0FBQ3ZGLEtBQUssVUFBVSxNQUFNLENBQUMsTUFBaUY7SUFDMUcsSUFBSSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxHQUFHLE1BQU0sQ0FBQztJQUNsRCxJQUFJLFVBQVUsR0FBRyxVQUFVLE9BQU8sNkVBQTZFLENBQUM7SUFDaEgsSUFBSSxNQUFNLEdBQUcsTUFBTSxJQUFBLG9CQUFZLEVBQUM7UUFDNUIsT0FBTyxFQUFFLEtBQUs7UUFDZCxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsbUJBQW1CLFVBQVUsRUFBRSxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQ3RELEdBQUc7UUFDSCxXQUFXLEVBQUUsbUJBQVc7S0FDM0IsQ0FBQyxDQUFDO0lBQ0gsSUFBSSxNQUFNLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDZixNQUFNLElBQUksS0FBSyxDQUFDLGdCQUFnQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyx3QkFBd0IsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ2xHLENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxJQUFJLENBQUMs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QVcsRUFBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLElBQUksUUFBUSxDQUFDO0lBQzNELElBQUksZ0JBQWdCLEdBQUcsS0FBSyxDQUFDO0lBQzdCLElBQUksV0FBVyxJQUFJLFdBQVcsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUMzQywwRkFBMEY7UUFDMUYsa0NBQWtDO1FBQ2xDLElBQUksUUFBUSxHQUFHLE1BQU0sTUFBTSxDQUFDO1lBQ3hCLElBQUksRUFBRSxDQUFDLFlBQVksRUFBRSxlQUFlLEVBQUUsV0FBVyxFQUFFLFNBQVMsQ0FBQztZQUM3RCxHQUFHLEVBQUUsUUFBUTtZQUNiLE9BQU87WUFDUCxZQUFZLEVBQUUsSUFBSTtTQUNyQixDQUFDLENBQUM7UUFDSCxnQkFBZ0IsR0FBRyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQztJQUM3QyxDQUFDO0lBQ0QsTUFBTSxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLFVBQVUsTUFBTSxFQUFFLENBQUMsRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFDeEYsTUFBTSxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLEVBQUUsR0FBRyxFQUFFLFFBQVEsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDO0lBQ2xFLE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLFNBQVMsRUFBRSxXQUFXLEVBQUUsQ0FBQztBQUN2RSxDQUFDO0FBckNELDRCQXFDQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5pbXBvcnQgeyBzcGF3blByb21pc2UgfSBmcm9tIFwiLi4vLi4vaGVscGVycy9zcGF3blwiO1xuaW1wb3J0IHsgZmluZFNvdXJjZUtleSwgc291cmNlS2V5UGF0aCwgc291cmNlUmVwb1BhdGggfSBmcm9tIFwiLi4vc291cmNlc1wiO1xuaW1wb3J0IHsgR0lUX1RJTUVPVVQsIE1BWF9FUlJPUl9CT0RZX0xFTkdUSCB9IGZyb20gXCIuL3BhdGhzXCI7XG5pbXBvcnQgeyBzb3VyY2VTdGF0ZSB9IGZyb20gXCIuL3N0YXRlXCI7XG5cbmFzeW5jIGZ1bmN0aW9uIHBhdGhFeGlzdHMoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZzLmFjY2VzcyhmaWxlUGF0aCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuLyoqIGNvcmUuc3NoQ29tbWFuZCBrZWVwcyB0aGUga2V5IHNlbGVjdGlvbiB3aXRoIHRoZSBjb21tYW5kIGluc3RlYWQgb2YgaW4gdGhlIGVudmlyb25tZW50LiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJ1bkdpdChjb25maWc6IHsgYXJnczogc3RyaW5nW107IGN3ZD86IHN0cmluZzsga2V5UGF0aDogc3RyaW5nOyBhbGxvd0ZhaWx1cmU/OiBib29sZWFuIH0pIHtcbiAgICBsZXQgeyBhcmdzLCBjd2QsIGtleVBhdGgsIGFsbG93RmFpbHVyZSB9ID0gY29uZmlnO1xuICAgIGxldCBzc2hDb21tYW5kID0gYHNzaCAtaSAke2tleVBhdGh9IC1vIElkZW50aXRpZXNPbmx5PXllcyAtbyBCYXRjaE1vZGU9eWVzIC1vIFN0cmljdEhvc3RLZXlDaGVja2luZz1hY2NlcHQtbmV3YDtcbiAgICBsZXQgcmVzdWx0ID0gYXdhaXQgc3Bhd25Qcm9taXNlKHtcbiAgICAgICAgY29tbWFuZDogXCJnaXRcIixcbiAgICAgICAgYXJnczogW1wiLWNcIiwgYGNvcmUuc3NoQ29tbWFuZD0ke3NzaENvbW1hbmR9YCwgLi4uYXJnc10sXG4gICAgICAgIGN3ZCxcbiAgICAgICAgdGltZW91dFRpbWU6IEdJVF9USU1FT1VULFxuICAgIH0pO1xuICAgIGlmIChyZXN1bHQuZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBnaXQgJHthcmdzLmpvaW4oXCIgXCIpfSB0byBydW4sIGZhaWxlZCB3aXRoICR7cmVzdWx0LmVycm9yLm1lc3NhZ2V9YCk7XG4gICAgfVxuICAgIGlmIChyZXN1bHQuc3RhdHVzICE9PSAwICYmICFhbGxvd0ZhaWx1cmUpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEV4cGVjdGVkIGdpdCAke2FyZ3Muam9pbihcIiBcIil9IHRvIGV4aXQgMCwgd2FzICR7cmVzdWx0LnN0YXR1c30uIGBcbiAgICAgICAgICAgICsgYCR7KHJlc3VsdC5zdGRvdXQgKyByZXN1bHQuc3RkZXJyKS50cmltKCkuc2xpY2UoMCwgTUFYX0VSUk9SX0JPRFlfTEVOR1RIKX1gXG4gICAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZXBvSXNVc2FibGUoY29uZmlnOiB7IHJlcG9QYXRoOiBzdHJpbmc7IGtleVBhdGg6IHN0cmluZyB9KSB7XG4gICAgbGV0IHsgcmVwb1BhdGgsIGtleVBhdGggfSA9IGNvbmZpZztcbiAgICBpZiAoIWF3YWl0IHBhdGhFeGlzdHMocGF0aC5qb2luKHJlcG9QYXRoLCBcIi5naXRcIikpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcInJldi1wYXJzZVwiLCBcIi0tZ2l0LWRpclwiXSwgY3dkOiByZXBvUGF0aCwga2V5UGF0aCwgYWxsb3dGYWlsdXJlOiB0cnVlIH0pO1xuICAgIGlmIChyZXN1bHQuc3RhdHVzICE9PSAwKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBSZXBvIGF0ICR7cmVwb1BhdGh9IGlzIG5vdCB1c2FibGUuICR7KHJlc3VsdC5zdGRvdXQgKyByZXN1bHQuc3RkZXJyKS50cmltKCl9YCk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG59XG5cbi8qKiBDbG9uZWQgYmVzaWRlIHRoZSBvbGQgY2hlY2tvdXQgYW5kIHN3YXBwZWQgaW4sIHNvIGEgY2xvbmUgdGhhdCBmYWlscyBsZWF2ZXMgdGhlIGNvcHkgd2UgYXJlXG4gICAgYWxyZWFkeSB1c2luZyB1bnRvdWNoZWQgcmF0aGVyIHRoYW4gZGVsZXRpbmcgdGhlIG9ubHkga2V5cyB3ZSBoYXZlLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb25lUmVwbyhjb25maWc6IHsgcmVwb1VSTDogc3RyaW5nOyByZXBvUGF0aDogc3RyaW5nOyBrZXlQYXRoOiBzdHJpbmcgfSkge1xuICAgIGxldCB7IHJlcG9VUkwsIHJlcG9QYXRoLCBrZXlQYXRoIH0gPSBjb25maWc7XG4gICAgbGV0IGluY29taW5nUGF0aCA9IGAke3JlcG9QYXRofS5pbmNvbWluZ2A7XG4gICAgYXdhaXQgZnMucm0oaW5jb21pbmdQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgYXdhaXQgZnMubWtkaXIocGF0aC5kaXJuYW1lKHJlcG9QYXRoKSwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgYXdhaXQgcnVuR2l0KHsgYXJnczogW1wiY2xvbmVcIiwgcmVwb1VSTCwgaW5jb21pbmdQYXRoXSwga2V5UGF0aCB9KTtcbiAgICBhd2FpdCBmcy5ybShyZXBvUGF0aCwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIGF3YWl0IGZzLnJlbmFtZShpbmNvbWluZ1BhdGgsIHJlcG9QYXRoKTtcbiAgICBjb25zb2xlLmxvZyhgQ2xvbmVkICR7cmVwb1VSTH0gaW50byAke3JlcG9QYXRofWApO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3VycmVudEJyYW5jaChjb25maWc6IHsgcmVwb1BhdGg6IHN0cmluZzsga2V5UGF0aDogc3RyaW5nIH0pIHtcbiAgICByZXR1cm4gKGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcInJldi1wYXJzZVwiLCBcIi0tYWJicmV2LXJlZlwiLCBcIkhFQURcIl0sIC4uLmNvbmZpZyB9KSkuc3Rkb3V0LnRyaW0oKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZW5zdXJlU291cmNlUmVwbyhyZXBvVVJMOiBzdHJpbmcpIHtcbiAgICBsZXQgcmVwb1BhdGggPSBzb3VyY2VSZXBvUGF0aChyZXBvVVJMKTtcbiAgICBsZXQga2V5UGF0aCA9IGF3YWl0IGZpbmRTb3VyY2VLZXkocmVwb1VSTCkgfHwgc291cmNlS2V5UGF0aChyZXBvVVJMKTtcbiAgICBpZiAoIWF3YWl0IHJlcG9Jc1VzYWJsZSh7IHJlcG9QYXRoLCBrZXlQYXRoIH0pKSB7XG4gICAgICAgIGF3YWl0IGNsb25lUmVwbyh7IHJlcG9VUkwsIHJlcG9QYXRoLCBrZXlQYXRoIH0pO1xuICAgIH1cbiAgICBpZiAoIXNvdXJjZVN0YXRlKHJlcG9VUkwpLmJyYW5jaCkge1xuICAgICAgICBzb3VyY2VTdGF0ZShyZXBvVVJMKS5icmFuY2ggPSBhd2FpdCBjdXJyZW50QnJhbmNoKHsgcmVwb1BhdGgsIGtleVBhdGggfSk7XG4gICAgfVxufVxuXG4vKiogUmV0dXJucyB3aGF0IGNoYW5nZWQsIHNvIHRoZSBjYWxsZXIgY2FuIHJlcG9ydCBpdC4gQSByZXdyaXR0ZW4gaGlzdG9yeSBpcyBjYWxsZWQgb3V0XG4gICAgc2VwYXJhdGVseSAtIGl0IG1lYW5zIHRoZSByZW1vdGUgbm8gbG9uZ2VyIGNvbnRhaW5zIHRoZSBjb21taXRzIHdlIGFscmVhZHkgaGFkLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN5bmNSZXBvKHJlcG9VUkw6IHN0cmluZykge1xuICAgIGF3YWl0IGVuc3VyZVNvdXJjZVJlcG8ocmVwb1VSTCk7XG4gICAgbGV0IHJlcG9QYXRoID0gc291cmNlUmVwb1BhdGgocmVwb1VSTCk7XG4gICAgbGV0IGtleVBhdGggPSBhd2FpdCBmaW5kU291cmNlS2V5KHJlcG9VUkwpIHx8IHNvdXJjZUtleVBhdGgocmVwb1VSTCk7XG4gICAgbGV0IGJyYW5jaCA9IHNvdXJjZVN0YXRlKHJlcG9VUkwpLmJyYW5jaDtcbiAgICBsZXQgbG9jYWxTaGEgPSAoYXdhaXQgcnVuR2l0KHsgYXJnczogW1wicmV2LXBhcnNlXCIsIFwiSEVBRFwiXSwgY3dkOiByZXBvUGF0aCwga2V5UGF0aCB9KSkuc3Rkb3V0LnRyaW0oKTtcblxuICAgIC8vIEEgcmVmIGxpc3RpbmcgaXMgYSBmZXcgaHVuZHJlZCBieXRlcyBhbmQgbm8gb2JqZWN0cywgc28gdGhlIHVzdWFsIGNhc2Ugb2Ygbm90aGluZyBoYXZpbmdcbiAgICAvLyBjaGFuZ2VkIGNvc3RzIGFsbW9zdCBub3RoaW5nIGFuZCB3ZSBvbmx5IGZldGNoIHdoZW4gdGhlcmUgaXMgc29tZXRoaW5nIHRvIGZldGNoLlxuICAgIGxldCBsaXN0aW5nID0gKGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcImxzLXJlbW90ZVwiLCBcIm9yaWdpblwiLCBicmFuY2hdLCBjd2Q6IHJlcG9QYXRoLCBrZXlQYXRoIH0pKS5zdGRvdXQ7XG4gICAgbGV0IHJlbW90ZVNoYSA9IChsaXN0aW5nLnNwbGl0KC9cXHMrLylbMF0gfHwgXCJcIikudHJpbSgpO1xuICAgIGlmICghcmVtb3RlU2hhKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb3JpZ2luIHRvIHJlcG9ydCBhIHNoYSBmb3IgJHticmFuY2h9LCBsaXN0ZWQgJHtsaXN0aW5nLnNsaWNlKDAsIE1BWF9FUlJPUl9CT0RZX0xFTkdUSCl9YCk7XG4gICAgfVxuICAgIGlmIChyZW1vdGVTaGEgPT09IGxvY2FsU2hhICYmIHJlbW90ZVNoYSA9PT0gc291cmNlU3RhdGUocmVwb1VSTCkubGFzdFNoYSkge1xuICAgICAgICByZXR1cm4geyBjaGFuZ2VkOiBmYWxzZSwgaGlzdG9yeVJld3JpdHRlbjogZmFsc2UsIHJlbW90ZVNoYSwgcHJldmlvdXNTaGE6IGxvY2FsU2hhIH07XG4gICAgfVxuXG4gICAgYXdhaXQgcnVuR2l0KHsgYXJnczogW1wiZmV0Y2hcIiwgXCItLXBydW5lXCIsIFwib3JpZ2luXCIsIGJyYW5jaF0sIGN3ZDogcmVwb1BhdGgsIGtleVBhdGggfSk7XG4gICAgcmVtb3RlU2hhID0gKGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcInJldi1wYXJzZVwiLCBgb3JpZ2luLyR7YnJhbmNofWBdLCBjd2Q6IHJlcG9QYXRoLCBrZXlQYXRoIH0pKS5zdGRvdXQudHJpbSgpO1xuXG4gICAgbGV0IHByZXZpb3VzU2hhID0gc291cmNlU3RhdGUocmVwb1VSTCkubGFzdFNoYSB8fCBsb2NhbFNoYTtcbiAgICBsZXQgaGlzdG9yeVJld3JpdHRlbiA9IGZhbHNlO1xuICAgIGlmIChwcmV2aW91c1NoYSAmJiBwcmV2aW91c1NoYSAhPT0gcmVtb3RlU2hhKSB7XG4gICAgICAgIC8vIElmIHdoYXQgd2UgYWxyZWFkeSBoYWQgaXMgbm8gbG9uZ2VyIGFuIGFuY2VzdG9yIG9mIHRoZSByZW1vdGUgdGlwLCBjb21taXRzIHdlcmUgcmVtb3ZlZFxuICAgICAgICAvLyBvciByZXdyaXR0ZW4gcmF0aGVyIHRoYW4gYWRkZWQuXG4gICAgICAgIGxldCBhbmNlc3RyeSA9IGF3YWl0IHJ1bkdpdCh7XG4gICAgICAgICAgICBhcmdzOiBbXCJtZXJnZS1iYXNlXCIsIFwiLS1pcy1hbmNlc3RvclwiLCBwcmV2aW91c1NoYSwgcmVtb3RlU2hhXSxcbiAgICAgICAgICAgIGN3ZDogcmVwb1BhdGgsXG4gICAgICAgICAgICBrZXlQYXRoLFxuICAgICAgICAgICAgYWxsb3dGYWlsdXJlOiB0cnVlLFxuICAgICAgICB9KTtcbiAgICAgICAgaGlzdG9yeVJld3JpdHRlbiA9IGFuY2VzdHJ5LnN0YXR1cyAhPT0gMDtcbiAgICB9XG4gICAgYXdhaXQgcnVuR2l0KHsgYXJnczogW1wicmVzZXRcIiwgXCItLWhhcmRcIiwgYG9yaWdpbi8ke2JyYW5jaH1gXSwgY3dkOiByZXBvUGF0aCwga2V5UGF0aCB9KTtcbiAgICBhd2FpdCBydW5HaXQoeyBhcmdzOiBbXCJjbGVhblwiLCBcIi1mZHhcIl0sIGN3ZDogcmVwb1BhdGgsIGtleVBhdGggfSk7XG4gICAgcmV0dXJuIHsgY2hhbmdlZDogdHJ1ZSwgaGlzdG9yeVJld3JpdHRlbiwgcmVtb3RlU2hhLCBwcmV2aW91c1NoYSB9O1xufVxuIl19
121
+ /* _JS_SOURCE_HASH = "da70130786edfd6c82adec69297c753d740fb3477e29daf0f2670052fa21b0fd"; */
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.notify = exports.setHostLabel = void 0;
7
+ const os_1 = __importDefault(require("os"));
8
+ const discord_1 = require("../../notifications/discord");
9
+ let hostLabelValue = "";
10
+ function setHostLabel(value) {
11
+ hostLabelValue = value;
12
+ }
13
+ exports.setHostLabel = setHostLabel;
14
+ // DO NOT add new calls to this. Every message goes to a real Discord server someone reads, so a
15
+ // notification is only ever added when the user explicitly asks for that specific case. Startup,
16
+ // success, errors, retries and recoveries all belong in console.log instead. The complete list of
17
+ // cases that are allowed to notify is at the top of daemon.ts.
18
+ /** A headline and the rest.
19
+
20
+ The headline is all a phone shows. It gets the whole preview to itself: no product name, no
21
+ host, no timestamp in front of it, because a person glancing at their lock screen needs to read
22
+ what happened, not which machine said it or when. Those go at the end, where they are there for
23
+ whoever opens the message and out of the way of whoever does not. */
24
+ async function notify(headline, body) {
25
+ let full = `**${headline}**\n\n${body}\n\n${hostLabelValue || os_1.default.hostname()}`;
26
+ // Logged before it is sent, and whether or not it arrives, so the journal is a complete record
27
+ // of what this machine had to say even when Discord is unreachable or the webhook is wrong.
28
+ console.log(`Discord: ${full}`);
29
+ try {
30
+ await (0, discord_1.sendDiscordNotification)(full);
31
+ }
32
+ catch (e) {
33
+ // A failed notification must never take the daemon down, the local log is the fallback.
34
+ console.log(`Failed to send the Discord notification above. ${e}`);
35
+ }
36
+ }
37
+ exports.notify = notify;
38
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZ5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibm90aWZ5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDRDQUFvQjtBQUNwQix5REFBc0U7QUFFdEUsSUFBSSxjQUFjLEdBQUcsRUFBRSxDQUFDO0FBRXhCLFNBQWdCLFlBQVksQ0FBQyxLQUFhO0lBQ3RDLGNBQWMsR0FBRyxLQUFLLENBQUM7QUFDM0IsQ0FBQztBQUZELG9DQUVDO0FBRUQsZ0dBQWdHO0FBQ2hHLGlHQUFpRztBQUNqRyxrR0FBa0c7QUFDbEcsK0RBQStEO0FBQy9EOzs7Ozt3RUFLd0U7QUFDakUsS0FBSyxVQUFVLE1BQU0sQ0FBQyxRQUFnQixFQUFFLElBQVk7SUFDdkQsSUFBSSxJQUFJLEdBQUcsS0FBSyxRQUFRLFNBQVMsSUFBSSxPQUFPLGNBQWMsSUFBSSxZQUFFLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQztJQUM5RSwrRkFBK0Y7SUFDL0YsNEZBQTRGO0lBQzVGLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ2hDLElBQUksQ0FBQztRQUNELE1BQU0sSUFBQSxpQ0FBdUIsRUFBQyxJQUFJLENBQUMsQ0FBQztJQUN4QyxDQUFDO0lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUNULHdGQUF3RjtRQUN4RixPQUFPLENBQUMsR0FBRyxDQUFDLGtEQUFrRCxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3ZFLENBQUM7QUFDTCxDQUFDO0FBWEQsd0JBV0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgb3MgZnJvbSBcIm9zXCI7XG5pbXBvcnQgeyBzZW5kRGlzY29yZE5vdGlmaWNhdGlvbiB9IGZyb20gXCIuLi8uLi9ub3RpZmljYXRpb25zL2Rpc2NvcmRcIjtcblxubGV0IGhvc3RMYWJlbFZhbHVlID0gXCJcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIHNldEhvc3RMYWJlbCh2YWx1ZTogc3RyaW5nKSB7XG4gICAgaG9zdExhYmVsVmFsdWUgPSB2YWx1ZTtcbn1cblxuLy8gRE8gTk9UIGFkZCBuZXcgY2FsbHMgdG8gdGhpcy4gRXZlcnkgbWVzc2FnZSBnb2VzIHRvIGEgcmVhbCBEaXNjb3JkIHNlcnZlciBzb21lb25lIHJlYWRzLCBzbyBhXG4vLyBub3RpZmljYXRpb24gaXMgb25seSBldmVyIGFkZGVkIHdoZW4gdGhlIHVzZXIgZXhwbGljaXRseSBhc2tzIGZvciB0aGF0IHNwZWNpZmljIGNhc2UuIFN0YXJ0dXAsXG4vLyBzdWNjZXNzLCBlcnJvcnMsIHJldHJpZXMgYW5kIHJlY292ZXJpZXMgYWxsIGJlbG9uZyBpbiBjb25zb2xlLmxvZyBpbnN0ZWFkLiBUaGUgY29tcGxldGUgbGlzdCBvZlxuLy8gY2FzZXMgdGhhdCBhcmUgYWxsb3dlZCB0byBub3RpZnkgaXMgYXQgdGhlIHRvcCBvZiBkYWVtb24udHMuXG4vKiogQSBoZWFkbGluZSBhbmQgdGhlIHJlc3QuXG5cbiAgICBUaGUgaGVhZGxpbmUgaXMgYWxsIGEgcGhvbmUgc2hvd3MuIEl0IGdldHMgdGhlIHdob2xlIHByZXZpZXcgdG8gaXRzZWxmOiBubyBwcm9kdWN0IG5hbWUsIG5vXG4gICAgaG9zdCwgbm8gdGltZXN0YW1wIGluIGZyb250IG9mIGl0LCBiZWNhdXNlIGEgcGVyc29uIGdsYW5jaW5nIGF0IHRoZWlyIGxvY2sgc2NyZWVuIG5lZWRzIHRvIHJlYWRcbiAgICB3aGF0IGhhcHBlbmVkLCBub3Qgd2hpY2ggbWFjaGluZSBzYWlkIGl0IG9yIHdoZW4uIFRob3NlIGdvIGF0IHRoZSBlbmQsIHdoZXJlIHRoZXkgYXJlIHRoZXJlIGZvclxuICAgIHdob2V2ZXIgb3BlbnMgdGhlIG1lc3NhZ2UgYW5kIG91dCBvZiB0aGUgd2F5IG9mIHdob2V2ZXIgZG9lcyBub3QuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbm90aWZ5KGhlYWRsaW5lOiBzdHJpbmcsIGJvZHk6IHN0cmluZykge1xuICAgIGxldCBmdWxsID0gYCoqJHtoZWFkbGluZX0qKlxcblxcbiR7Ym9keX1cXG5cXG4ke2hvc3RMYWJlbFZhbHVlIHx8IG9zLmhvc3RuYW1lKCl9YDtcbiAgICAvLyBMb2dnZWQgYmVmb3JlIGl0IGlzIHNlbnQsIGFuZCB3aGV0aGVyIG9yIG5vdCBpdCBhcnJpdmVzLCBzbyB0aGUgam91cm5hbCBpcyBhIGNvbXBsZXRlIHJlY29yZFxuICAgIC8vIG9mIHdoYXQgdGhpcyBtYWNoaW5lIGhhZCB0byBzYXkgZXZlbiB3aGVuIERpc2NvcmQgaXMgdW5yZWFjaGFibGUgb3IgdGhlIHdlYmhvb2sgaXMgd3JvbmcuXG4gICAgY29uc29sZS5sb2coYERpc2NvcmQ6ICR7ZnVsbH1gKTtcbiAgICB0cnkge1xuICAgICAgICBhd2FpdCBzZW5kRGlzY29yZE5vdGlmaWNhdGlvbihmdWxsKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIEEgZmFpbGVkIG5vdGlmaWNhdGlvbiBtdXN0IG5ldmVyIHRha2UgdGhlIGRhZW1vbiBkb3duLCB0aGUgbG9jYWwgbG9nIGlzIHRoZSBmYWxsYmFjay5cbiAgICAgICAgY29uc29sZS5sb2coYEZhaWxlZCB0byBzZW5kIHRoZSBEaXNjb3JkIG5vdGlmaWNhdGlvbiBhYm92ZS4gJHtlfWApO1xuICAgIH1cbn1cbiJdfQ==
39
+ /* _JS_SOURCE_HASH = "9fe72e2c338fa1d2d53a34b85265b997cc47def23f019ca77b8a3735088305e5"; */
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ // Locations the daemon owns. Fixed rather than configurable, so every machine looks the same and
3
+ // the config file only carries what genuinely differs between them.
4
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
5
+ //exports.MAX_REPO_FAILURES_BEFORE_RECLONE = exports.UNREVOKE_DELAY = exports.SIGNER_CHANGE_DELAY = exports.MAX_ERROR_BODY_LENGTH = exports.GIT_TIMEOUT = exports.WEBHOOK_CHECK_INTERVAL = exports.CHECK_INTERVAL = exports.AUTH_LOG_PATH = exports.PASSWD_PATH = exports.SSHD_DROPIN_PATH = exports.SSHD_DROPIN_DIR = exports.SSHD_CONFIG_PATH = exports.ROOT_AUTHORIZED_KEYS = exports.KEYS_HISTORY_PATH = exports.STATE_PATH = exports.CONFIG_PATH = void 0;
6
+ exports.CONFIG_PATH = "/etc/portsecure/daemon.json";
7
+ exports.STATE_PATH = "/var/lib/portsecure/state.json";
8
+ exports.KEYS_HISTORY_PATH = "/var/lib/portsecure/authorized-keys-history";
9
+ exports.ROOT_AUTHORIZED_KEYS = "/root/.ssh/authorized_keys";
10
+ exports.SSHD_CONFIG_PATH = "/etc/ssh/sshd_config";
11
+ exports.SSHD_DROPIN_DIR = "/etc/ssh/sshd_config.d";
12
+ exports.SSHD_DROPIN_PATH = "/etc/ssh/sshd_config.d/00-portsecure.conf";
13
+ exports.PASSWD_PATH = "/etc/passwd";
14
+ exports.AUTH_LOG_PATH = "/var/log/auth.log";
15
+ exports.CHECK_INTERVAL = 60 * 1000;
16
+ exports.WEBHOOK_CHECK_INTERVAL = 5 * 60 * 1000;
17
+ exports.GIT_TIMEOUT = 120 * 1000;
18
+ exports.MAX_ERROR_BODY_LENGTH = 500;
19
+ // A source that starts being signed by someone new is held at arm's length for this long, so a
20
+ // stolen signing key cannot push keys onto a machine before anyone notices the warning.
21
+ exports.SIGNER_CHANGE_DELAY = 24 * 60 * 60 * 1000;
22
+ // An unrevoke waits this long before taking effect, so a compromised signing key cannot instantly
23
+ // undo the revocation that locked it out.
24
+ exports.UNREVOKE_DELAY = 60 * 60 * 1000;
25
+ // After this many consecutive failures a repo is thrown away and cloned from scratch, which
26
+ // recovers from corruption and interrupted fetches. Counted in checks, so about a quarter hour.
27
+ exports.MAX_REPO_FAILURES_BEFORE_RECLONE = 15;
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGF0aHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJwYXRocy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsaUdBQWlHO0FBQ2pHLG9FQUFvRTs7O0FBRXZELFFBQUEsV0FBVyxHQUFHLDZCQUE2QixDQUFDO0FBQzVDLFFBQUEsVUFBVSxHQUFHLGdDQUFnQyxDQUFDO0FBQzlDLFFBQUEsaUJBQWlCLEdBQUcsNkNBQTZDLENBQUM7QUFDbEUsUUFBQSxvQkFBb0IsR0FBRyw0QkFBNEIsQ0FBQztBQUNwRCxRQUFBLGdCQUFnQixHQUFHLHNCQUFzQixDQUFDO0FBQzFDLFFBQUEsZUFBZSxHQUFHLHdCQUF3QixDQUFDO0FBQzNDLFFBQUEsZ0JBQWdCLEdBQUcsMkNBQTJDLENBQUM7QUFDL0QsUUFBQSxXQUFXLEdBQUcsYUFBYSxDQUFDO0FBQzVCLFFBQUEsYUFBYSxHQUFHLG1CQUFtQixDQUFDO0FBRXBDLFFBQUEsY0FBYyxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDM0IsUUFBQSxzQkFBc0IsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUN2QyxRQUFBLFdBQVcsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDO0FBQ3pCLFFBQUEscUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBQ3pDLCtGQUErRjtBQUMvRix3RkFBd0Y7QUFDM0UsUUFBQSxtQkFBbUIsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFDdkQsa0dBQWtHO0FBQ2xHLDBDQUEwQztBQUM3QixRQUFBLGNBQWMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQztBQUM3Qyw0RkFBNEY7QUFDNUYsZ0dBQWdHO0FBQ25GLFFBQUEsZ0NBQWdDLEdBQUcsRUFBRSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gTG9jYXRpb25zIHRoZSBkYWVtb24gb3ducy4gRml4ZWQgcmF0aGVyIHRoYW4gY29uZmlndXJhYmxlLCBzbyBldmVyeSBtYWNoaW5lIGxvb2tzIHRoZSBzYW1lIGFuZFxuLy8gdGhlIGNvbmZpZyBmaWxlIG9ubHkgY2FycmllcyB3aGF0IGdlbnVpbmVseSBkaWZmZXJzIGJldHdlZW4gdGhlbS5cblxuZXhwb3J0IGNvbnN0IENPTkZJR19QQVRIID0gXCIvZXRjL3BvcnRzZWN1cmUvZGFlbW9uLmpzb25cIjtcbmV4cG9ydCBjb25zdCBTVEFURV9QQVRIID0gXCIvdmFyL2xpYi9wb3J0c2VjdXJlL3N0YXRlLmpzb25cIjtcbmV4cG9ydCBjb25zdCBLRVlTX0hJU1RPUllfUEFUSCA9IFwiL3Zhci9saWIvcG9ydHNlY3VyZS9hdXRob3JpemVkLWtleXMtaGlzdG9yeVwiO1xuZXhwb3J0IGNvbnN0IFJPT1RfQVVUSE9SSVpFRF9LRVlTID0gXCIvcm9vdC8uc3NoL2F1dGhvcml6ZWRfa2V5c1wiO1xuZXhwb3J0IGNvbnN0IFNTSERfQ09ORklHX1BBVEggPSBcIi9ldGMvc3NoL3NzaGRfY29uZmlnXCI7XG5leHBvcnQgY29uc3QgU1NIRF9EUk9QSU5fRElSID0gXCIvZXRjL3NzaC9zc2hkX2NvbmZpZy5kXCI7XG5leHBvcnQgY29uc3QgU1NIRF9EUk9QSU5fUEFUSCA9IFwiL2V0Yy9zc2gvc3NoZF9jb25maWcuZC8wMC1wb3J0c2VjdXJlLmNvbmZcIjtcbmV4cG9ydCBjb25zdCBQQVNTV0RfUEFUSCA9IFwiL2V0Yy9wYXNzd2RcIjtcbmV4cG9ydCBjb25zdCBBVVRIX0xPR19QQVRIID0gXCIvdmFyL2xvZy9hdXRoLmxvZ1wiO1xuXG5leHBvcnQgY29uc3QgQ0hFQ0tfSU5URVJWQUwgPSA2MCAqIDEwMDA7XG5leHBvcnQgY29uc3QgV0VCSE9PS19DSEVDS19JTlRFUlZBTCA9IDUgKiA2MCAqIDEwMDA7XG5leHBvcnQgY29uc3QgR0lUX1RJTUVPVVQgPSAxMjAgKiAxMDAwO1xuZXhwb3J0IGNvbnN0IE1BWF9FUlJPUl9CT0RZX0xFTkdUSCA9IDUwMDtcbi8vIEEgc291cmNlIHRoYXQgc3RhcnRzIGJlaW5nIHNpZ25lZCBieSBzb21lb25lIG5ldyBpcyBoZWxkIGF0IGFybSdzIGxlbmd0aCBmb3IgdGhpcyBsb25nLCBzbyBhXG4vLyBzdG9sZW4gc2lnbmluZyBrZXkgY2Fubm90IHB1c2gga2V5cyBvbnRvIGEgbWFjaGluZSBiZWZvcmUgYW55b25lIG5vdGljZXMgdGhlIHdhcm5pbmcuXG5leHBvcnQgY29uc3QgU0lHTkVSX0NIQU5HRV9ERUxBWSA9IDI0ICogNjAgKiA2MCAqIDEwMDA7XG4vLyBBbiB1bnJldm9rZSB3YWl0cyB0aGlzIGxvbmcgYmVmb3JlIHRha2luZyBlZmZlY3QsIHNvIGEgY29tcHJvbWlzZWQgc2lnbmluZyBrZXkgY2Fubm90IGluc3RhbnRseVxuLy8gdW5kbyB0aGUgcmV2b2NhdGlvbiB0aGF0IGxvY2tlZCBpdCBvdXQuXG5leHBvcnQgY29uc3QgVU5SRVZPS0VfREVMQVkgPSA2MCAqIDYwICogMTAwMDtcbi8vIEFmdGVyIHRoaXMgbWFueSBjb25zZWN1dGl2ZSBmYWlsdXJlcyBhIHJlcG8gaXMgdGhyb3duIGF3YXkgYW5kIGNsb25lZCBmcm9tIHNjcmF0Y2gsIHdoaWNoXG4vLyByZWNvdmVycyBmcm9tIGNvcnJ1cHRpb24gYW5kIGludGVycnVwdGVkIGZldGNoZXMuIENvdW50ZWQgaW4gY2hlY2tzLCBzbyBhYm91dCBhIHF1YXJ0ZXIgaG91ci5cbmV4cG9ydCBjb25zdCBNQVhfUkVQT19GQUlMVVJFU19CRUZPUkVfUkVDTE9ORSA9IDE1O1xuIl19
29
+ /* _JS_SOURCE_HASH = "04c95747c8ff6d5611015502a598fe430e5fddd148541921318ff8e5ec0cbf25"; */
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
+ //exports.listRepoDir = exports.readRepoFile = exports.syncRepoFiles = exports.ensureRevokeKey = exports.revokeRepo = exports.sourceRepo = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const revokeSource_1 = require("../revokeSource");
10
+ const sources_1 = require("../sources");
11
+ const git_1 = require("./git");
12
+ function sourceRepo(sourceURL) {
13
+ return {
14
+ repoURL: sourceURL,
15
+ repoPath: (0, sources_1.sourceRepoPath)(sourceURL),
16
+ keyPath: async () => await (0, sources_1.findSourceKey)(sourceURL) || (0, sources_1.sourceKeyPath)(sourceURL),
17
+ };
18
+ }
19
+ exports.sourceRepo = sourceRepo;
20
+ function revokeRepo(sourceURL) {
21
+ return {
22
+ repoURL: (0, revokeSource_1.revokeRepoURL)(sourceURL),
23
+ repoPath: (0, revokeSource_1.revokeRepoPath)(sourceURL),
24
+ keyPath: () => ensureRevokeKey(sourceURL),
25
+ };
26
+ }
27
+ exports.revokeRepo = revokeRepo;
28
+ /** The revoke repo's key is worked out from the source's, so nothing extra had to be uploaded and
29
+ nothing extra is stored anywhere it could be taken from. */
30
+ async function ensureRevokeKey(sourceURL) {
31
+ let existing = await (0, revokeSource_1.findRevokeKey)(sourceURL);
32
+ if (existing) {
33
+ return existing;
34
+ }
35
+ let sourceKey = await (0, sources_1.findSourceKey)(sourceURL);
36
+ if (!sourceKey) {
37
+ throw new Error(`Expected a key for ${sourceURL} at ${(0, sources_1.sourceKeyPath)(sourceURL)}, no such file exists`);
38
+ }
39
+ let derived = (0, revokeSource_1.deriveRevokeKey)(await promises_1.default.readFile(sourceKey, "utf8"));
40
+ let keyPath = (0, revokeSource_1.revokeKeyPath)(sourceURL);
41
+ await promises_1.default.mkdir(path_1.default.dirname(keyPath), { recursive: true, mode: 0o700 });
42
+ await promises_1.default.writeFile(keyPath, derived.privateKeyFile, { mode: 0o600 });
43
+ await promises_1.default.writeFile(`${keyPath}.pub`, `${derived.publicKey} ${revokeSource_1.REVOKE_KEY_LABEL}\n`, { mode: 0o644 });
44
+ console.log(`Derived the revoke key for ${sourceURL} into ${keyPath}`);
45
+ return keyPath;
46
+ }
47
+ exports.ensureRevokeKey = ensureRevokeKey;
48
+ async function pathExists(filePath) {
49
+ try {
50
+ await promises_1.default.access(filePath);
51
+ return true;
52
+ }
53
+ catch (e) {
54
+ return false;
55
+ }
56
+ }
57
+ /** Brings the checkout in line with the remote. Cloned the first time, pulled after that, and the
58
+ usual case of nothing having changed costs one ref listing and no objects. Throws if the repo
59
+ cannot be read, so a caller cannot mistake that for an empty repo. */
60
+ async function syncRepoFiles(repo) {
61
+ let { repoURL, repoPath } = repo;
62
+ let keyPath = await repo.keyPath();
63
+ if (!await (0, git_1.repoIsUsable)({ repoPath, keyPath })) {
64
+ await (0, git_1.cloneRepo)({ repoURL, repoPath, keyPath });
65
+ return;
66
+ }
67
+ let localHead = await (0, git_1.runGit)({ args: ["rev-parse", "HEAD"], cwd: repoPath, keyPath, allowFailure: true });
68
+ if (localHead.status !== 0) {
69
+ // A repo with no commits yet, which is the state every revoke repo starts in. There is
70
+ // nothing to pull and nothing to say.
71
+ return;
72
+ }
73
+ let branch = (await (0, git_1.runGit)({ args: ["rev-parse", "--abbrev-ref", "HEAD"], cwd: repoPath, keyPath })).stdout.trim();
74
+ let listing = (await (0, git_1.runGit)({ args: ["ls-remote", "origin", branch], cwd: repoPath, keyPath })).stdout;
75
+ let remoteSha = (listing.split(/\s+/)[0] || "").trim();
76
+ if (remoteSha && remoteSha === localHead.stdout.trim()) {
77
+ return;
78
+ }
79
+ await (0, git_1.runGit)({ args: ["fetch", "--prune", "origin"], cwd: repoPath, keyPath });
80
+ await (0, git_1.runGit)({ args: ["reset", "--hard", `origin/${branch}`], cwd: repoPath, keyPath });
81
+ await (0, git_1.runGit)({ args: ["clean", "-fdx"], cwd: repoPath, keyPath });
82
+ }
83
+ exports.syncRepoFiles = syncRepoFiles;
84
+ /** Throws when there is no checkout at all. "I have never managed to read this repo" and "this
85
+ repo is empty" are different answers and must not collapse into one. */
86
+ async function requireCheckout(repo) {
87
+ if (!await pathExists(path_1.default.join(repo.repoPath, ".git"))) {
88
+ throw new Error(`Expected a checkout of ${repo.repoURL} at ${repo.repoPath}, there is none`);
89
+ }
90
+ }
91
+ /** One file out of the repo, or undefined if the repo does not have that file. */
92
+ async function readRepoFile(repo, filePath) {
93
+ await requireCheckout(repo);
94
+ try {
95
+ return await promises_1.default.readFile(path_1.default.join(repo.repoPath, filePath), "utf8");
96
+ }
97
+ catch (e) {
98
+ return undefined;
99
+ }
100
+ }
101
+ exports.readRepoFile = readRepoFile;
102
+ /** The names in one of the repo's directories, or nothing if it has no such directory. */
103
+ async function listRepoDir(repo, directory) {
104
+ await requireCheckout(repo);
105
+ try {
106
+ return (await promises_1.default.readdir(path_1.default.join(repo.repoPath, directory))).sort();
107
+ }
108
+ catch (e) {
109
+ return [];
110
+ }
111
+ }
112
+ exports.listRepoDir = listRepoDir;
113
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVwb0ZpbGVzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmVwb0ZpbGVzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLDJEQUE2QjtBQUM3QixnREFBd0I7QUFDeEIsa0RBQWlJO0FBQ2pJLHdDQUEwRTtBQUMxRSwrQkFBd0Q7QUFleEQsU0FBZ0IsVUFBVSxDQUFDLFNBQWlCO0lBQ3hDLE9BQU87UUFDSCxPQUFPLEVBQUUsU0FBUztRQUNsQixRQUFRLEVBQUUsSUFBQSx3QkFBYyxFQUFDLFNBQVMsQ0FBQztRQUNuQyxPQUFPLEVBQUUsS0FBSyxJQUFJLEVBQUUsQ0FBQyxNQUFNLElBQUEsdUJBQWEsRUFBQyxTQUFTLENBQUMsSUFBSSxJQUFBLHVCQUFhLEVBQUMsU0FBUyxDQUFDO0tBQ2xGLENBQUM7QUFDTixDQUFDO0FBTkQsZ0NBTUM7QUFFRCxTQUFnQixVQUFVLENBQUMsU0FBaUI7SUFDeEMsT0FBTztRQUNILE9BQU8sRUFBRSxJQUFBLDRCQUFhLEVBQUMsU0FBUyxDQUFDO1FBQ2pDLFFBQVEsRUFBRSxJQUFBLDZCQUFjLEVBQUMsU0FBUyxDQUFDO1FBQ25DLE9BQU8sRUFBRSxHQUFHLEVBQUUsQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDO0tBQzVDLENBQUM7QUFDTixDQUFDO0FBTkQsZ0NBTUM7QUFFRDsrREFDK0Q7QUFDeEQsS0FBSyxVQUFVLGVBQWUsQ0FBQyxTQUFpQjtJQUNuRCxJQUFJLFFBQVEsR0FBRyxNQUFNLElBQUEsNEJBQWEsRUFBQyxTQUFTLENBQUMsQ0FBQztJQUM5QyxJQUFJLFFBQVEsRUFBRSxDQUFDO1FBQ1gsT0FBTyxRQUFRLENBQUM7SUFDcEIsQ0FBQztJQUNELElBQUksU0FBUyxHQUFHLE1BQU0sSUFBQSx1QkFBYSxFQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQy9DLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztRQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsc0JBQXNCLFNBQVMsT0FBTyxJQUFBLHVC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QUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ3pFLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1QsT0FBTyxTQUFTLENBQUM7SUFDckIsQ0FBQztBQUNMLENBQUM7QUFQRCxvQ0FPQztBQUVELDBGQUEwRjtBQUNuRixLQUFLLFVBQVUsV0FBVyxDQUFDLElBQWEsRUFBRSxTQUFpQjtJQUM5RCxNQUFNLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUM1QixJQUFJLENBQUM7UUFDRCxPQUFPLENBQUMsTUFBTSxrQkFBRSxDQUFDLE9BQU8sQ0FBQyxjQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBQzFFLENBQUM7SUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1FBQ1QsT0FBTyxFQUFFLENBQUM7SUFDZCxDQUFDO0FBQ0wsQ0FBQztBQVBELGtDQU9DIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGZzIGZyb20gXCJmcy9wcm9taXNlc1wiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGRlcml2ZVJldm9rZUtleSwgZmluZFJldm9rZUtleSwgUkVWT0tFX0tFWV9MQUJFTCwgcmV2b2tlS2V5UGF0aCwgcmV2b2tlUmVwb1BhdGgsIHJldm9rZVJlcG9VUkwgfSBmcm9tIFwiLi4vcmV2b2tlU291cmNlXCI7XG5pbXBvcnQgeyBmaW5kU291cmNlS2V5LCBzb3VyY2VLZXlQYXRoLCBzb3VyY2VSZXBvUGF0aCB9IGZyb20gXCIuLi9zb3VyY2VzXCI7XG5pbXBvcnQgeyBjbG9uZVJlcG8sIHJlcG9Jc1VzYWJsZSwgcnVuR2l0IH0gZnJvbSBcIi4vZ2l0XCI7XG5cbi8qKiBSZWFkaW5nIGEgcmVwbywgbWFkZSB0byBsb29rIGxpa2UgcmVhZGluZyBhIGRpcmVjdG9yeS4gQSBjYWxsZXIgYXNrcyBmb3IgYSBmaWxlIGFuZCBnZXRzIGl0c1xuICAgIGNvbnRlbnRzOyBrZWVwaW5nIGEgY2hlY2tvdXQgb24gZGlzaywgY2xvbmluZyBpdCBvbmNlIGFuZCBwdWxsaW5nIGl0IHNpbmNlLCBpcyB0aGlzIG1vZHVsZSdzXG4gICAgYnVzaW5lc3MgYW5kIG5vYm9keSBlbHNlJ3MuXG5cbiAgICBOb3RoaW5nIGhlcmUgZXZlciBhbnN3ZXJzIFwidGhlcmUgaXMgbm90aGluZ1wiIHdoZW4gdGhlIHRydXRoIGlzIFwiSSBjb3VsZCBub3QgbG9va1wiLiBBIHJlcG8gdGhhdFxuICAgIGNhbm5vdCBiZSByZWFjaGVkIHRocm93cywgYW5kIHRoZSBjYWxsZXIgc2tpcHMgdGhhdCBzb3VyY2UsIGJlY2F1c2UgcmVhZGluZyBhbiB1bnJlYWNoYWJsZVxuICAgIHJldm9rZSByZXBvIGFzIGVtcHR5IHdvdWxkIHVuLXJldm9rZSBldmVyeSBrZXkgaW4gaXQuICovXG5leHBvcnQgdHlwZSBSZXBvUmVmID0ge1xuICAgIHJlcG9VUkw6IHN0cmluZztcbiAgICByZXBvUGF0aDogc3RyaW5nO1xuICAgIGtleVBhdGg6ICgpID0+IFByb21pc2U8c3RyaW5nPjtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBzb3VyY2VSZXBvKHNvdXJjZVVSTDogc3RyaW5nKTogUmVwb1JlZiB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgcmVwb1VSTDogc291cmNlVVJMLFxuICAgICAgICByZXBvUGF0aDogc291cmNlUmVwb1BhdGgoc291cmNlVVJMKSxcbiAgICAgICAga2V5UGF0aDogYXN5bmMgKCkgPT4gYXdhaXQgZmluZFNvdXJjZUtleShzb3VyY2VVUkwpIHx8IHNvdXJjZUtleVBhdGgoc291cmNlVVJMKSxcbiAgICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmV2b2tlUmVwbyhzb3VyY2VVUkw6IHN0cmluZyk6IFJlcG9SZWYge1xuICAgIHJldHVybiB7XG4gICAgICAgIHJlcG9VUkw6IHJldm9rZVJlcG9VUkwoc291cmNlVVJMKSxcbiAgICAgICAgcmVwb1BhdGg6IHJldm9rZVJlcG9QYXRoKHNvdXJjZVVSTCksXG4gICAgICAgIGtleVBhdGg6ICgpID0+IGVuc3VyZVJldm9rZUtleShzb3VyY2VVUkwpLFxuICAgIH07XG59XG5cbi8qKiBUaGUgcmV2b2tlIHJlcG8ncyBrZXkgaXMgd29ya2VkIG91dCBmcm9tIHRoZSBzb3VyY2Uncywgc28gbm90aGluZyBleHRyYSBoYWQgdG8gYmUgdXBsb2FkZWQgYW5kXG4gICAgbm90aGluZyBleHRyYSBpcyBzdG9yZWQgYW55d2hlcmUgaXQgY291bGQgYmUgdGFrZW4gZnJvbS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBlbnN1cmVSZXZva2VLZXkoc291cmNlVVJMOiBzdHJpbmcpIHtcbiAgICBsZXQgZXhpc3RpbmcgPSBhd2FpdCBmaW5kUmV2b2tlS2V5KHNvdXJjZVVSTCk7XG4gICAgaWYgKGV4aXN0aW5nKSB7XG4gICAgICAgIHJldHVybiBleGlzdGluZztcbiAgICB9XG4gICAgbGV0IHNvdXJjZUtleSA9IGF3YWl0IGZpbmRTb3VyY2VLZXkoc291cmNlVVJMKTtcbiAgICBpZiAoIXNvdXJjZUtleSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGEga2V5IGZvciAke3NvdXJjZVVSTH0gYXQgJHtzb3VyY2VLZXlQYXRoKHNvdXJjZVVSTCl9LCBubyBzdWNoIGZpbGUgZXhpc3RzYCk7XG4gICAgfVxuICAgIGxldCBkZXJpdmVkID0gZGVyaXZlUmV2b2tlS2V5KGF3YWl0IGZzLnJlYWRGaWxlKHNvdXJjZUtleSwgXCJ1dGY4XCIpKTtcbiAgICBsZXQga2V5UGF0aCA9IHJldm9rZUtleVBhdGgoc291cmNlVVJMKTtcbiAgICBhd2FpdCBmcy5ta2RpcihwYXRoLmRpcm5hbWUoa2V5UGF0aCksIHsgcmVjdXJzaXZlOiB0cnVlLCBtb2RlOiAwbzcwMCB9KTtcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoa2V5UGF0aCwgZGVyaXZlZC5wcml2YXRlS2V5RmlsZSwgeyBtb2RlOiAwbzYwMCB9KTtcbiAgICBhd2FpdCBmcy53cml0ZUZpbGUoYCR7a2V5UGF0aH0ucHViYCwgYCR7ZGVyaXZlZC5wdWJsaWNLZXl9ICR7UkVWT0tFX0tFWV9MQUJFTH1cXG5gLCB7IG1vZGU6IDBvNjQ0IH0pO1xuICAgIGNvbnNvbGUubG9nKGBEZXJpdmVkIHRoZSByZXZva2Uga2V5IGZvciAke3NvdXJjZVVSTH0gaW50byAke2tleVBhdGh9YCk7XG4gICAgcmV0dXJuIGtleVBhdGg7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBhdGhFeGlzdHMoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZzLmFjY2VzcyhmaWxlUGF0aCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuLyoqIEJyaW5ncyB0aGUgY2hlY2tvdXQgaW4gbGluZSB3aXRoIHRoZSByZW1vdGUuIENsb25lZCB0aGUgZmlyc3QgdGltZSwgcHVsbGVkIGFmdGVyIHRoYXQsIGFuZCB0aGVcbiAgICB1c3VhbCBjYXNlIG9mIG5vdGhpbmcgaGF2aW5nIGNoYW5nZWQgY29zdHMgb25lIHJlZiBsaXN0aW5nIGFuZCBubyBvYmplY3RzLiBUaHJvd3MgaWYgdGhlIHJlcG9cbiAgICBjYW5ub3QgYmUgcmVhZCwgc28gYSBjYWxsZXIgY2Fubm90IG1pc3Rha2UgdGhhdCBmb3IgYW4gZW1wdHkgcmVwby4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzeW5jUmVwb0ZpbGVzKHJlcG86IFJlcG9SZWYpIHtcbiAgICBsZXQgeyByZXBvVVJMLCByZXBvUGF0aCB9ID0gcmVwbztcbiAgICBsZXQga2V5UGF0aCA9IGF3YWl0IHJlcG8ua2V5UGF0aCgpO1xuICAgIGlmICghYXdhaXQgcmVwb0lzVXNhYmxlKHsgcmVwb1BhdGgsIGtleVBhdGggfSkpIHtcbiAgICAgICAgYXdhaXQgY2xvbmVSZXBvKHsgcmVwb1VSTCwgcmVwb1BhdGgsIGtleVBhdGggfSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgbGV0IGxvY2FsSGVhZCA9IGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcInJldi1wYXJzZVwiLCBcIkhFQURcIl0sIGN3ZDogcmVwb1BhdGgsIGtleVBhdGgsIGFsbG93RmFpbHVyZTogdHJ1ZSB9KTtcbiAgICBpZiAobG9jYWxIZWFkLnN0YXR1cyAhPT0gMCkge1xuICAgICAgICAvLyBBIHJlcG8gd2l0aCBubyBjb21taXRzIHlldCwgd2hpY2ggaXMgdGhlIHN0YXRlIGV2ZXJ5IHJldm9rZSByZXBvIHN0YXJ0cyBpbi4gVGhlcmUgaXNcbiAgICAgICAgLy8gbm90aGluZyB0byBwdWxsIGFuZCBub3RoaW5nIHRvIHNheS5cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgYnJhbmNoID0gKGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcInJldi1wYXJzZVwiLCBcIi0tYWJicmV2LXJlZlwiLCBcIkhFQURcIl0sIGN3ZDogcmVwb1BhdGgsIGtleVBhdGggfSkpLnN0ZG91dC50cmltKCk7XG4gICAgbGV0IGxpc3RpbmcgPSAoYXdhaXQgcnVuR2l0KHsgYXJnczogW1wibHMtcmVtb3RlXCIsIFwib3JpZ2luXCIsIGJyYW5jaF0sIGN3ZDogcmVwb1BhdGgsIGtleVBhdGggfSkpLnN0ZG91dDtcbiAgICBsZXQgcmVtb3RlU2hhID0gKGxpc3Rpbmcuc3BsaXQoL1xccysvKVswXSB8fCBcIlwiKS50cmltKCk7XG4gICAgaWYgKHJlbW90ZVNoYSAmJiByZW1vdGVTaGEgPT09IGxvY2FsSGVhZC5zdGRvdXQudHJpbSgpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgYXdhaXQgcnVuR2l0KHsgYXJnczogW1wiZmV0Y2hcIiwgXCItLXBydW5lXCIsIFwib3JpZ2luXCJdLCBjd2Q6IHJlcG9QYXRoLCBrZXlQYXRoIH0pO1xuICAgIGF3YWl0IHJ1bkdpdCh7IGFyZ3M6IFtcInJlc2V0XCIsIFwiLS1oYXJkXCIsIGBvcmlnaW4vJHticmFuY2h9YF0sIGN3ZDogcmVwb1BhdGgsIGtleVBhdGggfSk7XG4gICAgYXdhaXQgcnVuR2l0KHsgYXJnczogW1wiY2xlYW5cIiwgXCItZmR4XCJdLCBjd2Q6IHJlcG9QYXRoLCBrZXlQYXRoIH0pO1xufVxuXG4vKiogVGhyb3dzIHdoZW4gdGhlcmUgaXMgbm8gY2hlY2tvdXQgYXQgYWxsLiBcIkkgaGF2ZSBuZXZlciBtYW5hZ2VkIHRvIHJlYWQgdGhpcyByZXBvXCIgYW5kIFwidGhpc1xuICAgIHJlcG8gaXMgZW1wdHlcIiBhcmUgZGlmZmVyZW50IGFuc3dlcnMgYW5kIG11c3Qgbm90IGNvbGxhcHNlIGludG8gb25lLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVxdWlyZUNoZWNrb3V0KHJlcG86IFJlcG9SZWYpIHtcbiAgICBpZiAoIWF3YWl0IHBhdGhFeGlzdHMocGF0aC5qb2luKHJlcG8ucmVwb1BhdGgsIFwiLmdpdFwiKSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhIGNoZWNrb3V0IG9mICR7cmVwby5yZXBvVVJMfSBhdCAke3JlcG8ucmVwb1BhdGh9LCB0aGVyZSBpcyBub25lYCk7XG4gICAgfVxufVxuXG4vKiogT25lIGZpbGUgb3V0IG9mIHRoZSByZXBvLCBvciB1bmRlZmluZWQgaWYgdGhlIHJlcG8gZG9lcyBub3QgaGF2ZSB0aGF0IGZpbGUuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZFJlcG9GaWxlKHJlcG86IFJlcG9SZWYsIGZpbGVQYXRoOiBzdHJpbmcpIHtcbiAgICBhd2FpdCByZXF1aXJlQ2hlY2tvdXQocmVwbyk7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvLnJlcG9QYXRoLCBmaWxlUGF0aCksIFwidXRmOFwiKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxufVxuXG4vKiogVGhlIG5hbWVzIGluIG9uZSBvZiB0aGUgcmVwbydzIGRpcmVjdG9yaWVzLCBvciBub3RoaW5nIGlmIGl0IGhhcyBubyBzdWNoIGRpcmVjdG9yeS4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0UmVwb0RpcihyZXBvOiBSZXBvUmVmLCBkaXJlY3Rvcnk6IHN0cmluZykge1xuICAgIGF3YWl0IHJlcXVpcmVDaGVja291dChyZXBvKTtcbiAgICB0cnkge1xuICAgICAgICByZXR1cm4gKGF3YWl0IGZzLnJlYWRkaXIocGF0aC5qb2luKHJlcG8ucmVwb1BhdGgsIGRpcmVjdG9yeSkpKS5zb3J0KCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gW107XG4gICAgfVxufVxuIl19
114
+ /* _JS_SOURCE_HASH = "7340581691819b6036825721d39ae6393118181e0730254e1cead9650e3aa91e"; */