@camstack/server 1.2.593 → 1.2.594
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-root-inventory.js +11 -50
- package/dist/agent/addon-scan.js +6 -44
- package/dist/agent/agent-addon-runtime.js +3 -8
- package/dist/agent/agent-addon-updates.js +12 -52
- package/dist/agent/agent-cap-dispatch-service.js +3 -5
- package/dist/agent/agent-config.js +7 -42
- package/dist/agent/agent-deploy-swap.js +5 -41
- package/dist/agent/agent-group-runner.js +8 -47
- package/dist/agent/agent-http-auth.js +10 -22
- package/dist/agent/agent-http.js +69 -115
- package/dist/agent/agent-hub-addon-update.js +10 -16
- package/dist/agent/agent-hub-registration.js +4 -7
- package/dist/agent/agent-infra-capabilities.js +5 -9
- package/dist/agent/agent-json-file.js +5 -42
- package/dist/agent/agent-mesh-gate.js +5 -8
- package/dist/agent/agent-node-certificates.js +25 -28
- package/dist/agent/agent-pairing-local.js +10 -47
- package/dist/agent/agent-pairing-routes.js +16 -20
- package/dist/agent/agent-pairing-store.js +18 -58
- package/dist/agent/agent-reconnect.js +1 -4
- package/dist/agent/agent-service.js +42 -78
- package/dist/agent/agent-sniffing-listener.js +11 -48
- package/dist/agent/agent-undeploy.js +5 -41
- package/dist/agent/agent-update-routes.js +14 -19
- package/dist/agent/agent-update-service.js +38 -80
- package/dist/agent/apply-model-distribution.js +1 -4
- package/dist/agent/apply-stage-dev-uploads.js +6 -9
- package/dist/agent/derive-hub-url.js +3 -8
- package/dist/agent/fetch-bundle-from-hub.js +6 -9
- package/dist/agent/hubs-found.js +6 -43
- package/dist/agent/infra-boot-guard.js +1 -4
- package/dist/agent/infra-boot-plan.js +2 -6
- package/dist/agent/main.js +158 -186
- package/dist/agent/register-agent-cap-dispatch.js +3 -6
- package/dist/agent/serial-queue.js +2 -7
- package/dist/agent-status-page.js +1 -4
- package/dist/api/addon-upload.js +22 -61
- package/dist/api/agent-addon-delivery.js +6 -11
- package/dist/api/auth-whoami.js +1 -4
- package/dist/api/backup-download-pump.js +5 -9
- package/dist/api/backup-download.js +7 -10
- package/dist/api/core/addon-settings.router.js +16 -19
- package/dist/api/core/agent-pairing.router.js +76 -79
- package/dist/api/core/agents.router.js +21 -24
- package/dist/api/core/auth-admin-tokens.procedures.js +48 -52
- package/dist/api/core/auth-device-cert.procedures.js +62 -67
- package/dist/api/core/auth-limits.js +16 -25
- package/dist/api/core/auth-reauth.procedures.js +32 -37
- package/dist/api/core/auth-revoke-credentials.procedures.js +22 -26
- package/dist/api/core/auth-sessions.procedures.js +52 -56
- package/dist/api/core/auth.router.js +300 -304
- package/dist/api/core/cap-providers.js +74 -121
- package/dist/api/core/capabilities.router.js +34 -37
- package/dist/api/core/capability-preference-writes.js +10 -17
- package/dist/api/core/certificates.router.js +106 -109
- package/dist/api/core/cluster-nodes.router.js +15 -18
- package/dist/api/core/collection-preference.js +2 -6
- package/dist/api/core/event-bus-proxy.router.js +34 -37
- package/dist/api/core/failure-contributions.js +4 -8
- package/dist/api/core/hwaccel.router.js +17 -20
- package/dist/api/core/integration-secrets.js +8 -12
- package/dist/api/core/lifecycle-job-runner.js +13 -49
- package/dist/api/core/live-events.router.js +29 -32
- package/dist/api/core/load-contributions.js +4 -8
- package/dist/api/core/logging-settings.js +30 -43
- package/dist/api/core/logs.router.js +40 -43
- package/dist/api/core/notifications.router.js +15 -18
- package/dist/api/core/public-event-filter.js +4 -8
- package/dist/api/core/repl.router.js +18 -21
- package/dist/api/core/request-census-settings.js +11 -16
- package/dist/api/core/server-management.provider.js +1 -4
- package/dist/api/core/server-name.js +9 -17
- package/dist/api/core/site-location.js +16 -24
- package/dist/api/core/stream-probe.router.js +21 -24
- package/dist/api/core/system-events.router.js +23 -26
- package/dist/api/cors/cors-policy.js +20 -29
- package/dist/api/cors/register-cors-policy.js +9 -14
- package/dist/api/deploy-stage-registry.js +6 -10
- package/dist/api/dev-uploads-bundle.js +12 -50
- package/dist/api/health/adaptive-probe.routes.js +9 -13
- package/dist/api/health/health.routes.js +8 -13
- package/dist/api/hub-cluster-url.js +3 -9
- package/dist/api/model-distributor.js +12 -50
- package/dist/api/oauth2/consent-page.js +10 -13
- package/dist/api/oauth2/oauth2-routes.js +17 -25
- package/dist/api/oauth2/private-host.js +1 -4
- package/dist/api/server-upload-propagate.js +15 -51
- package/dist/api/server-upload.js +13 -50
- package/dist/api/sse-no-compression.js +1 -4
- package/dist/api/static/frame-policy.js +4 -9
- package/dist/api/static/precompressed-asset.js +15 -57
- package/dist/api/static/spa-mount.js +8 -47
- package/dist/api/static/spa-static.js +5 -12
- package/dist/api/tarball-manifest.js +7 -44
- package/dist/api/trpc/cap-mount-helpers.js +7 -12
- package/dist/api/trpc/cap-route-error-formatter.js +10 -13
- package/dist/api/trpc/cap-router-runtime.js +40 -51
- package/dist/api/trpc/client-ip.js +9 -20
- package/dist/api/trpc/core-cap-bridge.js +32 -42
- package/dist/api/trpc/device-collection-dispatch.js +23 -27
- package/dist/api/trpc/device-config-secret-redaction.js +24 -40
- package/dist/api/trpc/generated-cap-mounts.js +218 -222
- package/dist/api/trpc/generated-cap-routers.js +4688 -4850
- package/dist/api/trpc/http-request-census-hook.js +8 -11
- package/dist/api/trpc/http-request-census.js +34 -41
- package/dist/api/trpc/http-request-census.singleton.js +4 -8
- package/dist/api/trpc/localized-schema-paths.js +1 -4
- package/dist/api/trpc/principal-visibility.js +14 -22
- package/dist/api/trpc/remote-addon-update-grant.js +1 -4
- package/dist/api/trpc/scope-access.js +10 -15
- package/dist/api/trpc/server-provided-caps.js +3 -7
- package/dist/api/trpc/share-view-access.js +6 -14
- package/dist/api/trpc/trpc-error-device-tags.js +3 -6
- package/dist/api/trpc/trpc-error-principal.js +2 -6
- package/dist/api/trpc/trpc.context.js +20 -25
- package/dist/api/trpc/trpc.middleware.js +38 -46
- package/dist/api/trpc/trpc.router.js +58 -99
- package/dist/api/trpc/user-error.js +5 -8
- package/dist/api/trpc/ws-request-census.js +17 -24
- package/dist/api/trpc/ws-slow-consumer-guard.js +11 -16
- package/dist/api/upload-auth.js +5 -9
- package/dist/auth/addon-route-jwt-gate.js +4 -7
- package/dist/auth/addon-route-share-gate.js +7 -12
- package/dist/auth/app-confirm-page.js +17 -22
- package/dist/auth/app-confirm-routes.js +26 -31
- package/dist/auth/app-confirmations.js +7 -44
- package/dist/auth/app-page-shell.js +17 -30
- package/dist/auth/app-page-strings.js +11 -17
- package/dist/auth/app-passkey-page.js +16 -21
- package/dist/auth/app-passkey-routes.js +37 -41
- package/dist/auth/app-refused-route.js +13 -18
- package/dist/auth/auth-network-policy.js +11 -15
- package/dist/auth/auth-provider-gate.js +4 -9
- package/dist/auth/auth-rate-limit.js +3 -7
- package/dist/auth/client-address.js +6 -9
- package/dist/auth/device-enroll-proofs.js +6 -43
- package/dist/auth/external-link-intents.js +3 -7
- package/dist/auth/hub-sessions.js +6 -12
- package/dist/auth/native-link-completions.js +7 -11
- package/dist/auth/native-return.js +9 -13
- package/dist/auth/passkey-provider.js +26 -32
- package/dist/auth/second-factors.js +6 -10
- package/dist/auth/session-connections.js +6 -12
- package/dist/auth/session-cookie.js +12 -23
- package/dist/auth/session-lifetimes.js +8 -12
- package/dist/auth/session-mint.js +4 -11
- package/dist/auth/sso-finish-app.js +13 -16
- package/dist/auth/sso-finish-deps.js +21 -27
- package/dist/auth/sso-finish.js +28 -38
- package/dist/auth/sso-routes.js +22 -25
- package/dist/auth/used-bridge-ids.js +1 -5
- package/dist/boot/boot-config.js +16 -55
- package/dist/boot/init-sequence.js +1 -4
- package/dist/boot/integration-id-backfill.js +3 -8
- package/dist/boot/platform-keychain-key.js +5 -42
- package/dist/boot/post-boot.service.js +14 -18
- package/dist/boot/reconcile-lifecycle-jobs.js +3 -6
- package/dist/boot/retired-public-url-env.js +4 -8
- package/dist/bootstrap-packages.js +1 -4
- package/dist/closure-node-modules.js +2 -38
- package/dist/closure-patches/patch-reach.json +6 -2
- package/dist/core/addon/addon-call-gateway.js +1 -5
- package/dist/core/addon/addon-package.service.js +83 -123
- package/dist/core/addon/addon-process-view.js +2 -6
- package/dist/core/addon/addon-realign-plan.js +1 -4
- package/dist/core/addon/addon-registry.service.js +199 -185
- package/dist/core/addon/addon-row-manifest.js +1 -4
- package/dist/core/addon/addon-search.service.js +3 -7
- package/dist/core/addon/addon-settings-provider.js +1 -3
- package/dist/core/addon/addon-uninstall.js +4 -11
- package/dist/core/addon/addon.tokens.js +2 -5
- package/dist/core/addon/device-meta-mirror.js +8 -13
- package/dist/core/addon/forked-custom-actions.js +6 -11
- package/dist/core/addon/integration-visibility.js +3 -6
- package/dist/core/addon/materialize-route-path.js +1 -4
- package/dist/core/addon/package-dir-utils.js +8 -45
- package/dist/core/addon/prune-misplaced-addons.js +5 -43
- package/dist/core/addon/runner-convergence.js +1 -4
- package/dist/core/addon/runner-serialization.js +1 -4
- package/dist/core/addon/runner-spawn-fanout.js +3 -8
- package/dist/core/addon/settings-door-wiring.js +5 -8
- package/dist/core/addon/single-flight-refresh.js +1 -4
- package/dist/core/addon-bridge/addon-bridge.service.js +7 -44
- package/dist/core/addon-pages/addon-pages.service.js +3 -40
- package/dist/core/addon-widgets/addon-widgets.service.js +4 -42
- package/dist/core/agent/agent-addon-backfill.js +9 -17
- package/dist/core/agent/agent-delivery-ledger.js +3 -7
- package/dist/core/agent/agent-liveness-event.js +2 -6
- package/dist/core/agent/agent-pairing-http.js +41 -45
- package/dist/core/agent/agent-registry.service.js +53 -92
- package/dist/core/agent/cluster-node-history-mirror.js +3 -7
- package/dist/core/agent/cluster-node-history-store.js +113 -58
- package/dist/core/agent/hub-agent-pairing.js +1 -5
- package/dist/core/agent/node-certificates-client.js +3 -6
- package/dist/core/agent/node-directory.js +1 -4
- package/dist/core/app-links/well-known-app-links.js +2 -6
- package/dist/core/auth/auth.service.js +3 -8
- package/dist/core/auth/handoff-code.service.js +11 -49
- package/dist/core/auth/record-kinds.js +35 -0
- package/dist/core/auth/share-token.service.js +174 -122
- package/dist/core/capability/capability.service.js +1 -5
- package/dist/core/config/config.schema.js +1 -6
- package/dist/core/config/config.service.js +2 -6
- package/dist/core/events/event-bus.service.js +3 -7
- package/dist/core/feature/feature.service.js +2 -6
- package/dist/core/lifecycle/lifecycle-runner.singleton.js +5 -10
- package/dist/core/lifecycle/lifecycle-state-machine.js +1 -5
- package/dist/core/logging/log-ring-buffer.js +1 -5
- package/dist/core/logging/logging.service.js +5 -9
- package/dist/core/logging/scoped-logger.js +1 -5
- package/dist/core/moleculer/agent-readiness-pull.js +1 -4
- package/dist/core/moleculer/agent-registration-request.js +3 -7
- package/dist/core/moleculer/cap-call-fn.js +39 -5
- package/dist/core/moleculer/cap-route-authority.js +3 -8
- package/dist/core/moleculer/hub-mesh-guard.js +5 -9
- package/dist/core/moleculer/moleculer.service.js +108 -119
- package/dist/core/network/network-quality.service.js +2 -6
- package/dist/core/notification/notification-wrapper.service.js +3 -7
- package/dist/core/notification/toast-wrapper.service.js +3 -7
- package/dist/core/provider/provider.tokens.js +1 -4
- package/dist/core/repl/repl-engine.service.js +4 -8
- package/dist/core/runner-health/runner-boot-check.js +7 -15
- package/dist/core/runner-health/update-preflight.js +9 -14
- package/dist/core/server-update/server-update.service.js +12 -49
- package/dist/core/server-update/system-apply-closure-patches.js +6 -42
- package/dist/core/server-update/system-ensure-prebuilds.js +3 -6
- package/dist/core/server-update/system-exec-npm.js +2 -5
- package/dist/core/storage/fs-storage-backend.js +1 -5
- package/dist/core/storage/storage-location-manager.js +1 -5
- package/dist/core/storage/storage.service.js +2 -6
- package/dist/core/streaming/ffmpeg-stream-info.js +3 -8
- package/dist/core/streaming/stream-probe.service.js +12 -16
- package/dist/core/streaming/ttl-cache.js +1 -5
- package/dist/core/topology/topology-emitter.service.js +19 -23
- package/dist/core/update-availability-emitter.js +3 -7
- package/dist/core/update-availability-store.js +8 -45
- package/dist/core/updates/agent-installed-packages.js +5 -9
- package/dist/core/updates/restart-marker.js +3 -8
- package/dist/core/updates/update-check-scheduler.js +13 -18
- package/dist/core/updates/wrapper-update-checker.js +3 -7
- package/dist/first-boot-addon-plan.js +2 -6
- package/dist/framework-nodepath.js +2 -38
- package/dist/i18n/request-lang.js +7 -11
- package/dist/launcher.js +30 -65
- package/dist/lifecycle-journal-path.js +2 -38
- package/dist/main.js +287 -324
- package/dist/manual-boot.js +120 -157
- package/dist/node-role.js +1 -4
- package/dist/package-inventory.js +7 -48
- package/dist/pending-restore.js +7 -43
- package/dist/single-copy-cleanup-runner.js +9 -45
- package/dist/single-copy-cleanup.js +7 -15
- package/dist/sqlite-restore.js +9 -48
- package/dist/starter.js +4 -39
- package/dist/ui-serving/lazy-ui-serving.js +3 -39
- package/package.json +13 -13
|
@@ -1,47 +1,10 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.readJsonFile = readJsonFile;
|
|
37
|
-
exports.writeJsonFile0600 = writeJsonFile0600;
|
|
38
1
|
/**
|
|
39
2
|
* `agent.json` read/write helpers. The file is owner-only on every OS (an owner+SYSTEM ACL on
|
|
40
3
|
* Windows, where 0600 is a no-op) because it holds the mesh private key.
|
|
41
4
|
*/
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
function readJsonFile(file) {
|
|
5
|
+
import * as fs from 'node:fs';
|
|
6
|
+
import { writeOwnerOnlyFileSync } from '@camstack/types/node';
|
|
7
|
+
export function readJsonFile(file) {
|
|
45
8
|
if (!fs.existsSync(file))
|
|
46
9
|
return {};
|
|
47
10
|
try {
|
|
@@ -54,6 +17,6 @@ function readJsonFile(file) {
|
|
|
54
17
|
return {};
|
|
55
18
|
}
|
|
56
19
|
}
|
|
57
|
-
function writeJsonFile0600(file, data) {
|
|
58
|
-
|
|
20
|
+
export function writeJsonFile0600(file, data) {
|
|
21
|
+
writeOwnerOnlyFileSync(file, JSON.stringify(data, null, 2));
|
|
59
22
|
}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createAgentMeshGate = createAgentMeshGate;
|
|
4
1
|
/**
|
|
5
2
|
* The agent's mesh gate (D802, D857): only the hub may call this agent, and the
|
|
6
3
|
* hub is recognised by its CERTIFICATE — the agent's own TLS listener accepted
|
|
@@ -14,13 +11,13 @@ exports.createAgentMeshGate = createAgentMeshGate;
|
|
|
14
11
|
*
|
|
15
12
|
* Also here: the agent's outbound event scope (D848) — its events go to the hub only.
|
|
16
13
|
*/
|
|
17
|
-
|
|
14
|
+
import { AgentMeshIdentityGate, createAgentEventScope, createMeshAccessMiddleware, } from '@camstack/system';
|
|
18
15
|
const HUB_NODE_ID = 'hub';
|
|
19
16
|
/** At most one "refused" line per sender per this long. */
|
|
20
17
|
const REFUSED_LOG_INTERVAL_MS = 60_000;
|
|
21
|
-
function createAgentMeshGate(opts) {
|
|
18
|
+
export function createAgentMeshGate(opts) {
|
|
22
19
|
const lastLoggedAt = new Map();
|
|
23
|
-
const gate = new
|
|
20
|
+
const gate = new AgentMeshIdentityGate({
|
|
24
21
|
ownNodeId: opts.nodeId,
|
|
25
22
|
hubNodeId: HUB_NODE_ID,
|
|
26
23
|
isVerifiedPeer: opts.isVerifiedPeer,
|
|
@@ -35,11 +32,11 @@ function createAgentMeshGate(opts) {
|
|
|
35
32
|
opts.log?.(`mesh inbound: "${nodeId}" is not the certified hub — refused (first call: ${what})`);
|
|
36
33
|
},
|
|
37
34
|
});
|
|
38
|
-
const eventScope =
|
|
35
|
+
const eventScope = createAgentEventScope({
|
|
39
36
|
hubNodeId: HUB_NODE_ID,
|
|
40
37
|
...(opts.log !== undefined ? { log: opts.log } : {}),
|
|
41
38
|
});
|
|
42
|
-
const inbound =
|
|
39
|
+
const inbound = createMeshAccessMiddleware({
|
|
43
40
|
ownNodeId: opts.nodeId,
|
|
44
41
|
gate,
|
|
45
42
|
logger: {
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createAgentNodeCertificates = createAgentNodeCertificates;
|
|
4
1
|
/**
|
|
5
2
|
* The agent's side of certificate management (D856): the `node-certificates`
|
|
6
3
|
* capability, provided by the agent runtime and called by the hub through the
|
|
@@ -24,9 +21,9 @@ exports.createAgentNodeCertificates = createAgentNodeCertificates;
|
|
|
24
21
|
* HTTPS leaf. Same shape: key pair + CSR here, signed public key back, ONE atomic file
|
|
25
22
|
* under `<dataDir>/tls`, hot-swapped into the sniffing listener.
|
|
26
23
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
import { createPrivateKey, X509Certificate } from 'node:crypto';
|
|
25
|
+
import { collectAgentNames, createAgentHttpsRequest, createMeshCsrPem, describeHttpsLeaf, describeMeshLeaf, exportMeshPrivateKeyPem, generateMeshKeyPair, installAgentHttps, loadAgentHttps, pinnedHttpsCaFingerprint, } from '@camstack/system';
|
|
26
|
+
import { readJsonFile, writeJsonFile0600 } from './agent-json-file.js';
|
|
30
27
|
/** Let the capability answer before the broker is torn down and rebuilt. */
|
|
31
28
|
const RECONNECT_DELAY_MS = 400;
|
|
32
29
|
/** A swap found pending at boot gets at least this long for the hub to confirm. */
|
|
@@ -49,7 +46,7 @@ function defaultSchedule(fn, ms) {
|
|
|
49
46
|
timer.unref?.();
|
|
50
47
|
return { cancel: () => clearTimeout(timer) };
|
|
51
48
|
}
|
|
52
|
-
function createAgentNodeCertificates(deps) {
|
|
49
|
+
export function createAgentNodeCertificates(deps) {
|
|
53
50
|
const { nodeId, log } = deps;
|
|
54
51
|
const tags = { nodeId };
|
|
55
52
|
const schedule = deps.schedule ?? defaultSchedule;
|
|
@@ -57,7 +54,7 @@ function createAgentNodeCertificates(deps) {
|
|
|
57
54
|
let pendingKeyPem = null;
|
|
58
55
|
let rollbackTimer = null;
|
|
59
56
|
const readMesh = () => {
|
|
60
|
-
const raw =
|
|
57
|
+
const raw = readJsonFile(deps.configPath);
|
|
61
58
|
return {
|
|
62
59
|
current: isMeshMaterial(raw['meshTls']) ? raw['meshTls'] : null,
|
|
63
60
|
previous: isMeshMaterial(raw['meshTlsPrevious']) ? raw['meshTlsPrevious'] : null,
|
|
@@ -66,7 +63,7 @@ function createAgentNodeCertificates(deps) {
|
|
|
66
63
|
};
|
|
67
64
|
const stillValid = (material) => {
|
|
68
65
|
try {
|
|
69
|
-
return
|
|
66
|
+
return describeMeshLeaf(material.certPem).notAfter > now();
|
|
70
67
|
}
|
|
71
68
|
catch {
|
|
72
69
|
return false;
|
|
@@ -74,9 +71,9 @@ function createAgentNodeCertificates(deps) {
|
|
|
74
71
|
};
|
|
75
72
|
/** Write `agent.json` with the swap leftovers removed and `meshTls` optionally replaced. */
|
|
76
73
|
const writeSettled = (replaceCurrent) => {
|
|
77
|
-
const raw =
|
|
74
|
+
const raw = readJsonFile(deps.configPath);
|
|
78
75
|
const { meshTlsPrevious: _p, meshSwap: _s, ...rest } = raw;
|
|
79
|
-
|
|
76
|
+
writeJsonFile0600(deps.configPath, {
|
|
80
77
|
...rest,
|
|
81
78
|
...(replaceCurrent !== undefined ? { meshTls: replaceCurrent } : {}),
|
|
82
79
|
});
|
|
@@ -159,13 +156,13 @@ function createAgentNodeCertificates(deps) {
|
|
|
159
156
|
return {
|
|
160
157
|
getCertificates: async () => {
|
|
161
158
|
const { current } = readMesh();
|
|
162
|
-
const https =
|
|
159
|
+
const https = loadAgentHttps(deps.dataDir, (reason) => log.error('The HTTPS bundle on disk is unusable - serving plain HTTP only', {
|
|
163
160
|
tags,
|
|
164
161
|
meta: { reason },
|
|
165
162
|
}));
|
|
166
163
|
let mesh = null;
|
|
167
164
|
if (current !== null) {
|
|
168
|
-
const leaf =
|
|
165
|
+
const leaf = describeMeshLeaf(current.certPem);
|
|
169
166
|
mesh = {
|
|
170
167
|
cn: leaf.cn,
|
|
171
168
|
serial: leaf.serial,
|
|
@@ -182,7 +179,7 @@ function createAgentNodeCertificates(deps) {
|
|
|
182
179
|
state: 'not-issued',
|
|
183
180
|
reason: 'No hub-issued HTTPS certificate has been installed on this node yet.',
|
|
184
181
|
}
|
|
185
|
-
: { state: 'served', leaf:
|
|
182
|
+
: { state: 'served', leaf: describeHttpsLeaf(https.certPem) },
|
|
186
183
|
};
|
|
187
184
|
},
|
|
188
185
|
prepareMeshRenewal: async () => {
|
|
@@ -195,9 +192,9 @@ function createAgentNodeCertificates(deps) {
|
|
|
195
192
|
}
|
|
196
193
|
// A leftover from a finished or failed swap is never a rollback target.
|
|
197
194
|
writeSettled();
|
|
198
|
-
const keys = await
|
|
199
|
-
pendingKeyPem = await
|
|
200
|
-
const csrPem = await
|
|
195
|
+
const keys = await generateMeshKeyPair();
|
|
196
|
+
pendingKeyPem = await exportMeshPrivateKeyPem(keys.privateKey);
|
|
197
|
+
const csrPem = await createMeshCsrPem(keys, nodeId);
|
|
201
198
|
log.info('Mesh leaf renewal: new key and CSR generated', { tags });
|
|
202
199
|
return { csrPem };
|
|
203
200
|
},
|
|
@@ -208,9 +205,9 @@ function createAgentNodeCertificates(deps) {
|
|
|
208
205
|
if (pendingKeyPem === null) {
|
|
209
206
|
throw new Error('no pending key: prepareMeshRenewal was not called (or the node restarted)');
|
|
210
207
|
}
|
|
211
|
-
const leaf = new
|
|
212
|
-
const ca = new
|
|
213
|
-
const currentCa = new
|
|
208
|
+
const leaf = new X509Certificate(input.certPem);
|
|
209
|
+
const ca = new X509Certificate(input.caCertPem);
|
|
210
|
+
const currentCa = new X509Certificate(current.caCertPem);
|
|
214
211
|
if (ca.fingerprint256 !== currentCa.fingerprint256) {
|
|
215
212
|
throw new Error('the CA that came with the new leaf is not the CA this node trusts');
|
|
216
213
|
}
|
|
@@ -219,15 +216,15 @@ function createAgentNodeCertificates(deps) {
|
|
|
219
216
|
if (!new RegExp(`(?:^|\\n)CN=${nodeId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?:\\n|$)`).test(leaf.subject)) {
|
|
220
217
|
throw new Error(`the new leaf is not issued for "${nodeId}"`);
|
|
221
218
|
}
|
|
222
|
-
if (!leaf.checkPrivateKey(
|
|
219
|
+
if (!leaf.checkPrivateKey(createPrivateKey(pendingKeyPem))) {
|
|
223
220
|
throw new Error('the new leaf does not match the key this node generated');
|
|
224
221
|
}
|
|
225
|
-
const raw =
|
|
222
|
+
const raw = readJsonFile(deps.configPath);
|
|
226
223
|
const swap = {
|
|
227
224
|
fingerprint: leaf.fingerprint256,
|
|
228
225
|
deadline: now() + input.confirmWithinMs,
|
|
229
226
|
};
|
|
230
|
-
|
|
227
|
+
writeJsonFile0600(deps.configPath, {
|
|
231
228
|
...raw,
|
|
232
229
|
meshTls: { certPem: input.certPem, keyPem: pendingKeyPem, caCertPem: current.caCertPem },
|
|
233
230
|
meshTlsPrevious: current,
|
|
@@ -260,8 +257,8 @@ function createAgentNodeCertificates(deps) {
|
|
|
260
257
|
return { ok: true };
|
|
261
258
|
},
|
|
262
259
|
prepareHttpsCertificate: async () => {
|
|
263
|
-
const names =
|
|
264
|
-
const request = await
|
|
260
|
+
const names = collectAgentNames(nodeId, deps.hostFacts);
|
|
261
|
+
const request = await createAgentHttpsRequest(deps.dataDir, nodeId, names);
|
|
265
262
|
log.info('HTTPS certificate: new key and CSR generated', {
|
|
266
263
|
tags,
|
|
267
264
|
meta: { hostnames: names.hostnames.length, addresses: names.addresses.length },
|
|
@@ -270,11 +267,11 @@ function createAgentNodeCertificates(deps) {
|
|
|
270
267
|
csrPem: request.csrPem,
|
|
271
268
|
hostnames: [...names.hostnames],
|
|
272
269
|
addresses: [...names.addresses],
|
|
273
|
-
pinnedCaFingerprintSha256:
|
|
270
|
+
pinnedCaFingerprintSha256: pinnedHttpsCaFingerprint(deps.dataDir),
|
|
274
271
|
};
|
|
275
272
|
},
|
|
276
273
|
installHttpsCertificate: async (input) => {
|
|
277
|
-
const material =
|
|
274
|
+
const material = installAgentHttps(deps.dataDir, input);
|
|
278
275
|
const listener = deps.getHttpsListener();
|
|
279
276
|
if (listener === null) {
|
|
280
277
|
log.warn('HTTPS certificate installed on disk but the agent HTTP listener is not up', {
|
|
@@ -286,7 +283,7 @@ function createAgentNodeCertificates(deps) {
|
|
|
286
283
|
tags,
|
|
287
284
|
});
|
|
288
285
|
}
|
|
289
|
-
const leaf =
|
|
286
|
+
const leaf = describeHttpsLeaf(material.certPem);
|
|
290
287
|
log.info('HTTPS certificate installed and hot-swapped', {
|
|
291
288
|
tags,
|
|
292
289
|
meta: {
|
|
@@ -1,40 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.PAIRING_RESET_FILE = exports.PAIRING_PIN_FILE = void 0;
|
|
37
|
-
exports.createLocalPairingAnnouncer = createLocalPairingAnnouncer;
|
|
38
1
|
/**
|
|
39
2
|
* Where a pairing's one-time PIN, the agent's own code and the reset code are shown: ONLY on the
|
|
40
3
|
* agent's machine (D857).
|
|
@@ -45,11 +8,11 @@ exports.createLocalPairingAnnouncer = createLocalPairingAnnouncer;
|
|
|
45
8
|
* desktop window (which asks the agent's loopback `status`) - and types the hub's code and the PIN
|
|
46
9
|
* into the page.
|
|
47
10
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import { writeOwnerOnlyFileSync } from '@camstack/types/node';
|
|
14
|
+
export const PAIRING_PIN_FILE = 'pairing-pin.txt';
|
|
15
|
+
export const PAIRING_RESET_FILE = 'pairing-reset.txt';
|
|
53
16
|
function describe(s) {
|
|
54
17
|
const fp = s.hub.caFingerprint.slice(0, 16);
|
|
55
18
|
return [
|
|
@@ -64,9 +27,9 @@ function describe(s) {
|
|
|
64
27
|
* holds exactly the live ones and is removed when none is left - and a stale one left by a previous
|
|
65
28
|
* run is removed here, at boot. A PIN is never logged anywhere else.
|
|
66
29
|
*/
|
|
67
|
-
function createLocalPairingAnnouncer(dataDir, log) {
|
|
68
|
-
const file = path.join(dataDir,
|
|
69
|
-
const resetFile = path.join(dataDir,
|
|
30
|
+
export function createLocalPairingAnnouncer(dataDir, log) {
|
|
31
|
+
const file = path.join(dataDir, PAIRING_PIN_FILE);
|
|
32
|
+
const resetFile = path.join(dataDir, PAIRING_RESET_FILE);
|
|
70
33
|
const live = new Map();
|
|
71
34
|
const flush = () => {
|
|
72
35
|
try {
|
|
@@ -75,7 +38,7 @@ function createLocalPairingAnnouncer(dataDir, log) {
|
|
|
75
38
|
return;
|
|
76
39
|
}
|
|
77
40
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
78
|
-
|
|
41
|
+
writeOwnerOnlyFileSync(file, `${[...live.values()].map(describe).join('\n\n')}\n`);
|
|
79
42
|
}
|
|
80
43
|
catch (err) {
|
|
81
44
|
log.warn(`could not write ${file}: ${err instanceof Error ? err.message : String(err)} - the PIN is in the console above`);
|
|
@@ -98,7 +61,7 @@ function createLocalPairingAnnouncer(dataDir, log) {
|
|
|
98
61
|
log.warn(`\nPairing reset code: ${code}\n (clears pairing lockouts and pending offers: POST /api/agent/pairing/reset {"code": ...}; also in ${resetFile})`);
|
|
99
62
|
try {
|
|
100
63
|
fs.mkdirSync(dataDir, { recursive: true });
|
|
101
|
-
|
|
64
|
+
writeOwnerOnlyFileSync(resetFile, `${code}\n`);
|
|
102
65
|
}
|
|
103
66
|
catch (err) {
|
|
104
67
|
log.warn(`could not write ${resetFile}: ${err instanceof Error ? err.message : String(err)} - the code is in the console above`);
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.isLocalRequest = isLocalRequest;
|
|
4
|
-
exports.registerAgentPairingRoutes = registerAgentPairingRoutes;
|
|
5
|
-
const system_1 = require("@camstack/system");
|
|
6
|
-
const agent_http_auth_js_1 = require("./agent-http-auth.js");
|
|
1
|
+
import { PAIRING_PATHS, } from '@camstack/system';
|
|
2
|
+
import { authInputOf, isGenuineLoopback } from './agent-http-auth.js';
|
|
7
3
|
const OFFER_WINDOW_MS = 60_000;
|
|
8
4
|
const DEFAULT_OFFERS_PER_MINUTE = 10;
|
|
9
5
|
const MAX_TRACKED_SOURCES = 512;
|
|
10
6
|
/** True for a request from this machine itself: loopback peer, no forwarding header. */
|
|
11
|
-
function isLocalRequest(req) {
|
|
12
|
-
return
|
|
7
|
+
export function isLocalRequest(req) {
|
|
8
|
+
return isGenuineLoopback(authInputOf(req));
|
|
13
9
|
}
|
|
14
10
|
function send(reply, result) {
|
|
15
11
|
if (result.ok)
|
|
@@ -25,7 +21,7 @@ function send(reply, result) {
|
|
|
25
21
|
...(failure.retryAfterMs !== undefined ? { retryAfterMs: failure.retryAfterMs } : {}),
|
|
26
22
|
});
|
|
27
23
|
}
|
|
28
|
-
function registerAgentPairingRoutes(app, deps) {
|
|
24
|
+
export function registerAgentPairingRoutes(app, deps) {
|
|
29
25
|
const { pairing } = deps;
|
|
30
26
|
const now = deps.now ?? Date.now;
|
|
31
27
|
const limit = deps.offersPerMinute ?? DEFAULT_OFFERS_PER_MINUTE;
|
|
@@ -44,10 +40,10 @@ function registerAgentPairingRoutes(app, deps) {
|
|
|
44
40
|
offersBySource.set(source, [...recent, at]);
|
|
45
41
|
return false;
|
|
46
42
|
};
|
|
47
|
-
app.get(
|
|
43
|
+
app.get(PAIRING_PATHS.hello, async () => pairing.hello());
|
|
48
44
|
// The network sees who asks; the agent's own machine sees the secrets.
|
|
49
|
-
app.get(
|
|
50
|
-
app.post(
|
|
45
|
+
app.get(PAIRING_PATHS.status, async (req) => isLocalRequest(req) ? pairing.localView() : pairing.publicView());
|
|
46
|
+
app.post(PAIRING_PATHS.offer, async (req, reply) => {
|
|
51
47
|
if (rateLimited(req.socket.remoteAddress ?? 'unknown')) {
|
|
52
48
|
deps.log(`pairing offers from ${req.socket.remoteAddress ?? 'unknown'} are rate limited`);
|
|
53
49
|
return reply.status(429).header('retry-after', '60').send({
|
|
@@ -58,20 +54,20 @@ function registerAgentPairingRoutes(app, deps) {
|
|
|
58
54
|
}
|
|
59
55
|
return send(reply, await pairing.offer(req.body));
|
|
60
56
|
});
|
|
61
|
-
app.post(
|
|
62
|
-
app.post(
|
|
63
|
-
app.post(
|
|
64
|
-
app.post(
|
|
57
|
+
app.post(PAIRING_PATHS.reveal, async (req, reply) => send(reply, pairing.reveal(req.body)));
|
|
58
|
+
app.post(PAIRING_PATHS.poll, async (req, reply) => send(reply, pairing.poll(req.body)));
|
|
59
|
+
app.post(PAIRING_PATHS.cancel, async (req, reply) => send(reply, pairing.cancel(req.body)));
|
|
60
|
+
app.post(PAIRING_PATHS.complete, async (req, reply) => send(reply, await pairing.complete(req.body)));
|
|
65
61
|
const contextOf = (req) => ({
|
|
66
62
|
local: isLocalRequest(req),
|
|
67
63
|
source: req.socket.remoteAddress ?? 'unknown',
|
|
68
64
|
});
|
|
69
|
-
app.post(
|
|
70
|
-
app.post(
|
|
65
|
+
app.post(PAIRING_PATHS.confirm, async (req, reply) => send(reply, pairing.confirm(req.body, contextOf(req))));
|
|
66
|
+
app.post(PAIRING_PATHS.reject, async (req, reply) => send(reply, pairing.reject(req.body, contextOf(req))));
|
|
71
67
|
// Clears the offer lockouts and pending offers: this machine, or the reset code printed at boot.
|
|
72
|
-
app.post(
|
|
68
|
+
app.post(PAIRING_PATHS.reset, async (req, reply) => send(reply, pairing.reset(req.body, contextOf(req))));
|
|
73
69
|
// Authenticated by the onRequest hook (not a protocol path): this machine or a hub session.
|
|
74
|
-
app.post(
|
|
70
|
+
app.post(PAIRING_PATHS.forget, async (_req, reply) => {
|
|
75
71
|
if (pairing.state() !== 'paired') {
|
|
76
72
|
return reply
|
|
77
73
|
.status(409)
|
|
@@ -1,57 +1,17 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.isAgentPaired = isAgentPaired;
|
|
37
|
-
exports.pinnedMeshCaCert = pinnedMeshCaCert;
|
|
38
|
-
exports.persistPairing = persistPairing;
|
|
39
|
-
exports.forgetPairing = forgetPairing;
|
|
40
|
-
exports.pairedLeafFingerprint = pairedLeafFingerprint;
|
|
41
1
|
/**
|
|
42
2
|
* What pairing writes to, and removes from, `agent.json` (D857). The file is
|
|
43
3
|
* 0600 on every OS; this module only ever touches the keys named below. An older
|
|
44
4
|
* `secret` field is neither read nor removed here — the operator deletes it.
|
|
45
5
|
*/
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
6
|
+
import { X509Certificate } from 'node:crypto';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import { agentHttpsPaths } from '@camstack/system';
|
|
9
|
+
import { readJsonFile, writeJsonFile0600 } from './agent-json-file.js';
|
|
50
10
|
/** Keys that exist only while this agent is paired. */
|
|
51
11
|
const PAIRED_KEYS = ['meshTls', 'meshTlsPrevious', 'meshSwap', 'hubAddress'];
|
|
52
12
|
/** `agent.json` holds mesh material: the agent is paired. */
|
|
53
|
-
function isAgentPaired(configPath) {
|
|
54
|
-
const meshTls =
|
|
13
|
+
export function isAgentPaired(configPath) {
|
|
14
|
+
const meshTls = readJsonFile(configPath)['meshTls'];
|
|
55
15
|
return (meshTls !== null &&
|
|
56
16
|
typeof meshTls === 'object' &&
|
|
57
17
|
typeof Reflect.get(meshTls, 'certPem') === 'string' &&
|
|
@@ -59,17 +19,17 @@ function isAgentPaired(configPath) {
|
|
|
59
19
|
typeof Reflect.get(meshTls, 'caCertPem') === 'string');
|
|
60
20
|
}
|
|
61
21
|
/** The CA certificate this agent pinned at pairing, or `null` while unpaired. */
|
|
62
|
-
function pinnedMeshCaCert(configPath) {
|
|
63
|
-
const meshTls =
|
|
22
|
+
export function pinnedMeshCaCert(configPath) {
|
|
23
|
+
const meshTls = readJsonFile(configPath)['meshTls'];
|
|
64
24
|
if (meshTls === null || typeof meshTls !== 'object')
|
|
65
25
|
return null;
|
|
66
26
|
const ca = Reflect.get(meshTls, 'caCertPem');
|
|
67
27
|
return typeof ca === 'string' && ca.length > 0 ? ca : null;
|
|
68
28
|
}
|
|
69
29
|
/** Persist a completed pairing: the leaf, its key, the pinned CA and the hub's host. */
|
|
70
|
-
function persistPairing(configPath, pairing) {
|
|
71
|
-
const { meshTlsPrevious: _previous, meshSwap: _swap, ...existing } =
|
|
72
|
-
|
|
30
|
+
export function persistPairing(configPath, pairing) {
|
|
31
|
+
const { meshTlsPrevious: _previous, meshSwap: _swap, ...existing } = readJsonFile(configPath);
|
|
32
|
+
writeJsonFile0600(configPath, {
|
|
73
33
|
...existing,
|
|
74
34
|
hubAddress: pairing.hubAddress,
|
|
75
35
|
meshTls: pairing.meshTls,
|
|
@@ -79,22 +39,22 @@ function persistPairing(configPath, pairing) {
|
|
|
79
39
|
* Leave the hub: erase the mesh material, the hub address and the HTTPS bundle
|
|
80
40
|
* the hub issued. The agent is unpaired afterwards and accepts offers again.
|
|
81
41
|
*/
|
|
82
|
-
function forgetPairing(configPath, dataDir) {
|
|
83
|
-
const existing =
|
|
84
|
-
|
|
85
|
-
const https =
|
|
42
|
+
export function forgetPairing(configPath, dataDir) {
|
|
43
|
+
const existing = readJsonFile(configPath);
|
|
44
|
+
writeJsonFile0600(configPath, Object.fromEntries(Object.entries(existing).filter(([key]) => !PAIRED_KEYS.includes(key))));
|
|
45
|
+
const https = agentHttpsPaths(dataDir);
|
|
86
46
|
for (const file of [https.bundlePath, https.certPath, https.pendingKeyPath]) {
|
|
87
47
|
fs.rmSync(file, { force: true });
|
|
88
48
|
}
|
|
89
49
|
}
|
|
90
50
|
/** First 16 hex chars of the SHA-256 of the agent's mesh leaf, `null` while unpaired. */
|
|
91
|
-
function pairedLeafFingerprint(configPath) {
|
|
92
|
-
const meshTls =
|
|
51
|
+
export function pairedLeafFingerprint(configPath) {
|
|
52
|
+
const meshTls = readJsonFile(configPath)['meshTls'];
|
|
93
53
|
const certPem = meshTls !== null && typeof meshTls === 'object' ? Reflect.get(meshTls, 'certPem') : null;
|
|
94
54
|
if (typeof certPem !== 'string')
|
|
95
55
|
return null;
|
|
96
56
|
try {
|
|
97
|
-
return new
|
|
57
|
+
return new X509Certificate(certPem).fingerprint256
|
|
98
58
|
.replaceAll(':', '')
|
|
99
59
|
.toLowerCase()
|
|
100
60
|
.slice(0, 16);
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createReconnectRunner = createReconnectRunner;
|
|
4
|
-
function createReconnectRunner(deps) {
|
|
1
|
+
export function createReconnectRunner(deps) {
|
|
5
2
|
let generation = 0;
|
|
6
3
|
return async () => {
|
|
7
4
|
const mine = ++generation;
|