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
@@ -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"; */
@@ -0,0 +1,147 @@
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.describeEndedSessions = exports.describeAllEnded = exports.endAllSSHSessions = exports.endSessionsUsingKey = exports.parseAcceptedSessions = void 0;
7
+ const promises_1 = __importDefault(require("fs/promises"));
8
+ const spawn_1 = require("../../helpers/spawn");
9
+ const paths_1 = require("./paths");
10
+ // Taking a key out of authorized_keys only stops the next login. Whoever is already connected with
11
+ // it stays connected for as long as they like, which would make revoking a key that is being
12
+ // actively misused close to pointless.
13
+ //
14
+ // sshd names the key it accepted and the process handling that connection on the same line, so the
15
+ // sessions belonging to one key can be ended without touching anyone else's.
16
+ const ACCEPTED = /(?:sshd|sshd-session)\[(\d+)\]:\s+Accepted publickey for (\S+) from (\S+) port (\d+) ssh2: \S+ (SHA256:[A-Za-z0-9+/=]+)/;
17
+ function parseAcceptedSessions(contents, fingerprint) {
18
+ let sessions = [];
19
+ for (let line of contents.split("\n")) {
20
+ let match = line.match(ACCEPTED);
21
+ if (!match || match[5] !== fingerprint) {
22
+ continue;
23
+ }
24
+ sessions.push({ processId: Number(match[1]), user: match[2], ip: match[3], port: match[4] });
25
+ }
26
+ return sessions;
27
+ }
28
+ exports.parseAcceptedSessions = parseAcceptedSessions;
29
+ /** Process ids are reused, so one is only killed when it is still an ssh session. Killing whatever
30
+ happens to hold that number now would be far worse than missing a session. */
31
+ async function isSSHSession(processId) {
32
+ try {
33
+ let name = await promises_1.default.readFile(`/proc/${processId}/comm`, "utf8");
34
+ return name.trim().startsWith("sshd");
35
+ }
36
+ catch (e) {
37
+ return false;
38
+ }
39
+ }
40
+ /** The whole log, not only what is new, because the session being ended may have been established
41
+ long before the key was misused. */
42
+ async function readWholeAuthLog() {
43
+ try {
44
+ return await promises_1.default.readFile(paths_1.AUTH_LOG_PATH, "utf8");
45
+ }
46
+ catch (e) {
47
+ let result = await (0, spawn_1.spawnPromise)({
48
+ command: "journalctl",
49
+ args: ["-u", "ssh", "-u", "sshd", "--no-pager", "--since", "-30days"],
50
+ });
51
+ return result.status === 0 && result.stdout || "";
52
+ }
53
+ }
54
+ /** Ends every live session that authenticated with this key. Returns what was ended, so the
55
+ revocation can say so rather than leaving it to be discovered. */
56
+ async function endSessionsUsingKey(fingerprint) {
57
+ let ended = [];
58
+ for (let session of parseAcceptedSessions(await readWholeAuthLog(), fingerprint)) {
59
+ if (session.processId <= 1 || session.processId === process.pid) {
60
+ continue;
61
+ }
62
+ if (!await isSSHSession(session.processId)) {
63
+ continue;
64
+ }
65
+ try {
66
+ process.kill(session.processId, "SIGKILL");
67
+ ended.push(session);
68
+ console.log(`Ended ssh session ${session.processId} (${session.user} from ${session.ip}), it used ${fingerprint}`);
69
+ }
70
+ catch (e) {
71
+ // Gone between looking and killing, which is the outcome we wanted anyway.
72
+ }
73
+ }
74
+ return ended;
75
+ }
76
+ exports.endSessionsUsingKey = endSessionsUsingKey;
77
+ /** Whether this process is one connection. The listener is not a connection - it is the process
78
+ that accepts them - so it is not a candidate here at all.
79
+
80
+ Every openssh since 9.8 runs each connection as its own sshd-session. On older ones connections
81
+ are named sshd too, and the listener is the one systemd started directly with -D. */
82
+ async function isConnectionProcess(processId) {
83
+ var _a;
84
+ let name;
85
+ try {
86
+ name = (await promises_1.default.readFile(`/proc/${processId}/comm`, "utf8")).trim();
87
+ }
88
+ catch (e) {
89
+ return false;
90
+ }
91
+ if (name === "sshd-session") {
92
+ return true;
93
+ }
94
+ if (name !== "sshd") {
95
+ return false;
96
+ }
97
+ let commandLine = await promises_1.default.readFile(`/proc/${processId}/cmdline`, "utf8").catch(() => "");
98
+ let parentId = Number(((_a = (await promises_1.default.readFile(`/proc/${processId}/stat`, "utf8").catch(() => "")).split(") ")[1]) === null || _a === void 0 ? void 0 : _a.split(" ")[1]) || 0);
99
+ return !commandLine.includes("-D") && parentId !== 1;
100
+ }
101
+ /** Disconnects every ssh session on the machine.
102
+
103
+ Not only the ones using the key that was just taken away: a session that predates the key being
104
+ removed is exactly as dangerous, and working out which sessions are still entitled to be here
105
+ is guesswork. Anyone who still has access can reconnect in a second, and anyone who does not
106
+ should not be here. */
107
+ async function endAllSSHSessions() {
108
+ let ended = [];
109
+ for (let entry of await promises_1.default.readdir("/proc")) {
110
+ let processId = Number(entry);
111
+ if (!processId || processId <= 1 || processId === process.pid) {
112
+ continue;
113
+ }
114
+ if (!await isConnectionProcess(processId)) {
115
+ continue;
116
+ }
117
+ try {
118
+ process.kill(processId, "SIGKILL");
119
+ ended.push(processId);
120
+ }
121
+ catch (e) {
122
+ // Gone between looking and killing, which is the outcome we wanted anyway.
123
+ }
124
+ }
125
+ if (ended.length) {
126
+ console.log(`Disconnected ${ended.length} ssh session(s): ${ended.join(", ")}`);
127
+ }
128
+ return ended;
129
+ }
130
+ exports.endAllSSHSessions = endAllSSHSessions;
131
+ function describeAllEnded(ended) {
132
+ if (!ended.length) {
133
+ return " Nothing was connected.";
134
+ }
135
+ return ` Every ssh session on this machine was disconnected, ${ended.length} of them.`;
136
+ }
137
+ exports.describeAllEnded = describeAllEnded;
138
+ function describeEndedSessions(ended) {
139
+ if (!ended.length) {
140
+ return " Nothing was connected with it.";
141
+ }
142
+ return ` ${ended.length} live session(s) using it were killed: `
143
+ + ended.map(session => `${session.user}@${session.ip}:${session.port}`).join(", ") + ".";
144
+ }
145
+ exports.describeEndedSessions = describeEndedSessions;
146
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZXNzaW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSwyREFBNkI7QUFDN0IsK0NBQW1EO0FBQ25ELG1DQUF3QztBQUV4QyxtR0FBbUc7QUFDbkcsNkZBQTZGO0FBQzdGLHVDQUF1QztBQUN2QyxFQUFFO0FBQ0YsbUdBQW1HO0FBQ25HLDZFQUE2RTtBQUM3RSxNQUFNLFFBQVEsR0FBRyx5SEFBeUgsQ0FBQztBQUkzSSxTQUFnQixxQkFBcUIsQ0FBQyxRQUFnQixFQUFFLFdBQW1CO0lBQ3ZFLElBQUksUUFBUSxHQUFpQixFQUFFLENBQUM7SUFDaEMsS0FBSyxJQUFJLElBQUksSUFBSSxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDcEMsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNqQyxJQUFJLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxXQUFXLEVBQUUsQ0FBQztZQUNyQyxTQUFTO1FBQ2IsQ0FBQztRQUNELFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNqRyxDQUFDO0lBQ0QsT0FBTyxRQUFRLENBQUM7QUFDcEIsQ0FBQztBQVZELHNEQVVDO0FBRUQ7aUZBQ2lGO0FBQ2pGLEtBQUssVUFBVSxZQUFZLENBQUMsU0FBaUI7SUFDekMsSUFBSSxDQUFDO1FBQ0QsSUFBSSxJQUFJLEdBQUcsTUFBTSxrQkFBRSxDQUFDLFFBQVEsQ0FBQyxTQUFTLFNBQVMsT0FB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SyxDQUFDLE1BQU0sb0JBQW9CLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3BGLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNqQixDQUFDO0FBckJELDhDQXFCQztBQUVELFNBQWdCLGdCQUFnQixDQUFDLEtBQWU7SUFDNUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNoQixPQUFPLHlCQUF5QixDQUFDO0lBQ3JDLENBQUM7SUFDRCxPQUFPLHdEQUF3RCxLQUFLLENBQUMsTUFBTSxXQUFXLENBQUM7QUFDM0YsQ0FBQztBQUxELDRDQUtDO0FBRUQsU0FBZ0IscUJBQXFCLENBQUMsS0FBbUI7SUFDckQsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNoQixPQUFPLGlDQUFpQyxDQUFDO0lBQzdDLENBQUM7SUFDRCxPQUFPLElBQUksS0FBSyxDQUFDLE1BQU0seUNBQXlDO1VBQzFELEtBQUssQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxJQUFJLElBQUksT0FBTyxDQUFDLEVBQUUsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDO0FBQ2pHLENBQUM7QUFORCxzREFNQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBmcyBmcm9tIFwiZnMvcHJvbWlzZXNcIjtcbmltcG9ydCB7IHNwYXduUHJvbWlzZSB9IGZyb20gXCIuLi8uLi9oZWxwZXJzL3NwYXduXCI7XG5pbXBvcnQgeyBBVVRIX0xPR19QQVRIIH0gZnJvbSBcIi4vcGF0aHNcIjtcblxuLy8gVGFraW5nIGEga2V5IG91dCBvZiBhdXRob3JpemVkX2tleXMgb25seSBzdG9wcyB0aGUgbmV4dCBsb2dpbi4gV2hvZXZlciBpcyBhbHJlYWR5IGNvbm5lY3RlZCB3aXRoXG4vLyBpdCBzdGF5cyBjb25uZWN0ZWQgZm9yIGFzIGxvbmcgYXMgdGhleSBsaWtlLCB3aGljaCB3b3VsZCBtYWtlIHJldm9raW5nIGEga2V5IHRoYXQgaXMgYmVpbmdcbi8vIGFjdGl2ZWx5IG1pc3VzZWQgY2xvc2UgdG8gcG9pbnRsZXNzLlxuLy9cbi8vIHNzaGQgbmFtZXMgdGhlIGtleSBpdCBhY2NlcHRlZCBhbmQgdGhlIHByb2Nlc3MgaGFuZGxpbmcgdGhhdCBjb25uZWN0aW9uIG9uIHRoZSBzYW1lIGxpbmUsIHNvIHRoZVxuLy8gc2Vzc2lvbnMgYmVsb25naW5nIHRvIG9uZSBrZXkgY2FuIGJlIGVuZGVkIHdpdGhvdXQgdG91Y2hpbmcgYW55b25lIGVsc2Uncy5cbmNvbnN0IEFDQ0VQVEVEID0gLyg/OnNzaGR8c3NoZC1zZXNzaW9uKVxcWyhcXGQrKVxcXTpcXHMrQWNjZXB0ZWQgcHVibGlja2V5IGZvciAoXFxTKykgZnJvbSAoXFxTKykgcG9ydCAoXFxkKykgc3NoMjogXFxTKyAoU0hBMjU2OltBLVphLXowLTkrLz1dKykvO1xuXG5leHBvcnQgdHlwZSBLZXlTZXNzaW9uID0geyBwcm9jZXNzSWQ6IG51bWJlcjsgdXNlcjogc3RyaW5nOyBpcDogc3RyaW5nOyBwb3J0OiBzdHJpbmcgfTtcblxuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQWNjZXB0ZWRTZXNzaW9ucyhjb250ZW50czogc3RyaW5nLCBmaW5nZXJwcmludDogc3RyaW5nKSB7XG4gICAgbGV0IHNlc3Npb25zOiBLZXlTZXNzaW9uW10gPSBbXTtcbiAgICBmb3IgKGxldCBsaW5lIG9mIGNvbnRlbnRzLnNwbGl0KFwiXFxuXCIpKSB7XG4gICAgICAgIGxldCBtYXRjaCA9IGxpbmUubWF0Y2goQUNDRVBURUQpO1xuICAgICAgICBpZiAoIW1hdGNoIHx8IG1hdGNoWzVdICE9PSBmaW5nZXJwcmludCkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgc2Vzc2lvbnMucHVzaCh7IHByb2Nlc3NJZDogTnVtYmVyKG1hdGNoWzFdKSwgdXNlcjogbWF0Y2hbMl0sIGlwOiBtYXRjaFszXSwgcG9ydDogbWF0Y2hbNF0gfSk7XG4gICAgfVxuICAgIHJldHVybiBzZXNzaW9ucztcbn1cblxuLyoqIFByb2Nlc3MgaWRzIGFyZSByZXVzZWQsIHNvIG9uZSBpcyBvbmx5IGtpbGxlZCB3aGVuIGl0IGlzIHN0aWxsIGFuIHNzaCBzZXNzaW9uLiBLaWxsaW5nIHdoYXRldmVyXG4gICAgaGFwcGVucyB0byBob2xkIHRoYXQgbnVtYmVyIG5vdyB3b3VsZCBiZSBmYXIgd29yc2UgdGhhbiBtaXNzaW5nIGEgc2Vzc2lvbi4gKi9cbmFzeW5jIGZ1bmN0aW9uIGlzU1NIU2Vzc2lvbihwcm9jZXNzSWQ6IG51bWJlcikge1xuICAgIHRyeSB7XG4gICAgICAgIGxldCBuYW1lID0gYXdhaXQgZnMucmVhZEZpbGUoYC9wcm9jLyR7cHJvY2Vzc0lkfS9jb21tYCwgXCJ1dGY4XCIpO1xuICAgICAgICByZXR1cm4gbmFtZS50cmltKCkuc3RhcnRzV2l0aChcInNzaGRcIik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxufVxuXG4vKiogVGhlIHdob2xlIGxvZywgbm90IG9ubHkgd2hhdCBpcyBuZXcsIGJlY2F1c2UgdGhlIHNlc3Npb24gYmVpbmcgZW5kZWQgbWF5IGhhdmUgYmVlbiBlc3RhYmxpc2hlZFxuICAgIGxvbmcgYmVmb3JlIHRoZSBrZXkgd2FzIG1pc3VzZWQuICovXG5hc3luYyBmdW5jdGlvbiByZWFkV2hvbGVBdXRoTG9nKCkge1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBhd2FpdCBmcy5yZWFkRmlsZShBVVRIX0xPR19QQVRILCBcInV0ZjhcIik7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsZXQgcmVzdWx0ID0gYXdhaXQgc3Bhd25Qcm9taXNlKHtcbiAgICAgICAgICAgIGNvbW1hbmQ6IFwiam91cm5hbGN0bFwiLFxuICAgICAgICAgICAgYXJnczogW1wiLXVcIiwgXCJzc2hcIiwgXCItdVwiLCBcInNzaGRcIiwgXCItLW5vLXBhZ2VyXCIsIFwiLS1zaW5jZVwiLCBcIi0zMGRheXNcIl0sXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmVzdWx0LnN0YXR1cyA9PT0gMCAmJiByZXN1bHQuc3Rkb3V0IHx8IFwiXCI7XG4gICAgfVxufVxuXG4vKiogRW5kcyBldmVyeSBsaXZlIHNlc3Npb24gdGhhdCBhdXRoZW50aWNhdGVkIHdpdGggdGhpcyBrZXkuIFJldHVybnMgd2hhdCB3YXMgZW5kZWQsIHNvIHRoZVxuICAgIHJldm9jYXRpb24gY2FuIHNheSBzbyByYXRoZXIgdGhhbiBsZWF2aW5nIGl0IHRvIGJlIGRpc2NvdmVyZWQuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZW5kU2Vzc2lvbnNVc2luZ0tleShmaW5nZXJwcmludDogc3RyaW5nKSB7XG4gICAgbGV0IGVuZGVkOiBLZXlTZXNzaW9uW10gPSBbXTtcbiAgICBmb3IgKGxldCBzZXNzaW9uIG9mIHBhcnNlQWNjZXB0ZWRTZXNzaW9ucyhhd2FpdCByZWFkV2hvbGVBdXRoTG9nKCksIGZpbmdlcnByaW50KSkge1xuICAgICAgICBpZiAoc2Vzc2lvbi5wcm9jZXNzSWQgPD0gMSB8fCBzZXNzaW9uLnByb2Nlc3NJZCA9PT0gcHJvY2Vzcy5waWQpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghYXdhaXQgaXNTU0hTZXNzaW9uKHNlc3Npb24ucHJvY2Vzc0lkKSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHByb2Nlc3Mua2lsbChzZXNzaW9uLnByb2Nlc3NJZCwgXCJTSUdLSUxMXCIpO1xuICAgICAgICAgICAgZW5kZWQucHVzaChzZXNzaW9uKTtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBFbmRlZCBzc2ggc2Vzc2lvbiAke3Nlc3Npb24ucHJvY2Vzc0lkfSAoJHtzZXNzaW9uLnVzZXJ9IGZyb20gJHtzZXNzaW9uLmlwfSksIGl0IHVzZWQgJHtmaW5nZXJwcmludH1gKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgLy8gR29uZSBiZXR3ZWVuIGxvb2tpbmcgYW5kIGtpbGxpbmcsIHdoaWNoIGlzIHRoZSBvdXRjb21lIHdlIHdhbnRlZCBhbnl3YXkuXG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGVuZGVkO1xufVxuXG4vKiogV2hldGhlciB0aGlzIHByb2Nlc3MgaXMgb25lIGNvbm5lY3Rpb24uIFRoZSBsaXN0ZW5lciBpcyBub3QgYSBjb25uZWN0aW9uIC0gaXQgaXMgdGhlIHByb2Nlc3NcbiAgICB0aGF0IGFjY2VwdHMgdGhlbSAtIHNvIGl0IGlzIG5vdCBhIGNhbmRpZGF0ZSBoZXJlIGF0IGFsbC5cblxuICAgIEV2ZXJ5IG9wZW5zc2ggc2luY2UgOS44IHJ1bnMgZWFjaCBjb25uZWN0aW9uIGFzIGl0cyBvd24gc3NoZC1zZXNzaW9uLiBPbiBvbGRlciBvbmVzIGNvbm5lY3Rpb25zXG4gICAgYXJlIG5hbWVkIHNzaGQgdG9vLCBhbmQgdGhlIGxpc3RlbmVyIGlzIHRoZSBvbmUgc3lzdGVtZCBzdGFydGVkIGRpcmVjdGx5IHdpdGggLUQuICovXG5hc3luYyBmdW5jdGlvbiBpc0Nvbm5lY3Rpb25Qcm9jZXNzKHByb2Nlc3NJZDogbnVtYmVyKSB7XG4gICAgbGV0IG5hbWU6IHN0cmluZztcbiAgICB0cnkge1xuICAgICAgICBuYW1lID0gKGF3YWl0IGZzLnJlYWRGaWxlKGAvcHJvYy8ke3Byb2Nlc3NJZH0vY29tbWAsIFwidXRmOFwiKSkudHJpbSgpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAobmFtZSA9PT0gXCJzc2hkLXNlc3Npb25cIikge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKG5hbWUgIT09IFwic3NoZFwiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0IGNvbW1hbmRMaW5lID0gYXdhaXQgZnMucmVhZEZpbGUoYC9wcm9jLyR7cHJvY2Vzc0lkfS9jbWRsaW5lYCwgXCJ1dGY4XCIpLmNhdGNoKCgpID0+IFwiXCIpO1xuICAgIGxldCBwYXJlbnRJZCA9IE51bWJlcigoYXdhaXQgZnMucmVhZEZpbGUoYC9wcm9jLyR7cHJvY2Vzc0lkfS9zdGF0YCwgXCJ1dGY4XCIpLmNhdGNoKCgpID0+IFwiXCIpKS5zcGxpdChcIikgXCIpWzFdPy5zcGxpdChcIiBcIilbMV0gfHwgMCk7XG4gICAgcmV0dXJuICFjb21tYW5kTGluZS5pbmNsdWRlcyhcIi1EXCIpICYmIHBhcmVudElkICE9PSAxO1xufVxuXG4vKiogRGlzY29ubmVjdHMgZXZlcnkgc3NoIHNlc3Npb24gb24gdGhlIG1hY2hpbmUuXG5cbiAgICBOb3Qgb25seSB0aGUgb25lcyB1c2luZyB0aGUga2V5IHRoYXQgd2FzIGp1c3QgdGFrZW4gYXdheTogYSBzZXNzaW9uIHRoYXQgcHJlZGF0ZXMgdGhlIGtleSBiZWluZ1xuICAgIHJlbW92ZWQgaXMgZXhhY3RseSBhcyBkYW5nZXJvdXMsIGFuZCB3b3JraW5nIG91dCB3aGljaCBzZXNzaW9ucyBhcmUgc3RpbGwgZW50aXRsZWQgdG8gYmUgaGVyZVxuICAgIGlzIGd1ZXNzd29yay4gQW55b25lIHdobyBzdGlsbCBoYXMgYWNjZXNzIGNhbiByZWNvbm5lY3QgaW4gYSBzZWNvbmQsIGFuZCBhbnlvbmUgd2hvIGRvZXMgbm90XG4gICAgc2hvdWxkIG5vdCBiZSBoZXJlLiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGVuZEFsbFNTSFNlc3Npb25zKCkge1xuICAgIGxldCBlbmRlZDogbnVtYmVyW10gPSBbXTtcbiAgICBmb3IgKGxldCBlbnRyeSBvZiBhd2FpdCBmcy5yZWFkZGlyKFwiL3Byb2NcIikpIHtcbiAgICAgICAgbGV0IHByb2Nlc3NJZCA9IE51bWJlcihlbnRyeSk7XG4gICAgICAgIGlmICghcHJvY2Vzc0lkIHx8IHByb2Nlc3NJZCA8PSAxIHx8IHByb2Nlc3NJZCA9PT0gcHJvY2Vzcy5waWQpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghYXdhaXQgaXNDb25uZWN0aW9uUHJvY2Vzcyhwcm9jZXNzSWQpKSB7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcHJvY2Vzcy5raWxsKHByb2Nlc3NJZCwgXCJTSUdLSUxMXCIpO1xuICAgICAgICAgICAgZW5kZWQucHVzaChwcm9jZXNzSWQpO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAvLyBHb25lIGJldHdlZW4gbG9va2luZyBhbmQga2lsbGluZywgd2hpY2ggaXMgdGhlIG91dGNvbWUgd2Ugd2FudGVkIGFueXdheS5cbiAgICAgICAgfVxuICAgIH1cbiAgICBpZiAoZW5kZWQubGVuZ3RoKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBEaXNjb25uZWN0ZWQgJHtlbmRlZC5sZW5ndGh9IHNzaCBzZXNzaW9uKHMpOiAke2VuZGVkLmpvaW4oXCIsIFwiKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIGVuZGVkO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVzY3JpYmVBbGxFbmRlZChlbmRlZDogbnVtYmVyW10pIHtcbiAgICBpZiAoIWVuZGVkLmxlbmd0aCkge1xuICAgICAgICByZXR1cm4gXCIgTm90aGluZyB3YXMgY29ubmVjdGVkLlwiO1xuICAgIH1cbiAgICByZXR1cm4gYCBFdmVyeSBzc2ggc2Vzc2lvbiBvbiB0aGlzIG1hY2hpbmUgd2FzIGRpc2Nvbm5lY3RlZCwgJHtlbmRlZC5sZW5ndGh9IG9mIHRoZW0uYDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGRlc2NyaWJlRW5kZWRTZXNzaW9ucyhlbmRlZDogS2V5U2Vzc2lvbltdKSB7XG4gICAgaWYgKCFlbmRlZC5sZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIFwiIE5vdGhpbmcgd2FzIGNvbm5lY3RlZCB3aXRoIGl0LlwiO1xuICAgIH1cbiAgICByZXR1cm4gYCAke2VuZGVkLmxlbmd0aH0gbGl2ZSBzZXNzaW9uKHMpIHVzaW5nIGl0IHdlcmUga2lsbGVkOiBgXG4gICAgICAgICsgZW5kZWQubWFwKHNlc3Npb24gPT4gYCR7c2Vzc2lvbi51c2VyfUAke3Nlc3Npb24uaXB9OiR7c2Vzc2lvbi5wb3J0fWApLmpvaW4oXCIsIFwiKSArIFwiLlwiO1xufVxuIl19
147
+ /* _JS_SOURCE_HASH = "cf2ea8f23e7beb7a09486c083165a234b4ab5ff28fd30dc6d6a9f582ff201eaf"; */