sliftutils 1.7.128 → 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 (51) 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 +43 -34
  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/notify.ts +8 -2
  26. package/security/authorizedKeys/daemon/repoFiles.ts +118 -0
  27. package/security/authorizedKeys/daemon/revocation.ts +0 -0
  28. package/security/authorizedKeys/daemon/rootKeys.ts +77 -10
  29. package/security/authorizedKeys/daemon/state.ts +25 -7
  30. package/security/authorizedKeys/daemon/trust.ts +37 -16
  31. package/security/authorizedKeys/daemon/userKeys.ts +5 -4
  32. package/security/authorizedKeys/dist/authorizedKeys.ts.cache +37 -3
  33. package/security/authorizedKeys/dist/revokeSource.ts.cache +17 -4
  34. package/security/authorizedKeys/dist/sources.ts.cache +52 -8
  35. package/security/authorizedKeys/dist/unrevoke.ts.cache +113 -17
  36. package/security/authorizedKeys/secureSSH.ts +39 -21
  37. package/security/authorizedKeys/unrevoke.ts +159 -8
  38. package/security/helpers/dist/remoteSSH.ts.cache +19 -9
  39. package/security/machines/addMachine.ts +83 -0
  40. package/security/machines/dist/addMachine.ts.cache +88 -0
  41. package/security/machines/dist/identity.ts.cache +176 -0
  42. package/security/machines/dist/machines.ts.cache +322 -0
  43. package/security/machines/dist/trustClient.ts.cache +48 -0
  44. package/security/machines/dist/trustState.ts.cache +57 -0
  45. package/security/machines/identity.ts +199 -0
  46. package/security/machines/machines.ts +355 -0
  47. package/security/machines/trustClient.ts +51 -0
  48. package/security/machines/trustServer.ts +85 -0
  49. package/security/machines/trustState.ts +53 -0
  50. package/security/notifications/discord.ts +14 -5
  51. package/security/notifications/dist/discord.ts.cache +17 -8
@@ -1,6 +1,6 @@
1
1
  import fs from "fs/promises";
2
2
  import path from "path";
3
- import { keyFingerprint, keyRestriction, keyRestrictionList, NO_RESTRICTION, summarizeKey } from "../authorizedKeys";
3
+ import { keyFingerprint, keyNiceName, keyRestriction, keyRestrictionList, NO_RESTRICTION, summarizeKey } from "../authorizedKeys";
4
4
  import { KEYS_HISTORY_PATH, ROOT_AUTHORIZED_KEYS } from "./paths";
5
5
  import { notify } from "./notify";
6
6
  import { getState, saveState } from "./state";
@@ -53,6 +53,64 @@ function describeAddressChange(config: { previousLine: string; currentLine: stri
53
53
  return lines.join("\n");
54
54
  }
55
55
 
56
+ /** The change in one line, for the notification preview. One key added, one removed, or one
57
+ address gained or lost, said plainly - that covers nearly every real change. Anything with more
58
+ than one part to it falls back to counting, because a line that tries to say four things says
59
+ none of them in the space a preview gives it. */
60
+ export function summarizeKeyDifference(config: { before: string[]; after: string[] }) {
61
+ let { before, after } = config;
62
+ let beforeByKey = new Map(before.map(key => [keyIdentity(key), key]));
63
+ let afterByKey = new Map(after.map(key => [keyIdentity(key), key]));
64
+
65
+ let added = [...afterByKey].filter(([identity]) => !beforeByKey.has(identity)).map(([, key]) => key);
66
+ let removed = [...beforeByKey].filter(([identity]) => !afterByKey.has(identity)).map(([, key]) => key);
67
+ let addressesAdded: { key: string; address: string }[] = [];
68
+ let addressesRemoved: { key: string; address: string }[] = [];
69
+ let otherwiseChanged: string[] = [];
70
+ for (let [identity, previousLine] of beforeByKey) {
71
+ let currentLine = afterByKey.get(identity);
72
+ if (!currentLine || currentLine === previousLine) {
73
+ continue;
74
+ }
75
+ let keyLine = currentLine;
76
+ let previous = keyRestrictionList(previousLine) || [];
77
+ let current = keyRestrictionList(keyLine) || [];
78
+ let gained = current.filter(address => !previous.includes(address));
79
+ let lost = previous.filter(address => !current.includes(address));
80
+ if (!gained.length && !lost.length) {
81
+ otherwiseChanged.push(keyLine);
82
+ continue;
83
+ }
84
+ addressesAdded.push(...gained.map(address => ({ key: keyLine, address })));
85
+ addressesRemoved.push(...lost.map(address => ({ key: keyLine, address })));
86
+ }
87
+
88
+ let changes = added.length + removed.length + addressesAdded.length + addressesRemoved.length
89
+ + otherwiseChanged.length;
90
+ if (changes === 1) {
91
+ if (added.length) {
92
+ return `SSH KEY ADDED ${keyNiceName(added[0])}`;
93
+ }
94
+ if (removed.length) {
95
+ return `SSH KEY REMOVED ${keyNiceName(removed[0])}`;
96
+ }
97
+ if (addressesAdded.length) {
98
+ return `IP ${addressesAdded[0].address} ALLOWED ON ${keyNiceName(addressesAdded[0].key)}`;
99
+ }
100
+ if (addressesRemoved.length) {
101
+ return `IP ${addressesRemoved[0].address} REMOVED FROM ${keyNiceName(addressesRemoved[0].key)}`;
102
+ }
103
+ return `SSH KEY CHANGED ${keyNiceName(otherwiseChanged[0])}`;
104
+ }
105
+ let counted = [
106
+ added.length && `${added.length} key(s) added` || "",
107
+ removed.length && `${removed.length} key(s) removed` || "",
108
+ addressesAdded.length && `${addressesAdded.length} IP(s) allowed` || "",
109
+ addressesRemoved.length && `${addressesRemoved.length} IP(s) removed` || "",
110
+ ].filter(part => part);
111
+ return `SSH KEYS CHANGED: ${counted.join(", ") || "no keys differ"}`;
112
+ }
113
+
56
114
  export function describeKeyDifference(config: { before: string[]; after: string[] }) {
57
115
  let { before, after } = config;
58
116
  let beforeByKey = new Map(before.map(key => [keyIdentity(key), key]));
@@ -181,18 +239,27 @@ export async function enforceRootKeys(keys: string[]) {
181
239
  state.appliedKeys = keys;
182
240
  await saveState();
183
241
 
184
- let reasons = takeChangeReasons();
185
- let why = reasons.length && `\n\n${reasons.join("\n\n")}` || "";
242
+ let { leading, reasons } = takeChangeReasons();
243
+ // An attack names the message. Whoever is looking at a preview needs to see that, not that
244
+ // some keys changed - the change is what the attack caused.
245
+ let alert = leading.map(entry => entry.body).join("\n\n");
246
+ let why = [alert, ...reasons].filter(part => part).join("\n\n");
247
+ let before = weChangedIt && previouslyApplied || keys;
248
+ let after = weChangedIt && keys || currentKeys;
249
+ let headline = leading[0]?.headline || summarizeKeyDifference({ before, after });
250
+
186
251
  if (weChangedIt) {
187
- await notify(
188
- `applied authorized key changes:`
189
- + `\n\`\`\`\n${describeKeyDifference({ before: previouslyApplied, after: keys })}\n\`\`\`${why}`
252
+ await notify(headline,
253
+ `Who can log in as root:`
254
+ + `\n\`\`\`\n${describeKeyDifference({ before, after })}\n\`\`\``
255
+ + `${why && `\n${why}` || ""}`
190
256
  );
191
257
  return;
192
258
  }
193
- await notify(
194
- `root's authorized_keys was edited by something other than portsecure. The edit below has`
195
- + ` been undone, and the keys from the repos are back in place.`
196
- + `\n\`\`\`\n${describeKeyDifference({ before: keys, after: currentKeys })}\n\`\`\`${why}`
259
+ await notify(leading[0]?.headline || `SSH KEYS EDITED BY SOMETHING ELSE`,
260
+ `Something other than portsecure edited root's authorized_keys. The edit below has been`
261
+ + ` undone, and the keys from the repos are back in place.`
262
+ + `\n\`\`\`\n${describeKeyDifference({ before, after })}\n\`\`\``
263
+ + `${why && `\n${why}` || ""}`
197
264
  );
198
265
  }
@@ -17,14 +17,26 @@ export type SourceState = {
17
17
  reportedProblem: string;
18
18
  };
19
19
 
20
- /** A key this machine has stopped accepting. Kept even when the revoke repo no longer lists it:
21
- the deploy key that writes revocations lives on every server, so an attacker who took one could
22
- otherwise delete the revocation that locked them out. */
20
+ /** One revocation event: this key, used from this address, so it is no longer accepted. Kept even
21
+ when the revoke repo no longer lists it: the deploy key that writes revocations lives on every
22
+ server, so an attacker who took one could otherwise delete the revocation that locked them out.
23
+
24
+ The id is unique to the event, never derived from the key. A key that has been forgiven for one
25
+ address is still an ordinary key, and using it from some other address revokes it again, with a
26
+ new id that no existing unrevoke names. */
23
27
  export type RevocationState = {
24
- fingerprint: string;
25
28
  revocationId: string;
26
- // Set once an unrevoke has been seen, so the wait can be served out across restarts.
27
- unrevokeSeenAt: number;
29
+ fingerprint: string;
30
+ // The address it was used from. Half of what a revocation says, and the half an unrevoke has
31
+ // to name to undo it.
32
+ ip: string;
33
+ // Why this key was revoked, carried from the revocation file so a machine that reads one
34
+ // written elsewhere can say what happened rather than only that something did.
35
+ revokedAt: string;
36
+ revokedBy: string;
37
+ reason: string;
38
+ // Which unrevoke allowed this key from this address, once one has been seen. When the wait it
39
+ // started runs out is in unrevokeFirstSeen, which outlives the daemon.
28
40
  unrevokeId: string;
29
41
  unrevoked: boolean;
30
42
  // Whether we have said that this key actually left root's authorized_keys. The removal is the
@@ -50,7 +62,12 @@ export type DaemonState = {
50
62
  // revocations is on every server, so whoever stole one could otherwise erase the record that
51
63
  // shut them out. Restarting the daemon does clear it, which is the way back from a revocation
52
64
  // that should not have happened.
53
- revocations: { [fingerprint: string]: RevocationState };
65
+ revocations: { [revocationId: string]: RevocationState };
66
+ // When this machine first saw each unrevoke, by unrevoke id. On disk, unlike the revocations
67
+ // themselves, because it is what the hour long wait is counted from: measuring from a time the
68
+ // unrevoke file states would let whoever wrote it backdate the file and skip the wait, and
69
+ // measuring from process start would restart the wait on every restart.
70
+ unrevokeFirstSeen: { [unrevokeId: string]: number };
54
71
  pendingRevocations: PendingRevocation[];
55
72
  // The keys we last wrote out. What tells a change we made apart from one somebody else made:
56
73
  // if this still matches what we want, and the file does not, the file was edited behind us.
@@ -64,6 +81,7 @@ let state: DaemonState = {
64
81
  sources: {},
65
82
  userKeyHashes: {},
66
83
  revocations: {},
84
+ unrevokeFirstSeen: {},
67
85
  pendingRevocations: [],
68
86
  appliedKeys: [],
69
87
  authLogOffset: 0,
@@ -174,21 +174,31 @@ async function verifyCheckoutSigner(config: {
174
174
  return publicKey;
175
175
  }
176
176
 
177
+ /** Proves a checkout on disk was signed, and that the files in it are the ones that were signed.
178
+ Returns the signer, and throws if anything about that does not hold.
179
+
180
+ Anything reading a repo for something other than ssh keys goes through this first: the whole
181
+ checkout is covered by one manifest, so a machine list is exactly as trustworthy as the keys
182
+ beside it, and neither is worth reading unsigned. */
183
+ export async function verifyCheckout(repoPath: string) {
184
+ return await verifyCheckoutSigner({ repoPath, files: await readSignatureFiles(repoPath) });
185
+ }
186
+
177
187
  export function describeSigner(signer: string) {
178
188
  return signer === UNSIGNED && "<no public key>" || signer;
179
189
  }
180
190
 
181
191
  /** Reports a problem with a source's signature, but only when it is not the same problem we
182
192
  already reported, so a fault that persists does not repeat every check. */
183
- async function reportProblem(config: { repoURL: string; problem: string; message: string }) {
184
- let { repoURL, problem, message } = config;
193
+ async function reportProblem(config: { repoURL: string; problem: string; headline: string; body: string }) {
194
+ let { repoURL, problem, headline, body } = config;
185
195
  let sourceStateValue = sourceState(repoURL);
186
196
  if (sourceStateValue.reportedProblem === problem) {
187
197
  return;
188
198
  }
189
199
  sourceStateValue.reportedProblem = problem;
190
200
  await saveState();
191
- await notify(message);
201
+ await notify(headline, body);
192
202
  }
193
203
 
194
204
  /** The keys a source is allowed to contribute right now. A source signed by someone we have not
@@ -210,17 +220,24 @@ export async function resolveSourceKeys(repoURL: string) {
210
220
  await reportProblem({
211
221
  repoURL,
212
222
  problem: "stale",
213
- message: `\`${repoURL}\` changed but its signature was not updated, so the changes are being`
214
- + ` ignored. Still using the keys signed by \`${describeSigner(sourceStateValue.acceptedSigner)}\`.`
215
- + `\nTo deploy the change, run this in that repo:\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``,
223
+ headline: `KEY REPO CHANGED WITHOUT BEING SIGNED`,
224
+ body: `\`${repoURL}\` changed, but nobody signed the change, so it is being ignored`
225
+ + ` and this machine is still using the keys signed by`
226
+ + ` \`${describeSigner(sourceStateValue.acceptedSigner)}\`.`
227
+ + `\n\nTo make the change take effect, run this in that repo:`
228
+ + `\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``,
216
229
  });
217
230
  } else {
218
231
  await reportProblem({
219
232
  repoURL,
220
233
  problem: "corrupt",
221
- message: `\`${repoURL}\` has a corrupted signature, so its contents are being ignored:`
222
- + ` ${e}.\nStill using the keys signed by \`${describeSigner(sourceStateValue.acceptedSigner)}\`.`
223
- + `\nTo replace it, run this in that repo:\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``,
234
+ headline: `KEY REPO SIGNATURE IS BROKEN`,
235
+ body: `The signature on \`${repoURL}\` does not check out, so everything in it is`
236
+ + ` being ignored and this machine is still using the keys signed by`
237
+ + ` \`${describeSigner(sourceStateValue.acceptedSigner)}\`.`
238
+ + `\n\n${e}`
239
+ + `\n\nTo replace the signature, run this in that repo:`
240
+ + `\n\`\`\`\n${SIGN_COMMAND}\n\`\`\``,
224
241
  });
225
242
  }
226
243
  return sourceStateValue.acceptedKeys;
@@ -259,9 +276,10 @@ export async function resolveSourceKeys(repoURL: string) {
259
276
 
260
277
  // Going from nothing to something signed is only ever an improvement, so it does not wait.
261
278
  if (sourceStateValue.acceptedSigner === UNSIGNED) {
262
- await notify(
263
- `\`${repoURL}\` is now signed, by \`${signer}\`. It was not signed before, so its keys are`
264
- + ` being applied right away.`
279
+ await notify(`KEY REPO IS NOW SIGNED`,
280
+ `\`${repoURL}\` was not signed at all before, so this is an improvement and its keys`
281
+ + ` are being applied right away.`
282
+ + `\n\nsigned by: \`${signer}\``
265
283
  );
266
284
  return await accept();
267
285
  }
@@ -273,10 +291,13 @@ export async function resolveSourceKeys(repoURL: string) {
273
291
  sourceStateValue.pendingSigner = signer;
274
292
  sourceStateValue.pendingSince = Date.now();
275
293
  await saveState();
276
- await notify(
277
- `\`${repoURL}\` is now signed by \`${describeSigner(signer)}\`, where it was signed by`
278
- + ` \`${describeSigner(sourceStateValue.acceptedSigner)}\`. Its keys are NOT being applied.`
279
- + ` If nothing changes they will be applied in 24 hours.`
294
+ await notify(`KEY REPO SIGNED BY A DIFFERENT KEY`,
295
+ `Somebody else is signing \`${repoURL}\` now. Its keys are NOT being applied, and this`
296
+ + ` machine is still using the ones it already had. If nothing changes, the new signer`
297
+ + ` is accepted in 24 hours.`
298
+ + `\n\nIf that was not you, fix the repo before the 24 hours are up.`
299
+ + `\n\nsigned by now: \`${describeSigner(signer)}\``
300
+ + `\nsigned by before: \`${describeSigner(sourceStateValue.acceptedSigner)}\``
280
301
  );
281
302
  return sourceStateValue.acceptedKeys;
282
303
  }
@@ -65,10 +65,11 @@ export async function checkOtherUserKeys() {
65
65
  if (previousHash === undefined || previousHash === hash) {
66
66
  continue;
67
67
  }
68
- await notify(
69
- `authorized_keys for user \`${entry.name}\` changed (\`${entry.filePath}\`).`
70
- + ` portsecure does not manage this account, so the change was left in place.`
71
- + `\n\`\`\`\n${keys.map(summarizeKey).join("\n") || "(now empty)"}\n\`\`\``
68
+ await notify(`SSH KEYS CHANGED FOR USER ${entry.name}`,
69
+ `Somebody changed who can log in as \`${entry.name}\`. portsecure does not manage that`
70
+ + ` account, so the change was left alone. Who can log in as \`${entry.name}\` now:`
71
+ + `\n\`\`\`\n${keys.map(summarizeKey).join("\n") || "(nobody, the file is now empty)"}\n\`\`\``
72
+ + `\n${entry.filePath}`
72
73
  );
73
74
  }
74
75
  state.userKeyHashes = hashes;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
- //exports.readRepoKeys = exports.findKeyProblems = exports.summarizeKey = exports.keyRestriction = exports.keyRestrictionList = exports.NO_RESTRICTION = exports.keyFingerprint = exports.normalizeKeys = void 0;
6
+ //exports.readRepoKeys = exports.findKeyProblems = exports.keyNiceName = exports.summarizeKey = exports.allowAddresses = exports.keyRestriction = exports.keyRestrictionList = exports.NO_RESTRICTION = exports.keyFingerprint = exports.normalizeKeys = 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"));
@@ -44,6 +44,27 @@ function keyRestriction(keyLine) {
44
44
  return list.join(",");
45
45
  }
46
46
  exports.keyRestriction = keyRestriction;
47
+ /** Adds addresses to a key's from= list, leaving the rest of the line exactly as it was. Returns
48
+ which addresses were actually new, so a caller can report only what it changed.
49
+
50
+ A key with no from= at all is left alone: adding one would silently restrict a key that is
51
+ currently unrestricted, which is a different decision than the one being made here. */
52
+ function allowAddresses(keyLine, addresses) {
53
+ let list = keyRestrictionList(keyLine);
54
+ if (!list) {
55
+ return { keyLine, added: [] };
56
+ }
57
+ let allowed = list;
58
+ let added = addresses.filter(address => address && !allowed.includes(address));
59
+ if (!added.length) {
60
+ return { keyLine, added };
61
+ }
62
+ return {
63
+ keyLine: keyLine.replace(/from="[^"]*"/, `from="${[...allowed, ...added].join(",")}"`),
64
+ added,
65
+ };
66
+ }
67
+ exports.allowAddresses = allowAddresses;
47
68
  /** Enough to recognise whose key this is without printing the whole blob. */
48
69
  function summarizeKey(keyLine) {
49
70
  let parts = keyLine.trim().split(/\s+/);
@@ -57,6 +78,19 @@ function summarizeKey(keyLine) {
57
78
  return `${type} ...${blob.slice(-12)}${comment && ` ${comment}` || ""}`;
58
79
  }
59
80
  exports.summarizeKey = summarizeKey;
81
+ /** The shortest thing that still identifies a key to a person: the comment it carries, which is
82
+ usually user@machine, and otherwise the tail of the key itself. For the first line of a
83
+ notification, where there is only room for the one thing that matters. */
84
+ function keyNiceName(keyLine) {
85
+ let parts = keyLine.trim().split(/\s+/);
86
+ let typeIndex = parts.findIndex(part => /^(ssh-|ecdsa-|sk-)/.test(part));
87
+ if (typeIndex < 0) {
88
+ return keyLine.slice(0, 20);
89
+ }
90
+ let comment = parts.slice(typeIndex + 2).join(" ");
91
+ return comment || `...${(parts[typeIndex + 1] || "").slice(-8)}`;
92
+ }
93
+ exports.keyNiceName = keyNiceName;
60
94
  /** What a set of keys has to satisfy before it is worth signing, as a list of complaints.
61
95
 
62
96
  Every key needs a from=, because an unrestricted key can never be caught being used from the
@@ -107,5 +141,5 @@ async function readRepoKeys(repoPath) {
107
141
  return keys;
108
142
  }
109
143
  exports.readRepoKeys = readRepoKeys;
110
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXplZEtleXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJhdXRob3JpemVkS2V5cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUV4QixTQUFnQixhQUFhLENBQUMsUUFBZ0I7SUFDMUMsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUN2RyxDQUFDO0FBRkQsc0NBRUM7QUFFRDs4RUFDOEU7QUFDOUUsU0FBZ0IsY0FBYyxDQUFDLE9BQWU7SUFDMUMsSUFBSSxLQUFLLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN4QyxJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDekUsSUFBSSxJQUFJLEdBQUcsU0FBUyxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN4RCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDUixPQUFPLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFDRCxPQUFPLFNBQVMsR0FBRyxnQkFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsT0FB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QUFDO1FBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMseURBQXlELFFBQVEsaUJBQWlCLENBQUMsQ0FBQztJQUN4RyxDQUFDO0lBQ0QsSUFBSSxJQUFJLEdBQWEsRUFBRSxDQUFDO0lBQ3hCLEtBQUssSUFBSSxJQUFJLElBQUksUUFBUSxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLGFBQWEsQ0FBQyxNQUFNLGtCQUFFLENBQUMsUUFBUSxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDaEIsQ0FBQztBQWZELG9DQWVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplS2V5cyhjb250ZW50czogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGNvbnRlbnRzLnNwbGl0KFwiXFxuXCIpLm1hcChsaW5lID0+IGxpbmUudHJpbSgpKS5maWx0ZXIobGluZSA9PiBsaW5lICYmICFsaW5lLnN0YXJ0c1dpdGgoXCIjXCIpKTtcbn1cblxuLyoqIFRoZSBmaW5nZXJwcmludCBzc2ggaXRzZWxmIHJlcG9ydHMgZm9yIGEga2V5LCB3aGljaCBpcyB3aGF0IHRoZSBzc2hkIGxvZyBuYW1lcyBhbmQgdGhlcmVmb3JlXG4gICAgd2hhdCBhIHJldm9jYXRpb24gaXMga2V5ZWQgYnkuIFJldHVybnMgXCJcIiBmb3IgYSBsaW5lIHRoYXQgaG9sZHMgbm8ga2V5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtleUZpbmdlcnByaW50KGtleUxpbmU6IHN0cmluZykge1xuICAgIGxldCBwYXJ0cyA9IGtleUxpbmUudHJpbSgpLnNwbGl0KC9cXHMrLyk7XG4gICAgbGV0IHR5cGVJbmRleCA9IHBhcnRzLmZpbmRJbmRleChwYXJ0ID0+IC9eKHNzaC18ZWNkc2EtfHNrLSkvLnRlc3QocGFydCkpO1xuICAgIGxldCBibG9iID0gdHlwZUluZGV4ID49IDAgJiYgcGFydHNbdHlwZUluZGV4ICsgMV0gfHwgXCJcIjtcbiAgICBpZiAoIWJsb2IpIHtcbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxuICAgIHJldHVybiBcIlNIQTI1NjpcIiArIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShCdWZmZXIuZnJvbShibG9iLCBcImJhc2U2NFwiKSkuZGlnZXN0KFwiYmFzZTY0XCIpLnJlcGxhY2UoLz0rJC8sIFwiXCIpO1xufVxuXG5leHBvcnQgY29uc3QgTk9fUkVTVFJJQ1RJT04gPSBcIkFOWSBBRERSRVNTIChubyBmcm9tPSByZXN0cmljdGlvbilcIjtcblxuLyoqIFRoZSBhZGRyZXNzZXMgYSBrZXkgbWF5IGJlIHVzZWQgZnJvbSwgb25lIGJ5IG9uZSwgb3IgdW5kZWZpbmVkIHdoZW4gdGhlIGtleSBjYXJyaWVzIG5vIGZyb209XG4gICAgYXQgYWxsLiBVbmRlZmluZWQgYW5kIGFuIGVtcHR5IGxpc3QgYXJlIHZlcnkgZGlmZmVyZW50IHRoaW5ncywgc28gdGhleSBzdGF5IGRpc3Rpbmd1aXNoYWJsZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrZXlSZXN0cmljdGlvbkxpc3Qoa2V5TGluZTogc3RyaW5nKSB7XG4gICAgbGV0IG1hdGNoID0ga2V5TGluZS5tYXRjaCgvZnJvbT1cIihbXlwiXSopXCIvKTtcbiAgICBpZiAoIW1hdGNoKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiBtYXRjaFsxXS5zcGxpdChcIixcIikubWFwKGVudHJ5ID0+IGVudHJ5LnRyaW0oKSkuZmlsdGVyKGVudHJ5ID0+IGVudHJ5KTtcbn1cblxuLyoqIFRoZSBhZGRyZXNzZXMgYSBrZXkgbWF5IGJlIHVzZWQgZnJvbSwgd2hpY2ggaXMgdGhlIHBhcnQgb2YgYW4gYXV0aG9yaXplZF9rZXlzIGxpbmUgdGhhdFxuICAgIGRlY2lkZXMgaG93IG11Y2ggYSBzdG9sZW4ga2V5IGlzIHdvcnRoLiBBIGtleSB3aXRoIG5vIHJlc3RyaWN0aW9uIHNheXMgc28gbG91ZGx5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtleVJlc3RyaWN0aW9uKGtleUxpbmU6IHN0cmluZykge1xuICAgIGxldCBsaXN0ID0ga2V5UmVzdHJpY3Rpb25MaXN0KGtleUxpbmUpO1xuICAgIGlmICghbGlzdCkge1xuICAgICAgICByZXR1cm4gTk9fUkVTVFJJQ1RJT047XG4gICAgfVxuICAgIHJldHVybiBsaXN0LmpvaW4oXCIsXCIpO1xufVxuXG4vKiogRW5vdWdoIHRvIHJlY29nbmlzZSB3aG9zZSBrZXkgdGhpcyBpcyB3aXRob3V0IHByaW50aW5nIHRoZSB3aG9sZSBibG9iLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1bW1hcml6ZUtleShrZXlMaW5lOiBzdHJpbmcpIHtcbiAgICBsZXQgcGFydHMgPSBrZXlMaW5lLnRyaW0oKS5zcGxpdCgvXFxzKy8pO1xuICAgIGxldCB0eXBlSW5kZXggPSBwYXJ0cy5maW5kSW5kZXgocGFydCA9PiAvXihzc2gtfGVjZHNhLXxzay0pLy50ZXN0KHBhcnQpKTtcbiAgICBpZiAodHlwZUluZGV4IDwgMCkge1xuICAgICAgICByZXR1cm4ga2V5TGluZS5zbGljZSgwLCA2MCk7XG4gICAgfVxuICAgIGxldCB0eXBlID0gcGFydHNbdHlwZUluZGV4XTtcbiAgICBsZXQgYmxvYiA9IHBhcnRzW3R5cGVJbmRleCArIDFdIHx8IFwiXCI7XG4gICAgbGV0IGNvbW1lbnQgPSBwYXJ0cy5zbGljZSh0eXBlSW5kZXggKyAyKS5qb2luKFwiIFwiKTtcbiAgICByZXR1cm4gYCR7dHlwZX0gLi4uJHtibG9iLnNsaWNlKC0xMil9JHtjb21tZW50ICYmIGAgJHtjb21tZW50fWAgfHwgXCJcIn1gO1xufVxuXG4vKiogV2hhdCBhIHNldCBvZiBrZXlzIGhhcyB0byBzYXRpc2Z5IGJlZm9yZSBpdCBpcyB3b3J0aCBzaWduaW5nLCBhcyBhIGxpc3Qgb2YgY29tcGxhaW50cy5cblxuICAgIEV2ZXJ5IGtleSBuZWVkcyBhIGZyb209LCBiZWNhdXNlIGFuIHVucmVzdHJpY3RlZCBrZXkgY2FuIG5ldmVyIGJlIGNhdWdodCBiZWluZyB1c2VkIGZyb20gdGhlXG4gICAgd3JvbmcgcGxhY2UsIGFuZCBiZWluZyBjYXVnaHQgaXMgdGhlIG9ubHkgdGhpbmcgdGhhdCB0cmlnZ2VycyBhIHJldm9jYXRpb24uXG5cbiAgICBObyB0d28ga2V5cyBtYXkgYWxsb3cgdGhlIHNhbWUgYWRkcmVzc2VzLCBiZWNhdXNlIHRoYXQgaXMgb25lIHBlcnNvbiBob2xkaW5nIHR3byBrZXlzOiByZXZva2luZ1xuICAgIG9uZSBvZiB0aGVtIGxlYXZlcyB0aGUgb3RoZXIgd29ya2luZywgc28gdGhlIHJldm9jYXRpb24gYWNoaWV2ZXMgbm90aGluZy4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kS2V5UHJvYmxlbXMoa2V5czogc3RyaW5nW10pIHtcbiAgICBsZXQgcHJvYmxlbXM6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IGJ5UmVzdHJpY3Rpb24gPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nW10+KCk7XG4gICAgZm9yIChsZXQga2V5IG9mIGtleXMpIHtcbiAgICAgICAgbGV0IHJlc3RyaWN0aW9uID0ga2V5UmVzdHJpY3Rpb25MaXN0KGtleSk7XG4gICAgICAgIGlmICghcmVzdHJpY3Rpb24pIHtcbiAgICAgICAgICAgIHByb2JsZW1zLnB1c2goYG5vIGZyb209IHJlc3RyaWN0aW9uLCBzbyBpdCBjYW4gYmUgdXNlZCBmcm9tIGFueXdoZXJlOlxcbiAgICAgICR7c3VtbWFyaXplS2V5KGtleSl9YCk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBTb3J0ZWQsIHNvIHRoZSBzYW1lIGFkZHJlc3NlcyB3cml0dGVuIGluIGEgZGlmZmVyZW50IG9yZGVyIHN0aWxsIGNvdW50IGFzIHRoZSBzYW1lLlxuICAgICAgICBsZXQgaWRlbnRpdHkgPSBbLi4ucmVzdHJpY3Rpb25dLnNvcnQoKS5qb2luKFwiLFwiKTtcbiAgICAgICAgYnlSZXN0cmljdGlvbi5zZXQoaWRlbnRpdHksIFsuLi4oYnlSZXN0cmljdGlvbi5nZXQoaWRlbnRpdHkpIHx8IFtdKSwga2V5XSk7XG4gICAgfVxuICAgIGZvciAobGV0IFtyZXN0cmljdGlvbiwgc2hhcmluZ10gb2YgYnlSZXN0cmljdGlvbikge1xuICAgICAgICBpZiAoc2hhcmluZy5sZW5ndGggPCAyKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICBwcm9ibGVtcy5wdXNoKFxuICAgICAgICAgICAgYCR7c2hhcmluZy5sZW5ndGh9IGtleXMgYWxsb3cgZXhhY3RseSB0aGUgc2FtZSBhZGRyZXNzZXMgKCR7cmVzdHJpY3Rpb259KSwgd2hpY2ggaXMgb25lYFxuICAgICAgICAgICAgKyBgIHBlcnNvbiBob2xkaW5nIG1vcmUgdGhhbiBvbmUga2V5OlxcbmBcbiAgICAgICAgICAgICsgc2hhcmluZy5tYXAoa2V5ID0+IGAgICAgICAke3N1bW1hcml6ZUtleShrZXkpfWApLmpvaW4oXCJcXG5cIilcbiAgICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHByb2JsZW1zO1xufVxuXG4vKiogUmVhZHMgdGhlIGF1dGhvcml6ZWQga2V5cyBhIHJlcG8gY2hlY2tvdXQgd2FudHMgYXBwbGllZC4gUHJlZmVycyBhIHRvcCBsZXZlbCBhdXRob3JpemVkX2tleXNcbiAgICBmaWxlIGFuZCBvdGhlcndpc2UgY29uY2F0ZW5hdGVzIGV2ZXJ5IC5wdWIgYXQgdGhlIHRvcCBsZXZlbC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkUmVwb0tleXMocmVwb1BhdGg6IHN0cmluZykge1xuICAgIGxldCBjb21iaW5lZFBhdGggPSBwYXRoLmpvaW4ocmVwb1BhdGgsIFwiYXV0aG9yaXplZF9rZXlzXCIpO1xuICAgIGxldCBlbnRyaWVzID0gYXdhaXQgZnMucmVhZGRpcihyZXBvUGF0aCk7XG4gICAgaWYgKGVudHJpZXMuaW5jbHVkZXMoXCJhdXRob3JpemVkX2tleXNcIikpIHtcbiAgICAgICAgcmV0dXJuIG5vcm1hbGl6ZUtleXMoYXdhaXQgZnMucmVhZEZpbGUoY29tYmluZWRQYXRoLCBcInV0ZjhcIikpO1xuICAgIH1cbiAgICBsZXQgcHViRmlsZXMgPSBlbnRyaWVzLmZpbHRlcihuYW1lID0+IG5hbWUuZW5kc1dpdGgoXCIucHViXCIpKS5zb3J0KCk7XG4gICAgaWYgKCFwdWJGaWxlcy5sZW5ndGgpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBhdXRob3JpemVkX2tleXMgb3IgYXQgbGVhc3Qgb25lIC5wdWIgZmlsZSBpbiAke3JlcG9QYXRofSwgZm91bmQgbmVpdGhlcmApO1xuICAgIH1cbiAgICBsZXQga2V5czogc3RyaW5nW10gPSBbXTtcbiAgICBmb3IgKGxldCBuYW1lIG9mIHB1YkZpbGVzKSB7XG4gICAgICAgIGtleXMucHVzaCguLi5ub3JtYWxpemVLZXlzKGF3YWl0IGZzLnJlYWRGaWxlKHBhdGguam9pbihyZXBvUGF0aCwgbmFtZSksIFwidXRmOFwiKSkpO1xuICAgIH1cbiAgICByZXR1cm4ga2V5cztcbn1cbiJdfQ==
111
- /* _JS_SOURCE_HASH = "a5147a2eb954468a9ddfcac36189a744f5b17f944d7e837ce0a525c780093a26"; */
144
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aG9yaXplZEtleXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJhdXRob3JpemVkS2V5cy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxvREFBNEI7QUFDNUIsMkRBQTZCO0FBQzdCLGdEQUF3QjtBQUV4QixTQUFnQixhQUFhLENBQUMsUUFBZ0I7SUFDMUMsT0FBTyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztBQUN2RyxDQUFDO0FBRkQsc0NBRUM7QUFFRDs4RUFDOEU7QUFDOUUsU0FBZ0IsY0FBYyxDQUFDLE9BQWU7SUFDMUMsSUFBSSxLQUFLLEdBQUcsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUN4QyxJQUFJLFNBQVMsR0FBRyxLQUFLLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDekUsSUFBSSxJQUFJLEdBQUcsU0FBUyxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsU0FBUyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN4RCxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDUixPQUFPLEVBQUUsQ0FBQztJQUNkLENBQUM7SUFDRCxPQUFPLFNBQVMsR0FBRyxnQkFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsT0FB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QUFFLENBQUM7UUFDdEMsT0FBTyxhQUFhLENBQUMsTUFBTSxrQkFBRSxDQUFDLFFBQVEsQ0FBQyxZQUFZLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNsRSxDQUFDO0lBQ0QsSUFBSSxRQUFRLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNwRSxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ25CLE1BQU0sSUFBSSxLQUFLLENBQUMseURBQXlELFFBQVEsaUJBQWlCLENBQUMsQ0FBQztJQUN4RyxDQUFDO0lBQ0QsSUFBSSxJQUFJLEdBQWEsRUFBRSxDQUFDO0lBQ3hCLEtBQUssSUFBSSxJQUFJLElBQUksUUFBUSxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLGFBQWEsQ0FBQyxNQUFNLGtCQUFFLENBQUMsUUFBUSxDQUFDLGNBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0RixDQUFDO0lBQ0QsT0FBTyxJQUFJLENBQUM7QUFDaEIsQ0FBQztBQWZELG9DQWVDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNyeXB0byBmcm9tIFwiY3J5cHRvXCI7XG5pbXBvcnQgZnMgZnJvbSBcImZzL3Byb21pc2VzXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplS2V5cyhjb250ZW50czogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGNvbnRlbnRzLnNwbGl0KFwiXFxuXCIpLm1hcChsaW5lID0+IGxpbmUudHJpbSgpKS5maWx0ZXIobGluZSA9PiBsaW5lICYmICFsaW5lLnN0YXJ0c1dpdGgoXCIjXCIpKTtcbn1cblxuLyoqIFRoZSBmaW5nZXJwcmludCBzc2ggaXRzZWxmIHJlcG9ydHMgZm9yIGEga2V5LCB3aGljaCBpcyB3aGF0IHRoZSBzc2hkIGxvZyBuYW1lcyBhbmQgdGhlcmVmb3JlXG4gICAgd2hhdCBhIHJldm9jYXRpb24gaXMga2V5ZWQgYnkuIFJldHVybnMgXCJcIiBmb3IgYSBsaW5lIHRoYXQgaG9sZHMgbm8ga2V5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtleUZpbmdlcnByaW50KGtleUxpbmU6IHN0cmluZykge1xuICAgIGxldCBwYXJ0cyA9IGtleUxpbmUudHJpbSgpLnNwbGl0KC9cXHMrLyk7XG4gICAgbGV0IHR5cGVJbmRleCA9IHBhcnRzLmZpbmRJbmRleChwYXJ0ID0+IC9eKHNzaC18ZWNkc2EtfHNrLSkvLnRlc3QocGFydCkpO1xuICAgIGxldCBibG9iID0gdHlwZUluZGV4ID49IDAgJiYgcGFydHNbdHlwZUluZGV4ICsgMV0gfHwgXCJcIjtcbiAgICBpZiAoIWJsb2IpIHtcbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxuICAgIHJldHVybiBcIlNIQTI1NjpcIiArIGNyeXB0by5jcmVhdGVIYXNoKFwic2hhMjU2XCIpLnVwZGF0ZShCdWZmZXIuZnJvbShibG9iLCBcImJhc2U2NFwiKSkuZGlnZXN0KFwiYmFzZTY0XCIpLnJlcGxhY2UoLz0rJC8sIFwiXCIpO1xufVxuXG5leHBvcnQgY29uc3QgTk9fUkVTVFJJQ1RJT04gPSBcIkFOWSBBRERSRVNTIChubyBmcm9tPSByZXN0cmljdGlvbilcIjtcblxuLyoqIFRoZSBhZGRyZXNzZXMgYSBrZXkgbWF5IGJlIHVzZWQgZnJvbSwgb25lIGJ5IG9uZSwgb3IgdW5kZWZpbmVkIHdoZW4gdGhlIGtleSBjYXJyaWVzIG5vIGZyb209XG4gICAgYXQgYWxsLiBVbmRlZmluZWQgYW5kIGFuIGVtcHR5IGxpc3QgYXJlIHZlcnkgZGlmZmVyZW50IHRoaW5ncywgc28gdGhleSBzdGF5IGRpc3Rpbmd1aXNoYWJsZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBrZXlSZXN0cmljdGlvbkxpc3Qoa2V5TGluZTogc3RyaW5nKSB7XG4gICAgbGV0IG1hdGNoID0ga2V5TGluZS5tYXRjaCgvZnJvbT1cIihbXlwiXSopXCIvKTtcbiAgICBpZiAoIW1hdGNoKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHJldHVybiBtYXRjaFsxXS5zcGxpdChcIixcIikubWFwKGVudHJ5ID0+IGVudHJ5LnRyaW0oKSkuZmlsdGVyKGVudHJ5ID0+IGVudHJ5KTtcbn1cblxuLyoqIFRoZSBhZGRyZXNzZXMgYSBrZXkgbWF5IGJlIHVzZWQgZnJvbSwgd2hpY2ggaXMgdGhlIHBhcnQgb2YgYW4gYXV0aG9yaXplZF9rZXlzIGxpbmUgdGhhdFxuICAgIGRlY2lkZXMgaG93IG11Y2ggYSBzdG9sZW4ga2V5IGlzIHdvcnRoLiBBIGtleSB3aXRoIG5vIHJlc3RyaWN0aW9uIHNheXMgc28gbG91ZGx5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGtleVJlc3RyaWN0aW9uKGtleUxpbmU6IHN0cmluZykge1xuICAgIGxldCBsaXN0ID0ga2V5UmVzdHJpY3Rpb25MaXN0KGtleUxpbmUpO1xuICAgIGlmICghbGlzdCkge1xuICAgICAgICByZXR1cm4gTk9fUkVTVFJJQ1RJT047XG4gICAgfVxuICAgIHJldHVybiBsaXN0LmpvaW4oXCIsXCIpO1xufVxuXG4vKiogQWRkcyBhZGRyZXNzZXMgdG8gYSBrZXkncyBmcm9tPSBsaXN0LCBsZWF2aW5nIHRoZSByZXN0IG9mIHRoZSBsaW5lIGV4YWN0bHkgYXMgaXQgd2FzLiBSZXR1cm5zXG4gICAgd2hpY2ggYWRkcmVzc2VzIHdlcmUgYWN0dWFsbHkgbmV3LCBzbyBhIGNhbGxlciBjYW4gcmVwb3J0IG9ubHkgd2hhdCBpdCBjaGFuZ2VkLlxuXG4gICAgQSBrZXkgd2l0aCBubyBmcm9tPSBhdCBhbGwgaXMgbGVmdCBhbG9uZTogYWRkaW5nIG9uZSB3b3VsZCBzaWxlbnRseSByZXN0cmljdCBhIGtleSB0aGF0IGlzXG4gICAgY3VycmVudGx5IHVucmVzdHJpY3RlZCwgd2hpY2ggaXMgYSBkaWZmZXJlbnQgZGVjaXNpb24gdGhhbiB0aGUgb25lIGJlaW5nIG1hZGUgaGVyZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhbGxvd0FkZHJlc3NlcyhrZXlMaW5lOiBzdHJpbmcsIGFkZHJlc3Nlczogc3RyaW5nW10pIHtcbiAgICBsZXQgbGlzdCA9IGtleVJlc3RyaWN0aW9uTGlzdChrZXlMaW5lKTtcbiAgICBpZiAoIWxpc3QpIHtcbiAgICAgICAgcmV0dXJuIHsga2V5TGluZSwgYWRkZWQ6IFtdIGFzIHN0cmluZ1tdIH07XG4gICAgfVxuICAgIGxldCBhbGxvd2VkID0gbGlzdDtcbiAgICBsZXQgYWRkZWQgPSBhZGRyZXNzZXMuZmlsdGVyKGFkZHJlc3MgPT4gYWRkcmVzcyAmJiAhYWxsb3dlZC5pbmNsdWRlcyhhZGRyZXNzKSk7XG4gICAgaWYgKCFhZGRlZC5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIHsga2V5TGluZSwgYWRkZWQgfTtcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgICAga2V5TGluZToga2V5TGluZS5yZXBsYWNlKC9mcm9tPVwiW15cIl0qXCIvLCBgZnJvbT1cIiR7Wy4uLmFsbG93ZWQsIC4uLmFkZGVkXS5qb2luKFwiLFwiKX1cImApLFxuICAgICAgICBhZGRlZCxcbiAgICB9O1xufVxuXG4vKiogRW5vdWdoIHRvIHJlY29nbmlzZSB3aG9zZSBrZXkgdGhpcyBpcyB3aXRob3V0IHByaW50aW5nIHRoZSB3aG9sZSBibG9iLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1bW1hcml6ZUtleShrZXlMaW5lOiBzdHJpbmcpIHtcbiAgICBsZXQgcGFydHMgPSBrZXlMaW5lLnRyaW0oKS5zcGxpdCgvXFxzKy8pO1xuICAgIGxldCB0eXBlSW5kZXggPSBwYXJ0cy5maW5kSW5kZXgocGFydCA9PiAvXihzc2gtfGVjZHNhLXxzay0pLy50ZXN0KHBhcnQpKTtcbiAgICBpZiAodHlwZUluZGV4IDwgMCkge1xuICAgICAgICByZXR1cm4ga2V5TGluZS5zbGljZSgwLCA2MCk7XG4gICAgfVxuICAgIGxldCB0eXBlID0gcGFydHNbdHlwZUluZGV4XTtcbiAgICBsZXQgYmxvYiA9IHBhcnRzW3R5cGVJbmRleCArIDFdIHx8IFwiXCI7XG4gICAgbGV0IGNvbW1lbnQgPSBwYXJ0cy5zbGljZSh0eXBlSW5kZXggKyAyKS5qb2luKFwiIFwiKTtcbiAgICByZXR1cm4gYCR7dHlwZX0gLi4uJHtibG9iLnNsaWNlKC0xMil9JHtjb21tZW50ICYmIGAgJHtjb21tZW50fWAgfHwgXCJcIn1gO1xufVxuXG4vKiogVGhlIHNob3J0ZXN0IHRoaW5nIHRoYXQgc3RpbGwgaWRlbnRpZmllcyBhIGtleSB0byBhIHBlcnNvbjogdGhlIGNvbW1lbnQgaXQgY2Fycmllcywgd2hpY2ggaXNcbiAgICB1c3VhbGx5IHVzZXJAbWFjaGluZSwgYW5kIG90aGVyd2lzZSB0aGUgdGFpbCBvZiB0aGUga2V5IGl0c2VsZi4gRm9yIHRoZSBmaXJzdCBsaW5lIG9mIGFcbiAgICBub3RpZmljYXRpb24sIHdoZXJlIHRoZXJlIGlzIG9ubHkgcm9vbSBmb3IgdGhlIG9uZSB0aGluZyB0aGF0IG1hdHRlcnMuICovXG5leHBvcnQgZnVuY3Rpb24ga2V5TmljZU5hbWUoa2V5TGluZTogc3RyaW5nKSB7XG4gICAgbGV0IHBhcnRzID0ga2V5TGluZS50cmltKCkuc3BsaXQoL1xccysvKTtcbiAgICBsZXQgdHlwZUluZGV4ID0gcGFydHMuZmluZEluZGV4KHBhcnQgPT4gL14oc3NoLXxlY2RzYS18c2stKS8udGVzdChwYXJ0KSk7XG4gICAgaWYgKHR5cGVJbmRleCA8IDApIHtcbiAgICAgICAgcmV0dXJuIGtleUxpbmUuc2xpY2UoMCwgMjApO1xuICAgIH1cbiAgICBsZXQgY29tbWVudCA9IHBhcnRzLnNsaWNlKHR5cGVJbmRleCArIDIpLmpvaW4oXCIgXCIpO1xuICAgIHJldHVybiBjb21tZW50IHx8IGAuLi4keyhwYXJ0c1t0eXBlSW5kZXggKyAxXSB8fCBcIlwiKS5zbGljZSgtOCl9YDtcbn1cblxuLyoqIFdoYXQgYSBzZXQgb2Yga2V5cyBoYXMgdG8gc2F0aXNmeSBiZWZvcmUgaXQgaXMgd29ydGggc2lnbmluZywgYXMgYSBsaXN0IG9mIGNvbXBsYWludHMuXG5cbiAgICBFdmVyeSBrZXkgbmVlZHMgYSBmcm9tPSwgYmVjYXVzZSBhbiB1bnJlc3RyaWN0ZWQga2V5IGNhbiBuZXZlciBiZSBjYXVnaHQgYmVpbmcgdXNlZCBmcm9tIHRoZVxuICAgIHdyb25nIHBsYWNlLCBhbmQgYmVpbmcgY2F1Z2h0IGlzIHRoZSBvbmx5IHRoaW5nIHRoYXQgdHJpZ2dlcnMgYSByZXZvY2F0aW9uLlxuXG4gICAgTm8gdHdvIGtleXMgbWF5IGFsbG93IHRoZSBzYW1lIGFkZHJlc3NlcywgYmVjYXVzZSB0aGF0IGlzIG9uZSBwZXJzb24gaG9sZGluZyB0d28ga2V5czogcmV2b2tpbmdcbiAgICBvbmUgb2YgdGhlbSBsZWF2ZXMgdGhlIG90aGVyIHdvcmtpbmcsIHNvIHRoZSByZXZvY2F0aW9uIGFjaGlldmVzIG5vdGhpbmcuICovXG5leHBvcnQgZnVuY3Rpb24gZmluZEtleVByb2JsZW1zKGtleXM6IHN0cmluZ1tdKSB7XG4gICAgbGV0IHByb2JsZW1zOiBzdHJpbmdbXSA9IFtdO1xuICAgIGxldCBieVJlc3RyaWN0aW9uID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZ1tdPigpO1xuICAgIGZvciAobGV0IGtleSBvZiBrZXlzKSB7XG4gICAgICAgIGxldCByZXN0cmljdGlvbiA9IGtleVJlc3RyaWN0aW9uTGlzdChrZXkpO1xuICAgICAgICBpZiAoIXJlc3RyaWN0aW9uKSB7XG4gICAgICAgICAgICBwcm9ibGVtcy5wdXNoKGBubyBmcm9tPSByZXN0cmljdGlvbiwgc28gaXQgY2FuIGJlIHVzZWQgZnJvbSBhbnl3aGVyZTpcXG4gICAgICAke3N1bW1hcml6ZUtleShrZXkpfWApO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8gU29ydGVkLCBzbyB0aGUgc2FtZSBhZGRyZXNzZXMgd3JpdHRlbiBpbiBhIGRpZmZlcmVudCBvcmRlciBzdGlsbCBjb3VudCBhcyB0aGUgc2FtZS5cbiAgICAgICAgbGV0IGlkZW50aXR5ID0gWy4uLnJlc3RyaWN0aW9uXS5zb3J0KCkuam9pbihcIixcIik7XG4gICAgICAgIGJ5UmVzdHJpY3Rpb24uc2V0KGlkZW50aXR5LCBbLi4uKGJ5UmVzdHJpY3Rpb24uZ2V0KGlkZW50aXR5KSB8fCBbXSksIGtleV0pO1xuICAgIH1cbiAgICBmb3IgKGxldCBbcmVzdHJpY3Rpb24sIHNoYXJpbmddIG9mIGJ5UmVzdHJpY3Rpb24pIHtcbiAgICAgICAgaWYgKHNoYXJpbmcubGVuZ3RoIDwgMikge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgcHJvYmxlbXMucHVzaChcbiAgICAgICAgICAgIGAke3NoYXJpbmcubGVuZ3RofSBrZXlzIGFsbG93IGV4YWN0bHkgdGhlIHNhbWUgYWRkcmVzc2VzICgke3Jlc3RyaWN0aW9ufSksIHdoaWNoIGlzIG9uZWBcbiAgICAgICAgICAgICsgYCBwZXJzb24gaG9sZGluZyBtb3JlIHRoYW4gb25lIGtleTpcXG5gXG4gICAgICAgICAgICArIHNoYXJpbmcubWFwKGtleSA9PiBgICAgICAgJHtzdW1tYXJpemVLZXkoa2V5KX1gKS5qb2luKFwiXFxuXCIpXG4gICAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiBwcm9ibGVtcztcbn1cblxuLyoqIFJlYWRzIHRoZSBhdXRob3JpemVkIGtleXMgYSByZXBvIGNoZWNrb3V0IHdhbnRzIGFwcGxpZWQuIFByZWZlcnMgYSB0b3AgbGV2ZWwgYXV0aG9yaXplZF9rZXlzXG4gICAgZmlsZSBhbmQgb3RoZXJ3aXNlIGNvbmNhdGVuYXRlcyBldmVyeSAucHViIGF0IHRoZSB0b3AgbGV2ZWwuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZFJlcG9LZXlzKHJlcG9QYXRoOiBzdHJpbmcpIHtcbiAgICBsZXQgY29tYmluZWRQYXRoID0gcGF0aC5qb2luKHJlcG9QYXRoLCBcImF1dGhvcml6ZWRfa2V5c1wiKTtcbiAgICBsZXQgZW50cmllcyA9IGF3YWl0IGZzLnJlYWRkaXIocmVwb1BhdGgpO1xuICAgIGlmIChlbnRyaWVzLmluY2x1ZGVzKFwiYXV0aG9yaXplZF9rZXlzXCIpKSB7XG4gICAgICAgIHJldHVybiBub3JtYWxpemVLZXlzKGF3YWl0IGZzLnJlYWRGaWxlKGNvbWJpbmVkUGF0aCwgXCJ1dGY4XCIpKTtcbiAgICB9XG4gICAgbGV0IHB1YkZpbGVzID0gZW50cmllcy5maWx0ZXIobmFtZSA9PiBuYW1lLmVuZHNXaXRoKFwiLnB1YlwiKSkuc29ydCgpO1xuICAgIGlmICghcHViRmlsZXMubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgYXV0aG9yaXplZF9rZXlzIG9yIGF0IGxlYXN0IG9uZSAucHViIGZpbGUgaW4gJHtyZXBvUGF0aH0sIGZvdW5kIG5laXRoZXJgKTtcbiAgICB9XG4gICAgbGV0IGtleXM6IHN0cmluZ1tdID0gW107XG4gICAgZm9yIChsZXQgbmFtZSBvZiBwdWJGaWxlcykge1xuICAgICAgICBrZXlzLnB1c2goLi4ubm9ybWFsaXplS2V5cyhhd2FpdCBmcy5yZWFkRmlsZShwYXRoLmpvaW4ocmVwb1BhdGgsIG5hbWUpLCBcInV0ZjhcIikpKTtcbiAgICB9XG4gICAgcmV0dXJuIGtleXM7XG59XG4iXX0=
145
+ /* _JS_SOURCE_HASH = "5dc60c0f88ff3878003bf57017d1342326afa7c6a9f511d5896e4113565a7823"; */
@@ -1,8 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
3
- //exports.deriveRevokeKey = exports.revokeRepoPath = exports.revokeKeyPath = exports.revokeRepoURL = exports.REVOKE_KEY_LABEL = void 0;
6
+ //exports.deriveRevokeKey = exports.revokeRepoPath = exports.findRevokeKey = exports.legacyRevokeKeyPath = exports.revokeKeyPath = exports.revokeRepoURL = exports.REVOKE_KEY_LABEL = void 0;
4
7
  const deriveKey_1 = require("../keys/deriveKey");
5
8
  const sshKeyFile_1 = require("../keys/sshKeyFile");
9
+ const path_1 = __importDefault(require("path"));
6
10
  const sources_1 = require("./sources");
7
11
  // A source's revocations live in a repo beside it. Derived rather than configured, so adding a
8
12
  // source brings its revoke repo with it and there is nothing extra to pass on the command line.
@@ -16,9 +20,18 @@ function revokeRepoURL(sourceURL) {
16
20
  }
17
21
  exports.revokeRepoURL = revokeRepoURL;
18
22
  function revokeKeyPath(sourceURL) {
19
- return `${sources_1.REPO_KEYS_DIR}/${(0, sources_1.sourceName)(sourceURL)}${REVOKED_SUFFIX}`;
23
+ return path_1.default.join((0, sources_1.keysDir)(), `${(0, sources_1.sourceName)(sourceURL)}${REVOKED_SUFFIX}`);
20
24
  }
21
25
  exports.revokeKeyPath = revokeKeyPath;
26
+ function legacyRevokeKeyPath(sourceURL) {
27
+ return `${sources_1.LEGACY_REPO_KEYS_DIR}/${(0, sources_1.sourceName)(sourceURL)}${REVOKED_SUFFIX}`;
28
+ }
29
+ exports.legacyRevokeKeyPath = legacyRevokeKeyPath;
30
+ /** Wherever this source's revoke key already is, or nothing if it has not been derived yet. */
31
+ async function findRevokeKey(sourceURL) {
32
+ return await (0, sources_1.findKey)({ current: revokeKeyPath(sourceURL), legacy: legacyRevokeKeyPath(sourceURL) });
33
+ }
34
+ exports.findRevokeKey = findRevokeKey;
22
35
  function revokeRepoPath(sourceURL) {
23
36
  return `${sources_1.REPOS_DIR}/${(0, sources_1.sourceName)(sourceURL)}${REVOKED_SUFFIX}`;
24
37
  }
@@ -40,5 +53,5 @@ function deriveRevokeKey(sourcePrivateKey) {
40
53
  };
41
54
  }
42
55
  exports.deriveRevokeKey = deriveRevokeKey;
43
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV2b2tlU291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmV2b2tlU291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLGlEQUFxRDtBQUNyRCxtREFBcUY7QUFDckYsdUNBQWlFO0FBRWpFLCtGQUErRjtBQUMvRixnR0FBZ0c7QUFDaEcsTUFBTSxjQUFjLEdBQUcsVUFBVSxDQUFDO0FBQ2xDLCtGQUErRjtBQUMvRixrRUFBa0U7QUFDckQsUUFBQSxnQkFBZ0IsR0FBRyxpQkFBaUIsQ0FBQztBQUVsRCxTQUFnQixhQUFhLENBQUMsU0FBaUI7SUFDM0MsSUFBSSxVQUFVLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDakQsT0FBTyxHQUFHLFVBQVUsR0FBRyxjQUFjLE1BQU0sQ0FBQztBQUNoRCxDQUFDO0FBSEQsc0NBR0M7QUFFRCxTQUFnQixhQUFhLENBQUMsU0FBaUI7SUFDM0MsT0FBTyxHQUFHLHVCQUFhLElBQUksSUFBQSxvQkFBVSxFQUFDLFNBQVMsQ0FBQyxHQUFHLGNBQWMsRUFBRSxDQUFDO0FBQ3hFLENBQUM7QUFGRCxzQ0FFQztBQUVELFNBQWdCLGNBQWMsQ0FBQyxTQUFpQjtJQUM1QyxPQUFPLEdBQUcsbUJBQVMsSUFBSSxJQUFBLG9CQUFVLEVBQUMsU0FBUyxDQUFDLEdBQUcsY0FBYyxFQUFFLENBQUM7QUFDcEUsQ0FBQztBQUZELHdDQUVDO0FBRUQ7eUZBQ3lGO0FBQ3pGLFNBQWdCLGVBQWUsQ0FBQyxnQkFBd0I7SUFDcEQsSUFBSSxNQUFNLEdBQUcsSUFBQSxtQ0FBc0IsRUFBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3RELElBQUksT0FBTyxHQUFHLElBQUEsNEJBQWdCLEVBQUMsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLEVBQUUsd0JBQWdCLEVBQUUsQ0FBQyxDQUFDO0lBQy9FLE9BQU87UUFDSCxTQUFTLEVBQUUsZUFBZSxNQUFNLENBQUMsTUFBTSxDQUFDO1lBQ3BDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO1lBQ3RELE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxTQUFTO1NBQ2hELENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUU7UUFDdkIsY0FBYyxFQUFFLElBQUEsb0NBQXVCLEVBQUM7WUFDcEMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxJQUFJO1lBQ2xCLE9BQU8sRUFBRSxHQUFHLE1BQU0sQ0FBQyxPQUFPLElBQUksWUFBWSxJQUFJLHdCQUFnQixFQUFFO1NBQ25FLENBQUM7S0FDTCxDQUFDO0FBQ04sQ0FBQztBQWJELDBDQWFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZGVyaXZlRWQyNTUxOUtleSB9IGZyb20gXCIuLi9rZXlzL2Rlcml2ZUtleVwiO1xuaW1wb3J0IHsgZm9ybWF0T3BlblNTSFByaXZhdGVLZXksIHBhcnNlT3BlblNTSFByaXZhdGVLZXkgfSBmcm9tIFwiLi4va2V5cy9zc2hLZXlGaWxlXCI7XG5pbXBvcnQgeyBSRVBPX0tFWVNfRElSLCBSRVBPU19ESVIsIHNvdXJjZU5hbWUgfSBmcm9tIFwiLi9zb3VyY2VzXCI7XG5cbi8vIEEgc291cmNlJ3MgcmV2b2NhdGlvbnMgbGl2ZSBpbiBhIHJlcG8gYmVzaWRlIGl0LiBEZXJpdmVkIHJhdGhlciB0aGFuIGNvbmZpZ3VyZWQsIHNvIGFkZGluZyBhXG4vLyBzb3VyY2UgYnJpbmdzIGl0cyByZXZva2UgcmVwbyB3aXRoIGl0IGFuZCB0aGVyZSBpcyBub3RoaW5nIGV4dHJhIHRvIHBhc3Mgb24gdGhlIGNvbW1hbmQgbGluZS5cbmNvbnN0IFJFVk9LRURfU1VGRklYID0gXCJfcmV2b2tlZFwiO1xuLy8gR2l0SHViIHdpbGwgbm90IHRha2UgdGhlIHNhbWUgcHVibGljIGtleSBhcyBhIGRlcGxveSBrZXkgb24gdHdvIHJlcG9zLCBzbyB0aGUgcmV2b2tlIHJlcG8gaXNcbi8vIHJlYWNoZWQgd2l0aCBhIGtleSBkZXJpdmVkIGZyb20gdGhlIHNvdXJjZSdzLCB1bmRlciB0aGlzIGxhYmVsLlxuZXhwb3J0IGNvbnN0IFJFVk9LRV9LRVlfTEFCRUwgPSBcInJldm9rZWdpdGh1YmtleVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmV2b2tlUmVwb1VSTChzb3VyY2VVUkw6IHN0cmluZykge1xuICAgIGxldCB3aXRob3V0R2l0ID0gc291cmNlVVJMLnJlcGxhY2UoL1xcLmdpdCQvLCBcIlwiKTtcbiAgICByZXR1cm4gYCR7d2l0aG91dEdpdH0ke1JFVk9LRURfU1VGRklYfS5naXRgO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmV2b2tlS2V5UGF0aChzb3VyY2VVUkw6IHN0cmluZykge1xuICAgIHJldHVybiBgJHtSRVBPX0tFWVNfRElSfS8ke3NvdXJjZU5hbWUoc291cmNlVVJMKX0ke1JFVk9LRURfU1VGRklYfWA7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXZva2VSZXBvUGF0aChzb3VyY2VVUkw6IHN0cmluZykge1xuICAgIHJldHVybiBgJHtSRVBPU19ESVJ9LyR7c291cmNlTmFtZShzb3VyY2VVUkwpfSR7UkVWT0tFRF9TVUZGSVh9YDtcbn1cblxuLyoqIFRoZSByZXZva2UgcmVwbydzIGtleSwgd29ya2VkIG91dCBmcm9tIHRoZSBzb3VyY2UgcmVwbydzIGtleS4gQW55dGhpbmcgaG9sZGluZyB0aGUgc291cmNlIGtleVxuICAgIGNhbiBwcm9kdWNlIGl0LCBzbyBpdCBuZXZlciBoYXMgdG8gYmUgc3RvcmVkIGFueXdoZXJlIHNlcGFyYXRlbHkgb3IgaGFuZGVkIGFyb3VuZC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZXJpdmVSZXZva2VLZXkoc291cmNlUHJpdmF0ZUtleTogc3RyaW5nKSB7XG4gICAgbGV0IHNvdXJjZSA9IHBhcnNlT3BlblNTSFByaXZhdGVLZXkoc291cmNlUHJpdmF0ZUtleSk7XG4gICAgbGV0IGRlcml2ZWQgPSBkZXJpdmVFZDI1NTE5S2V5KHsgc2VlZDogc291cmNlLnNlZWQsIGxhYmVsOiBSRVZPS0VfS0VZX0xBQkVMIH0pO1xuICAgIHJldHVybiB7XG4gICAgICAgIHB1YmxpY0tleTogYHNzaC1lZDI1NTE5ICR7QnVmZmVyLmNvbmNhdChbXG4gICAgICAgICAgICBCdWZmZXIuZnJvbShbMCwgMCwgMCwgMTFdKSwgQnVmZmVyLmZyb20oXCJzc2gtZWQyNTUxOVwiKSxcbiAgICAgICAgICAgIEJ1ZmZlci5mcm9tKFswLCAwLCAwLCAzMl0pLCBkZXJpdmVkLnB1YmxpY0tleSxcbiAgICAgICAgXSkudG9TdHJpbmcoXCJiYXNlNjRcIil9YCxcbiAgICAgICAgcHJpdmF0ZUtleUZpbGU6IGZvcm1hdE9wZW5TU0hQcml2YXRlS2V5KHtcbiAgICAgICAgICAgIHNlZWQ6IGRlcml2ZWQuc2VlZCxcbiAgICAgICAgICAgIGNvbW1lbnQ6IGAke3NvdXJjZS5jb21tZW50IHx8IFwicG9ydHNlY3VyZVwifSAke1JFVk9LRV9LRVlfTEFCRUx9YCxcbiAgICAgICAgfSksXG4gICAgfTtcbn1cbiJdfQ==
44
- /* _JS_SOURCE_HASH = "9f16cd6aea6e1f1a646eda715ac4cac70dc67579ce23c1e473bd371b7985b229"; */
56
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmV2b2tlU291cmNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmV2b2tlU291cmNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGlEQUFxRDtBQUNyRCxtREFBcUY7QUFDckYsZ0RBQXdCO0FBQ3hCLHVDQUEwRjtBQUUxRiwrRkFBK0Y7QUFDL0YsZ0dBQWdHO0FBQ2hHLE1BQU0sY0FBYyxHQUFHLFVBQVUsQ0FBQztBQUNsQywrRkFBK0Y7QUFDL0Ysa0VBQWtFO0FBQ3JELFFBQUEsZ0JBQWdCLEdBQUcsaUJBQWlCLENBQUM7QUFFbEQsU0FBZ0IsYUFBYSxDQUFDLFNBQWlCO0lBQzNDLElBQUksVUFBVSxHQUFHLFNBQVMsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO0lBQ2pELE9BQU8sR0FBRyxVQUFVLEdBQUcsY0FBYyxNQUFNLENBQUM7QUFDaEQsQ0FBQztBQUhELHNDQUdDO0FBRUQsU0FBZ0IsYUFBYSxDQUFDLFNBQWlCO0lBQzNDLE9BQU8sY0FBSSxDQUFDLElBQUksQ0FBQyxJQUFBLGlCQUFPLEdBQUUsRUFBRSxHQUFHLElBQUEsb0JBQVUsRUFBQyxTQUFTLENBQUMsR0FBRyxjQUFjLEVBQUUsQ0FBQyxDQUFDO0FBQzdFLENBQUM7QUFGRCxzQ0FFQztBQUVELFNBQWdCLG1CQUFtQixDQUFDLFNBQWlCO0lBQ2pELE9BQU8sR0FBRyw4QkFBb0IsSUFBSSxJQUFBLG9CQUFVLEVBQUMsU0FBUyxDQUFDLEdBQUcsY0FBYyxFQUFFLENBQUM7QUFDL0UsQ0FBQztBQUZELGtEQUVDO0FBRUQsK0ZBQStGO0FBQ3hGLEtBQUssVUFBVSxhQUFhLENBQUMsU0FBaUI7SUFDakQsT0FBTyxNQUFNLElBQUEsaUJBQU8sRUFBQyxFQUFFLE9BQU8sRUFBRSxhQUFhLENBQUMsU0FBUyxDQUFDLEVBQUUsTUFBTSxFQUFFLG1CQUFtQixDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUN4RyxDQUFDO0FBRkQsc0NBRUM7QUFFRCxTQUFnQixjQUFjLENBQUMsU0FBaUI7SUFDNUMsT0FBTyxHQUFHLG1CQUFTLElBQUksSUFBQSxvQkFBVSxFQUFDLFNBQVMsQ0FBQyxHQUFHLGNBQWMsRUFBRSxDQUFDO0FBQ3BFLENBQUM7QUFGRCx3Q0FFQztBQUVEO3lGQUN5RjtBQUN6RixTQUFnQixlQUFlLENBQUMsZ0JBQXdCO0lBQ3BELElBQUksTUFBTSxHQUFHLElBQUEsbUNBQXNCLEVBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUN0RCxJQUFJLE9BQU8sR0FBRyxJQUFBLDRCQUFnQixFQUFDLEVBQUUsSUFBSSxFQUFFLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxFQUFFLHdCQUFnQixFQUFFLENBQUMsQ0FBQztJQUMvRSxPQUFPO1FBQ0gsU0FBUyxFQUFFLGVBQWUsTUFBTSxDQUFDLE1BQU0sQ0FBQztZQUNwQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQztZQUN0RCxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsU0FBUztTQUNoRCxDQUFDLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFO1FBQ3ZCLGNBQWMsRUFBRSxJQUFBLG9DQUF1QixFQUFDO1lBQ3BDLElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixPQUFPLEVBQUUsR0FBRyxNQUFNLENBQUMsT0FBTyxJQUFJLFlBQVksSUFBSSx3QkFBZ0IsRUFBRTtTQUNuRSxDQUFDO0tBQ0wsQ0FBQztBQUNOLENBQUM7QUFiRCwwQ0FhQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRlcml2ZUVkMjU1MTlLZXkgfSBmcm9tIFwiLi4va2V5cy9kZXJpdmVLZXlcIjtcbmltcG9ydCB7IGZvcm1hdE9wZW5TU0hQcml2YXRlS2V5LCBwYXJzZU9wZW5TU0hQcml2YXRlS2V5IH0gZnJvbSBcIi4uL2tleXMvc3NoS2V5RmlsZVwiO1xuaW1wb3J0IHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGZpbmRLZXksIGtleXNEaXIsIExFR0FDWV9SRVBPX0tFWVNfRElSLCBSRVBPU19ESVIsIHNvdXJjZU5hbWUgfSBmcm9tIFwiLi9zb3VyY2VzXCI7XG5cbi8vIEEgc291cmNlJ3MgcmV2b2NhdGlvbnMgbGl2ZSBpbiBhIHJlcG8gYmVzaWRlIGl0LiBEZXJpdmVkIHJhdGhlciB0aGFuIGNvbmZpZ3VyZWQsIHNvIGFkZGluZyBhXG4vLyBzb3VyY2UgYnJpbmdzIGl0cyByZXZva2UgcmVwbyB3aXRoIGl0IGFuZCB0aGVyZSBpcyBub3RoaW5nIGV4dHJhIHRvIHBhc3Mgb24gdGhlIGNvbW1hbmQgbGluZS5cbmNvbnN0IFJFVk9LRURfU1VGRklYID0gXCJfcmV2b2tlZFwiO1xuLy8gR2l0SHViIHdpbGwgbm90IHRha2UgdGhlIHNhbWUgcHVibGljIGtleSBhcyBhIGRlcGxveSBrZXkgb24gdHdvIHJlcG9zLCBzbyB0aGUgcmV2b2tlIHJlcG8gaXNcbi8vIHJlYWNoZWQgd2l0aCBhIGtleSBkZXJpdmVkIGZyb20gdGhlIHNvdXJjZSdzLCB1bmRlciB0aGlzIGxhYmVsLlxuZXhwb3J0IGNvbnN0IFJFVk9LRV9LRVlfTEFCRUwgPSBcInJldm9rZWdpdGh1YmtleVwiO1xuXG5leHBvcnQgZnVuY3Rpb24gcmV2b2tlUmVwb1VSTChzb3VyY2VVUkw6IHN0cmluZykge1xuICAgIGxldCB3aXRob3V0R2l0ID0gc291cmNlVVJMLnJlcGxhY2UoL1xcLmdpdCQvLCBcIlwiKTtcbiAgICByZXR1cm4gYCR7d2l0aG91dEdpdH0ke1JFVk9LRURfU1VGRklYfS5naXRgO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmV2b2tlS2V5UGF0aChzb3VyY2VVUkw6IHN0cmluZykge1xuICAgIHJldHVybiBwYXRoLmpvaW4oa2V5c0RpcigpLCBgJHtzb3VyY2VOYW1lKHNvdXJjZVVSTCl9JHtSRVZPS0VEX1NVRkZJWH1gKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGxlZ2FjeVJldm9rZUtleVBhdGgoc291cmNlVVJMOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYCR7TEVHQUNZX1JFUE9fS0VZU19ESVJ9LyR7c291cmNlTmFtZShzb3VyY2VVUkwpfSR7UkVWT0tFRF9TVUZGSVh9YDtcbn1cblxuLyoqIFdoZXJldmVyIHRoaXMgc291cmNlJ3MgcmV2b2tlIGtleSBhbHJlYWR5IGlzLCBvciBub3RoaW5nIGlmIGl0IGhhcyBub3QgYmVlbiBkZXJpdmVkIHlldC4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmaW5kUmV2b2tlS2V5KHNvdXJjZVVSTDogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGF3YWl0IGZpbmRLZXkoeyBjdXJyZW50OiByZXZva2VLZXlQYXRoKHNvdXJjZVVSTCksIGxlZ2FjeTogbGVnYWN5UmV2b2tlS2V5UGF0aChzb3VyY2VVUkwpIH0pO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmV2b2tlUmVwb1BhdGgoc291cmNlVVJMOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYCR7UkVQT1NfRElSfS8ke3NvdXJjZU5hbWUoc291cmNlVVJMKX0ke1JFVk9LRURfU1VGRklYfWA7XG59XG5cbi8qKiBUaGUgcmV2b2tlIHJlcG8ncyBrZXksIHdvcmtlZCBvdXQgZnJvbSB0aGUgc291cmNlIHJlcG8ncyBrZXkuIEFueXRoaW5nIGhvbGRpbmcgdGhlIHNvdXJjZSBrZXlcbiAgICBjYW4gcHJvZHVjZSBpdCwgc28gaXQgbmV2ZXIgaGFzIHRvIGJlIHN0b3JlZCBhbnl3aGVyZSBzZXBhcmF0ZWx5IG9yIGhhbmRlZCBhcm91bmQuICovXG5leHBvcnQgZnVuY3Rpb24gZGVyaXZlUmV2b2tlS2V5KHNvdXJjZVByaXZhdGVLZXk6IHN0cmluZykge1xuICAgIGxldCBzb3VyY2UgPSBwYXJzZU9wZW5TU0hQcml2YXRlS2V5KHNvdXJjZVByaXZhdGVLZXkpO1xuICAgIGxldCBkZXJpdmVkID0gZGVyaXZlRWQyNTUxOUtleSh7IHNlZWQ6IHNvdXJjZS5zZWVkLCBsYWJlbDogUkVWT0tFX0tFWV9MQUJFTCB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgICBwdWJsaWNLZXk6IGBzc2gtZWQyNTUxOSAke0J1ZmZlci5jb25jYXQoW1xuICAgICAgICAgICAgQnVmZmVyLmZyb20oWzAsIDAsIDAsIDExXSksIEJ1ZmZlci5mcm9tKFwic3NoLWVkMjU1MTlcIiksXG4gICAgICAgICAgICBCdWZmZXIuZnJvbShbMCwgMCwgMCwgMzJdKSwgZGVyaXZlZC5wdWJsaWNLZXksXG4gICAgICAgIF0pLnRvU3RyaW5nKFwiYmFzZTY0XCIpfWAsXG4gICAgICAgIHByaXZhdGVLZXlGaWxlOiBmb3JtYXRPcGVuU1NIUHJpdmF0ZUtleSh7XG4gICAgICAgICAgICBzZWVkOiBkZXJpdmVkLnNlZWQsXG4gICAgICAgICAgICBjb21tZW50OiBgJHtzb3VyY2UuY29tbWVudCB8fCBcInBvcnRzZWN1cmVcIn0gJHtSRVZPS0VfS0VZX0xBQkVMfWAsXG4gICAgICAgIH0pLFxuICAgIH07XG59XG4iXX0=
57
+ /* _JS_SOURCE_HASH = "fa19b1fd43388ad835ac95f96f64acb37f8ebbc316741e6c48fc273ac174e1e7"; */
@@ -1,11 +1,25 @@
1
1
  "use strict";
2
- // PORTED CODE: security/authorizedKeys/daemon/portsecureDaemon.js contains a plain JS port of everything here, so it can
3
- // resolve the same locations with no dependencies. Both sides must derive identical paths from a
4
- // repo url - if you change one, make the matching change in the other.
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule && mod.default) ? mod : { "default": mod };
4
+ };
5
5
  Object.defineProperty(exports, "__esModule", { value: true , configurable: true});
6
- //exports.sourceRepoPath = exports.sourceKeyPath = exports.sourceName = exports.REPOS_DIR = exports.REPO_KEYS_DIR = void 0;
7
- exports.REPO_KEYS_DIR = "/etc/portsecure/repo-keys";
6
+ //exports.findSourceKey = exports.findKey = exports.sourceRepoPath = exports.legacySourceKeyPath = exports.sourceKeyPath = exports.sourceName = exports.keysDir = exports.REPOS_DIR = exports.LEGACY_REPO_KEYS_DIR = exports.KEYS_DIR_NAME = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const os_1 = __importDefault(require("os"));
9
+ const path_1 = __importDefault(require("path"));
10
+ // PORTED CODE: nothing here is duplicated any more, the daemon imports it directly. Kept in one
11
+ // place because the daemon and the deploy have to agree on where a source's key and checkout live.
12
+ // The user's own folder, so this works the same on a machine that has no /etc. The daemon runs as
13
+ // root, so on a host this is root's home.
14
+ exports.KEYS_DIR_NAME = "authorized_keys";
15
+ // Where keys used to go. Still read, so a host set up before this keeps working, but nothing is
16
+ // written here any more.
17
+ exports.LEGACY_REPO_KEYS_DIR = "/etc/portsecure/repo-keys";
8
18
  exports.REPOS_DIR = "/var/lib/portsecure/authorized-keys-repos";
19
+ function keysDir() {
20
+ return path_1.default.join(os_1.default.homedir(), exports.KEYS_DIR_NAME);
21
+ }
22
+ exports.keysDir = keysDir;
9
23
  /** A repo url reduced to something usable as a file name. Derived rather than configured, so the
10
24
  daemon and the deploy script always agree on where a source's key and checkout live. */
11
25
  function sourceName(repoURL) {
@@ -13,12 +27,42 @@ function sourceName(repoURL) {
13
27
  }
14
28
  exports.sourceName = sourceName;
15
29
  function sourceKeyPath(repoURL) {
16
- return `${exports.REPO_KEYS_DIR}/${sourceName(repoURL)}`;
30
+ return path_1.default.join(keysDir(), sourceName(repoURL));
17
31
  }
18
32
  exports.sourceKeyPath = sourceKeyPath;
33
+ function legacySourceKeyPath(repoURL) {
34
+ return `${exports.LEGACY_REPO_KEYS_DIR}/${sourceName(repoURL)}`;
35
+ }
36
+ exports.legacySourceKeyPath = legacySourceKeyPath;
19
37
  function sourceRepoPath(repoURL) {
20
38
  return `${exports.REPOS_DIR}/${sourceName(repoURL)}`;
21
39
  }
22
40
  exports.sourceRepoPath = sourceRepoPath;
23
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNvdXJjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHlIQUF5SDtBQUN6SCxpR0FBaUc7QUFDakcsdUVBQXVFOzs7QUFFMUQsUUFBQSxhQUFhLEdBQUcsMkJBQTJCLENBQUM7QUFDNUMsUUFBQSxTQUFTLEdBQUcsMkNBQTJDLENBQUM7QUFFckU7MkZBQzJGO0FBQzNGLFNBQWdCLFVBQVUsQ0FBQyxPQUFlO0lBQ3RDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQ3hGLENBQUM7QUFGRCxnQ0FFQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxPQUFlO0lBQ3pDLE9BQU8sR0FBRyxxQkFBYSxJQUFJLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO0FBQ3JELENBQUM7QUFGRCxzQ0FFQztBQUVELFNBQWdCLGNBQWMsQ0FBQyxPQUFlO0lBQzFDLE9BQU8sR0FBRyxpQkFBUyxJQUFJLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO0FBQ2pELENBQUM7QUFGRCx3Q0FFQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIFBPUlRFRCBDT0RFOiBzZWN1cml0eS9hdXRob3JpemVkS2V5cy9kYWVtb24vcG9ydHNlY3VyZURhZW1vbi5qcyBjb250YWlucyBhIHBsYWluIEpTIHBvcnQgb2YgZXZlcnl0aGluZyBoZXJlLCBzbyBpdCBjYW5cbi8vIHJlc29sdmUgdGhlIHNhbWUgbG9jYXRpb25zIHdpdGggbm8gZGVwZW5kZW5jaWVzLiBCb3RoIHNpZGVzIG11c3QgZGVyaXZlIGlkZW50aWNhbCBwYXRocyBmcm9tIGFcbi8vIHJlcG8gdXJsIC0gaWYgeW91IGNoYW5nZSBvbmUsIG1ha2UgdGhlIG1hdGNoaW5nIGNoYW5nZSBpbiB0aGUgb3RoZXIuXG5cbmV4cG9ydCBjb25zdCBSRVBPX0tFWVNfRElSID0gXCIvZXRjL3BvcnRzZWN1cmUvcmVwby1rZXlzXCI7XG5leHBvcnQgY29uc3QgUkVQT1NfRElSID0gXCIvdmFyL2xpYi9wb3J0c2VjdXJlL2F1dGhvcml6ZWQta2V5cy1yZXBvc1wiO1xuXG4vKiogQSByZXBvIHVybCByZWR1Y2VkIHRvIHNvbWV0aGluZyB1c2FibGUgYXMgYSBmaWxlIG5hbWUuIERlcml2ZWQgcmF0aGVyIHRoYW4gY29uZmlndXJlZCwgc28gdGhlXG4gICAgZGFlbW9uIGFuZCB0aGUgZGVwbG95IHNjcmlwdCBhbHdheXMgYWdyZWUgb24gd2hlcmUgYSBzb3VyY2UncyBrZXkgYW5kIGNoZWNrb3V0IGxpdmUuICovXG5leHBvcnQgZnVuY3Rpb24gc291cmNlTmFtZShyZXBvVVJMOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gcmVwb1VSTC5yZXBsYWNlKC9bXkEtWmEtejAtOV0rL2csIFwiLVwiKS5yZXBsYWNlKC9eLSt8LSskL2csIFwiXCIpLnRvTG93ZXJDYXNlKCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzb3VyY2VLZXlQYXRoKHJlcG9VUkw6IHN0cmluZykge1xuICAgIHJldHVybiBgJHtSRVBPX0tFWVNfRElSfS8ke3NvdXJjZU5hbWUocmVwb1VSTCl9YDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNvdXJjZVJlcG9QYXRoKHJlcG9VUkw6IHN0cmluZykge1xuICAgIHJldHVybiBgJHtSRVBPU19ESVJ9LyR7c291cmNlTmFtZShyZXBvVVJMKX1gO1xufVxuIl19
24
- /* _JS_SOURCE_HASH = "d4a51163d16ac57a8fa5966ca3b09eaebcbef4ca2200c706a7e125220c7db7b8"; */
41
+ async function pathExists(filePath) {
42
+ try {
43
+ await promises_1.default.access(filePath);
44
+ return true;
45
+ }
46
+ catch (e) {
47
+ return false;
48
+ }
49
+ }
50
+ /** The key for a source, wherever it happens to be. The user folder is where they go now, and the
51
+ old location is still read so a host that predates the move keeps working. */
52
+ async function findKey(config) {
53
+ let { current, legacy } = config;
54
+ if (await pathExists(current)) {
55
+ return current;
56
+ }
57
+ if (await pathExists(legacy)) {
58
+ return legacy;
59
+ }
60
+ return "";
61
+ }
62
+ exports.findKey = findKey;
63
+ async function findSourceKey(repoURL) {
64
+ return await findKey({ current: sourceKeyPath(repoURL), legacy: legacySourceKeyPath(repoURL) });
65
+ }
66
+ exports.findSourceKey = findSourceKey;
67
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic291cmNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNvdXJjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsMkRBQTZCO0FBQzdCLDRDQUFvQjtBQUNwQixnREFBd0I7QUFFeEIsZ0dBQWdHO0FBQ2hHLG1HQUFtRztBQUVuRyxrR0FBa0c7QUFDbEcsMENBQTBDO0FBQzdCLFFBQUEsYUFBYSxHQUFHLGlCQUFpQixDQUFDO0FBQy9DLGdHQUFnRztBQUNoRyx5QkFBeUI7QUFDWixRQUFBLG9CQUFvQixHQUFHLDJCQUEyQixDQUFDO0FBQ25ELFFBQUEsU0FBUyxHQUFHLDJDQUEyQyxDQUFDO0FBRXJFLFNBQWdCLE9BQU87SUFDbkIsT0FBTyxjQUFJLENBQUMsSUFBSSxDQUFDLFlBQUUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxxQkFBYSxDQUFDLENBQUM7QUFDbEQsQ0FBQztBQUZELDBCQUVDO0FBRUQ7MkZBQzJGO0FBQzNGLFNBQWdCLFVBQVUsQ0FBQyxPQUFlO0lBQ3RDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO0FBQ3hGLENBQUM7QUFGRCxnQ0FFQztBQUVELFNBQWdCLGFBQWEsQ0FBQyxPQUFlO0lBQ3pDLE9BQU8sY0FBSSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsRUFBRSxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztBQUNyRCxDQUFDO0FBRkQsc0NBRUM7QUFFRCxTQUFnQixtQkFBbUIsQ0FBQyxPQUFlO0lBQy9DLE9BQU8sR0FBRyw0QkFBb0IsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztBQUM1RCxDQUFDO0FBRkQsa0RBRUM7QUFFRCxTQUFnQixjQUFjLENBQUMsT0FBZTtJQUMxQyxPQUFPLEdBQUcsaUJBQVMsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztBQUNqRCxDQUFDO0FBRkQsd0NBRUM7QUFFRCxLQUFLLFVBQVUsVUFBVSxDQUFDLFFBQWdCO0lBQ3RDLElBQUksQ0FBQztRQUNELE1BQU0sa0JBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDMUIsT0FBTyxJQUFJLENBQUM7SUFDaEIsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDVCxPQUFPLEtBQUssQ0FBQztJQUNqQixDQUFDO0FBQ0wsQ0FBQztBQUVEO2lGQUNpRjtBQUMxRSxLQUFLLFVBQVUsT0FBTyxDQUFDLE1BQTJDO0lBQ3JFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDO0lBQ2pDLElBQUksTUFBTSxVQUFVLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztRQUM1QixPQUFPLE9BQU8sQ0FBQztJQUNuQixDQUFDO0lBQ0QsSUFBSSxNQUFNLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO1FBQzNCLE9BQU8sTUFBTSxDQUFDO0lBQ2xCLENBQUM7SUFDRCxPQUFPLEVBQUUsQ0FBQztBQUNkLENBQUM7QUFURCwwQkFTQztBQUVNLEtBQUssVUFBVSxhQUFhLENBQUMsT0FBZTtJQUMvQyxPQUFPLE1BQU0sT0FBTyxDQUFDLEVBQUUsT0FBTyxFQUFFLGFBQWEsQ0FBQyxPQUFPLENBQUMsRUFBRSxNQUFNLEVBQUUsbUJBQW1CLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBQ3BHLENBQUM7QUFGRCxzQ0FFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCBvcyBmcm9tIFwib3NcIjtcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCI7XG5cbi8vIFBPUlRFRCBDT0RFOiBub3RoaW5nIGhlcmUgaXMgZHVwbGljYXRlZCBhbnkgbW9yZSwgdGhlIGRhZW1vbiBpbXBvcnRzIGl0IGRpcmVjdGx5LiBLZXB0IGluIG9uZVxuLy8gcGxhY2UgYmVjYXVzZSB0aGUgZGFlbW9uIGFuZCB0aGUgZGVwbG95IGhhdmUgdG8gYWdyZWUgb24gd2hlcmUgYSBzb3VyY2UncyBrZXkgYW5kIGNoZWNrb3V0IGxpdmUuXG5cbi8vIFRoZSB1c2VyJ3Mgb3duIGZvbGRlciwgc28gdGhpcyB3b3JrcyB0aGUgc2FtZSBvbiBhIG1hY2hpbmUgdGhhdCBoYXMgbm8gL2V0Yy4gVGhlIGRhZW1vbiBydW5zIGFzXG4vLyByb290LCBzbyBvbiBhIGhvc3QgdGhpcyBpcyByb290J3MgaG9tZS5cbmV4cG9ydCBjb25zdCBLRVlTX0RJUl9OQU1FID0gXCJhdXRob3JpemVkX2tleXNcIjtcbi8vIFdoZXJlIGtleXMgdXNlZCB0byBnby4gU3RpbGwgcmVhZCwgc28gYSBob3N0IHNldCB1cCBiZWZvcmUgdGhpcyBrZWVwcyB3b3JraW5nLCBidXQgbm90aGluZyBpc1xuLy8gd3JpdHRlbiBoZXJlIGFueSBtb3JlLlxuZXhwb3J0IGNvbnN0IExFR0FDWV9SRVBPX0tFWVNfRElSID0gXCIvZXRjL3BvcnRzZWN1cmUvcmVwby1rZXlzXCI7XG5leHBvcnQgY29uc3QgUkVQT1NfRElSID0gXCIvdmFyL2xpYi9wb3J0c2VjdXJlL2F1dGhvcml6ZWQta2V5cy1yZXBvc1wiO1xuXG5leHBvcnQgZnVuY3Rpb24ga2V5c0RpcigpIHtcbiAgICByZXR1cm4gcGF0aC5qb2luKG9zLmhvbWVkaXIoKSwgS0VZU19ESVJfTkFNRSk7XG59XG5cbi8qKiBBIHJlcG8gdXJsIHJlZHVjZWQgdG8gc29tZXRoaW5nIHVzYWJsZSBhcyBhIGZpbGUgbmFtZS4gRGVyaXZlZCByYXRoZXIgdGhhbiBjb25maWd1cmVkLCBzbyB0aGVcbiAgICBkYWVtb24gYW5kIHRoZSBkZXBsb3kgc2NyaXB0IGFsd2F5cyBhZ3JlZSBvbiB3aGVyZSBhIHNvdXJjZSdzIGtleSBhbmQgY2hlY2tvdXQgbGl2ZS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzb3VyY2VOYW1lKHJlcG9VUkw6IHN0cmluZykge1xuICAgIHJldHVybiByZXBvVVJMLnJlcGxhY2UoL1teQS1aYS16MC05XSsvZywgXCItXCIpLnJlcGxhY2UoL14tK3wtKyQvZywgXCJcIikudG9Mb3dlckNhc2UoKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNvdXJjZUtleVBhdGgocmVwb1VSTDogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHBhdGguam9pbihrZXlzRGlyKCksIHNvdXJjZU5hbWUocmVwb1VSTCkpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbGVnYWN5U291cmNlS2V5UGF0aChyZXBvVVJMOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYCR7TEVHQUNZX1JFUE9fS0VZU19ESVJ9LyR7c291cmNlTmFtZShyZXBvVVJMKX1gO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc291cmNlUmVwb1BhdGgocmVwb1VSTDogc3RyaW5nKSB7XG4gICAgcmV0dXJuIGAke1JFUE9TX0RJUn0vJHtzb3VyY2VOYW1lKHJlcG9VUkwpfWA7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHBhdGhFeGlzdHMoZmlsZVBhdGg6IHN0cmluZykge1xuICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGZzLmFjY2VzcyhmaWxlUGF0aCk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuLyoqIFRoZSBrZXkgZm9yIGEgc291cmNlLCB3aGVyZXZlciBpdCBoYXBwZW5zIHRvIGJlLiBUaGUgdXNlciBmb2xkZXIgaXMgd2hlcmUgdGhleSBnbyBub3csIGFuZCB0aGVcbiAgICBvbGQgbG9jYXRpb24gaXMgc3RpbGwgcmVhZCBzbyBhIGhvc3QgdGhhdCBwcmVkYXRlcyB0aGUgbW92ZSBrZWVwcyB3b3JraW5nLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZpbmRLZXkoY29uZmlnOiB7IGN1cnJlbnQ6IHN0cmluZzsgbGVnYWN5OiBzdHJpbmcgfSkge1xuICAgIGxldCB7IGN1cnJlbnQsIGxlZ2FjeSB9ID0gY29uZmlnO1xuICAgIGlmIChhd2FpdCBwYXRoRXhpc3RzKGN1cnJlbnQpKSB7XG4gICAgICAgIHJldHVybiBjdXJyZW50O1xuICAgIH1cbiAgICBpZiAoYXdhaXQgcGF0aEV4aXN0cyhsZWdhY3kpKSB7XG4gICAgICAgIHJldHVybiBsZWdhY3k7XG4gICAgfVxuICAgIHJldHVybiBcIlwiO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmluZFNvdXJjZUtleShyZXBvVVJMOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gYXdhaXQgZmluZEtleSh7IGN1cnJlbnQ6IHNvdXJjZUtleVBhdGgocmVwb1VSTCksIGxlZ2FjeTogbGVnYWN5U291cmNlS2V5UGF0aChyZXBvVVJMKSB9KTtcbn1cbiJdfQ==
68
+ /* _JS_SOURCE_HASH = "d66a91022052069dc8a7c111312ca09502fb4974baa795ec49d4d0ebed0668bf"; */