@camstack/system 1.2.435 → 1.2.436
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/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/autotrack/index.js +1 -1
- package/dist/builtins/autotrack/index.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
- package/dist/builtins/calendars/calendars.addon.js +1 -1
- package/dist/builtins/calendars/calendars.addon.mjs +1 -1
- package/dist/builtins/camera-grid/index.js +1 -1
- package/dist/builtins/camera-grid/index.mjs +1 -1
- package/dist/builtins/composer/composer.addon.js +2 -2
- package/dist/builtins/composer/composer.addon.mjs +2 -2
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
- package/dist/builtins/device-manager/device-manager.addon.js +2 -2
- package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +6 -7
- package/dist/builtins/keychain/index.mjs +6 -7
- package/dist/builtins/keychain/keychain-service.d.ts +1 -2
- package/dist/builtins/keychain/system-held-secrets.d.ts +5 -5
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/local-auth.addon.js +2 -2
- package/dist/builtins/local-auth/local-auth.addon.mjs +2 -2
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/index.js +1 -1
- package/dist/builtins/sqlite-storage/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -3
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
- package/dist/builtins/system-config/system-config.addon.d.ts +3 -24
- package/dist/builtins/system-config/system-config.addon.js +105 -1410
- package/dist/builtins/system-config/system-config.addon.mjs +108 -1402
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-Cm42mgbv.js → composition-sources-BAOlCu4j.js} +1 -1
- package/dist/{composition-sources-_7W2Ly9s.mjs → composition-sources-gN_BWUKp.mjs} +1 -1
- package/dist/constants-BFpowodq.mjs +20 -0
- package/dist/constants-GENKqk9k.js +66 -0
- package/dist/{device-ca-B6YJZus6.mjs → device-ca-BNM5ai4t.mjs} +1 -1
- package/dist/{device-ca-WXuKc8AX.js → device-ca-CuWuRW9N.js} +1 -1
- package/dist/{dist-CnUtkSwN.js → dist-DVe0Nsp8.js} +0 -12
- package/dist/{dist-Bz4_y8Xy.mjs → dist-DjD2M79P.mjs} +1 -1
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/index.js +132 -795
- package/dist/index.mjs +133 -753
- package/dist/kernel/index.d.ts +7 -21
- package/dist/kernel/moleculer/agent-ui-unlock.d.ts +7 -32
- package/dist/kernel/moleculer/broker-factory.d.ts +3 -9
- package/dist/kernel/moleculer/broker-transport-swap.d.ts +17 -0
- package/dist/kernel/moleculer/hub-service.d.ts +6 -16
- package/dist/kernel/moleculer/mesh-access-middleware.d.ts +7 -17
- package/dist/kernel/moleculer/mesh-identity.d.ts +57 -0
- package/dist/kernel/moleculer/mesh-mtls/constants.d.ts +1 -4
- package/dist/kernel/moleculer/mesh-mtls/index.d.ts +1 -4
- package/dist/kernel/moleculer/mesh-mtls/mesh-ca.d.ts +1 -1
- package/dist/kernel/moleculer/mesh-mtls/mesh-renewal.d.ts +1 -1
- package/dist/kernel/moleculer/node-registry.d.ts +0 -6
- package/dist/kernel/moleculer/register-node-client.d.ts +9 -7
- package/dist/{restore-archive-DJYuznWP.mjs → restore-archive-BxmP1ChO.mjs} +1 -1
- package/dist/{restore-archive-BNoFLAg8.js → restore-archive-D4h904rb.js} +1 -1
- package/dist/{retired-settings-keys-9nA85bwT.mjs → retired-settings-keys-CQaknvx1.mjs} +1 -1
- package/dist/{retired-settings-keys-CO3RqsDw.js → retired-settings-keys-CYP5IZJ5.js} +1 -1
- package/dist/{wal-maintenance-D3gwRj1B.js → wal-maintenance-Br60onAQ.js} +0 -0
- package/dist/{wal-maintenance-DLrbapzi.mjs → wal-maintenance-CaDsrJM_.mjs} +0 -0
- package/package.json +1 -1
- package/dist/builtins/system-config/cluster-secret-keeper.d.ts +0 -63
- package/dist/constants-DL87WgeN.js +0 -221
- package/dist/constants-DoiTA134.mjs +0 -102
- package/dist/kernel/moleculer/agent-mesh-authenticator.d.ts +0 -91
- package/dist/kernel/moleculer/cluster-secret.d.ts +0 -46
- package/dist/kernel/moleculer/mesh-auth-mode.d.ts +0 -58
- package/dist/kernel/moleculer/mesh-authenticator.d.ts +0 -77
- package/dist/kernel/moleculer/mesh-auto-enforce.d.ts +0 -46
- package/dist/kernel/moleculer/mesh-join-client.d.ts +0 -73
- package/dist/kernel/moleculer/mesh-join-hold.d.ts +0 -85
- package/dist/kernel/moleculer/mesh-join-proof.d.ts +0 -39
- package/dist/kernel/moleculer/mesh-mtls/mesh-enroll.d.ts +0 -34
- package/dist/kernel/moleculer/mesh-mtls/mesh-join-token.d.ts +0 -56
|
@@ -3,11 +3,11 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_chunk = require("../../chunk-Cek0wNdY.js");
|
|
6
|
-
const require_dist = require("../../dist-
|
|
6
|
+
const require_dist = require("../../dist-DVe0Nsp8.js");
|
|
7
7
|
const require_safe_buffer$1 = require("../../safe-buffer-D3aoa-7X.js");
|
|
8
8
|
const require_x509_es = require("../../x509.es-r7Ht1thA.js");
|
|
9
9
|
const require_agent_https = require("../../agent-https-BZIwS4xF.js");
|
|
10
|
-
const require_constants$8 = require("../../constants-
|
|
10
|
+
const require_constants$8 = require("../../constants-GENKqk9k.js");
|
|
11
11
|
const require_src$1 = require("../../src-CnAqG6EF.js");
|
|
12
12
|
let zod = require("zod");
|
|
13
13
|
let node_crypto = require("node:crypto");
|
|
@@ -106,73 +106,27 @@ function createCidrMatcher(entries) {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
//#endregion
|
|
109
|
-
//#region src/kernel/moleculer/mesh-auth-mode.ts
|
|
110
|
-
/** The field key inside the `cluster` section. */
|
|
111
|
-
var MESH_AUTH_MODE_FIELD = "meshAuth";
|
|
112
|
-
function isMeshAuthMode(value) {
|
|
113
|
-
return value === "transition" || value === "enforced";
|
|
114
|
-
}
|
|
115
|
-
/** A stored value that is not a mode reads as `transition`: never refuse on a typo. */
|
|
116
|
-
function parseMeshAuthMode(value) {
|
|
117
|
-
return isMeshAuthMode(value) ? value : "transition";
|
|
118
|
-
}
|
|
119
|
-
var MODE_SLOT = Symbol.for("camstack.cluster.mesh-auth-mode");
|
|
120
|
-
var ENFORCER_SLOT = Symbol.for("camstack.cluster.mesh-auth-enforcer");
|
|
121
|
-
var STATUS_SLOT = Symbol.for("camstack.cluster.mesh-auth-status");
|
|
122
|
-
/** Published by `system-config` whenever the stored mode is (re)read. */
|
|
123
|
-
function setProcessMeshAuthMode(mode) {
|
|
124
|
-
Reflect.set(globalThis, MODE_SLOT, mode);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* The hub's mode. Until `system-config` has read it: `transition` — the safe
|
|
128
|
-
* side for an upgrading cluster (nothing that worked before is refused), and
|
|
129
|
-
* exactly what an unread setting means.
|
|
130
|
-
*/
|
|
131
|
-
function getProcessMeshAuthMode() {
|
|
132
|
-
return parseMeshAuthMode(Reflect.get(globalThis, MODE_SLOT));
|
|
133
|
-
}
|
|
134
|
-
function setProcessMeshEnforcer(enforcer) {
|
|
135
|
-
if (enforcer === null) Reflect.deleteProperty(globalThis, ENFORCER_SLOT);
|
|
136
|
-
else Reflect.set(globalThis, ENFORCER_SLOT, enforcer);
|
|
137
|
-
}
|
|
138
|
-
/** Ask the owner of the setting to switch to `enforced`. `false` when nobody can. */
|
|
139
|
-
async function requestProcessMeshEnforcement(reason) {
|
|
140
|
-
const enforcer = Reflect.get(globalThis, ENFORCER_SLOT);
|
|
141
|
-
if (typeof enforcer !== "function") return false;
|
|
142
|
-
await enforcer(reason);
|
|
143
|
-
return true;
|
|
144
|
-
}
|
|
145
|
-
/** Published by the hub's broker; read by System → Cluster. */
|
|
146
|
-
function setProcessMeshAuthStatusSource(source) {
|
|
147
|
-
if (source === null) Reflect.deleteProperty(globalThis, STATUS_SLOT);
|
|
148
|
-
else Reflect.set(globalThis, STATUS_SLOT, source);
|
|
149
|
-
}
|
|
150
|
-
function getProcessMeshAuthStatus() {
|
|
151
|
-
const source = Reflect.get(globalThis, STATUS_SLOT);
|
|
152
|
-
return typeof source === "function" ? source() : null;
|
|
153
|
-
}
|
|
154
|
-
//#endregion
|
|
155
109
|
//#region src/kernel/moleculer/agent-ui-unlock.ts
|
|
156
110
|
/**
|
|
157
|
-
* Agent UI remote unlock tickets (D821).
|
|
111
|
+
* Agent UI remote unlock tickets (D821, re-keyed by D857).
|
|
158
112
|
*
|
|
159
|
-
* A hub admin mints a short-lived
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
113
|
+
* A hub admin mints a short-lived ticket bound to one agent `nodeId`, signed
|
|
114
|
+
* with the MESH CA key (ES256 JWS). The agent verifies it
|
|
115
|
+
* with the CA certificate it pinned at pairing and redeems it once for a tab
|
|
116
|
+
* session Bearer. There is no shared secret: a ticket is worth exactly as much
|
|
117
|
+
* as the CA key that signed it, and the agent trusts exactly the CA its
|
|
118
|
+
* operator confirmed during pairing.
|
|
163
119
|
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* payload = { v: 1, nodeId, exp (ms), jti }
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* D857 (transition release): a ticket signed by the MESH CA key (ES256 JWS) is accepted by an agent
|
|
172
|
-
* IN ADDITION to the HMAC ticket. The removal release mints only this form.
|
|
120
|
+
* ticket = b64url(header) '.' b64url(payload) '.' b64url(ES256 signature)
|
|
121
|
+
* header = { alg: 'ES256', typ: 'camstack-agent-ui-unlock+jwt' }
|
|
122
|
+
* payload = { v: 1, use: 'agent-ui-unlock', nodeId, iat (ms), exp (ms), jti }
|
|
123
|
+
*
|
|
124
|
+
* The `typ` and `use` pins keep a join token or a pairing proof (also signed
|
|
125
|
+
* by the CA key) from ever being accepted here, and the reverse.
|
|
173
126
|
*/
|
|
174
127
|
var AGENT_UI_UNLOCK_TYP = "camstack-agent-ui-unlock+jwt";
|
|
175
128
|
var AGENT_UI_UNLOCK_USE = "agent-ui-unlock";
|
|
129
|
+
var AGENT_UI_UNLOCK_VERSION = 1;
|
|
176
130
|
/** Ticket lifetime — long enough for a redirect hop, short enough to steal poorly. */
|
|
177
131
|
var AGENT_UI_UNLOCK_TTL_MS = 5 * 6e4;
|
|
178
132
|
/**
|
|
@@ -202,18 +156,28 @@ var UnlockTicketJtiStore = class {
|
|
|
202
156
|
for (const [jti, exp] of this.spent) if (exp <= nowMs) this.spent.delete(jti);
|
|
203
157
|
}
|
|
204
158
|
};
|
|
159
|
+
function b64urlJson$1(value) {
|
|
160
|
+
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
161
|
+
}
|
|
205
162
|
function mintAgentUiUnlockTicket(input) {
|
|
206
163
|
const nowMs = input.nowMs ?? Date.now();
|
|
207
164
|
const ttl = Math.min(Math.max(1e3, input.ttlMs ?? 3e5), AGENT_UI_UNLOCK_TTL_MS);
|
|
208
165
|
const payload = {
|
|
209
166
|
v: 1,
|
|
167
|
+
use: AGENT_UI_UNLOCK_USE,
|
|
210
168
|
nodeId: input.nodeId,
|
|
211
169
|
iat: nowMs,
|
|
212
170
|
exp: nowMs + ttl,
|
|
213
171
|
jti: input.jti ?? (0, node_crypto.randomBytes)(16).toString("base64url")
|
|
214
172
|
};
|
|
215
|
-
const
|
|
216
|
-
|
|
173
|
+
const signingInput = `${b64urlJson$1({
|
|
174
|
+
alg: "ES256",
|
|
175
|
+
typ: AGENT_UI_UNLOCK_TYP
|
|
176
|
+
})}.${b64urlJson$1(payload)}`;
|
|
177
|
+
return `${signingInput}.${(0, node_crypto.sign)("sha256", Buffer.from(signingInput, "utf8"), {
|
|
178
|
+
key: (0, node_crypto.createPrivateKey)(input.caKeyPem),
|
|
179
|
+
dsaEncoding: "ieee-p1363"
|
|
180
|
+
}).toString("base64url")}`;
|
|
217
181
|
}
|
|
218
182
|
/** A ticket is issued now-ish, lives at most the TTL, and not before `notBeforeMs`. */
|
|
219
183
|
function issuedSanely(payload, nowMs, notBeforeMs) {
|
|
@@ -222,22 +186,36 @@ function issuedSanely(payload, nowMs, notBeforeMs) {
|
|
|
222
186
|
return notBeforeMs === void 0 || payload.iat >= notBeforeMs;
|
|
223
187
|
}
|
|
224
188
|
/**
|
|
225
|
-
* Verify a ticket
|
|
226
|
-
* signature, shape, expiry or nodeId fails
|
|
189
|
+
* Verify a ticket against the mesh CA certificate the agent pinned. Returns the
|
|
190
|
+
* payload, or `null` when the signature, header, shape, expiry or nodeId fails
|
|
191
|
+
* (no reason string — refuse quietly).
|
|
227
192
|
*/
|
|
228
|
-
function verifyAgentUiUnlockTicket(
|
|
193
|
+
function verifyAgentUiUnlockTicket(caCertPem, ticket, options) {
|
|
229
194
|
const nowMs = options.nowMs ?? Date.now();
|
|
230
|
-
const
|
|
231
|
-
if (
|
|
232
|
-
const payloadB64 =
|
|
233
|
-
|
|
234
|
-
|
|
195
|
+
const parts = ticket.split(".");
|
|
196
|
+
if (parts.length !== 3) return null;
|
|
197
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
198
|
+
if (headerB64 === void 0 || payloadB64 === void 0 || signatureB64 === void 0) return null;
|
|
199
|
+
let header;
|
|
235
200
|
let parsed;
|
|
236
201
|
try {
|
|
202
|
+
header = JSON.parse(Buffer.from(headerB64, "base64url").toString("utf8"));
|
|
237
203
|
parsed = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
238
204
|
} catch {
|
|
239
205
|
return null;
|
|
240
206
|
}
|
|
207
|
+
if (typeof header !== "object" || header === null) return null;
|
|
208
|
+
if (Reflect.get(header, "alg") !== "ES256" || Reflect.get(header, "typ") !== "camstack-agent-ui-unlock+jwt") return null;
|
|
209
|
+
let valid = false;
|
|
210
|
+
try {
|
|
211
|
+
valid = (0, node_crypto.verify)("sha256", Buffer.from(`${headerB64}.${payloadB64}`, "utf8"), {
|
|
212
|
+
key: new node_crypto.X509Certificate(caCertPem).publicKey,
|
|
213
|
+
dsaEncoding: "ieee-p1363"
|
|
214
|
+
}, Buffer.from(signatureB64, "base64url"));
|
|
215
|
+
} catch {
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
if (!valid) return null;
|
|
241
219
|
const payload = parsePayload(parsed);
|
|
242
220
|
if (payload === null) return null;
|
|
243
221
|
if (payload.exp <= nowMs) return null;
|
|
@@ -296,96 +274,7 @@ function parseAgentDashboardOrigins(stored) {
|
|
|
296
274
|
}
|
|
297
275
|
return out;
|
|
298
276
|
}
|
|
299
|
-
function sign$1(secretHash, payloadB64) {
|
|
300
|
-
return (0, node_crypto.createHmac)("sha256", Buffer.from(secretHash, "utf8")).update(`${AGENT_UI_UNLOCK_DOMAIN}|${payloadB64}`, "utf8").digest("base64url");
|
|
301
|
-
}
|
|
302
|
-
function sigsEqual(expected, presented) {
|
|
303
|
-
const a = Buffer.from(expected, "utf8");
|
|
304
|
-
const b = Buffer.from(presented, "utf8");
|
|
305
|
-
if (a.length !== b.length) return false;
|
|
306
|
-
return (0, node_crypto.timingSafeEqual)(a, b);
|
|
307
|
-
}
|
|
308
277
|
function parsePayload(value) {
|
|
309
|
-
if (typeof value !== "object" || value === null) return null;
|
|
310
|
-
const rec = value;
|
|
311
|
-
if (rec["v"] !== 1) return null;
|
|
312
|
-
const nodeId = rec["nodeId"];
|
|
313
|
-
const exp = rec["exp"];
|
|
314
|
-
const jti = rec["jti"];
|
|
315
|
-
if (typeof nodeId !== "string" || nodeId.length === 0) return null;
|
|
316
|
-
if (typeof exp !== "number" || !Number.isFinite(exp)) return null;
|
|
317
|
-
if (typeof jti !== "string" || jti.length === 0) return null;
|
|
318
|
-
const iat = rec["iat"];
|
|
319
|
-
return {
|
|
320
|
-
v: 1,
|
|
321
|
-
nodeId,
|
|
322
|
-
iat: typeof iat === "number" && Number.isFinite(iat) ? iat : exp - AGENT_UI_UNLOCK_TTL_MS,
|
|
323
|
-
exp,
|
|
324
|
-
jti
|
|
325
|
-
};
|
|
326
|
-
}
|
|
327
|
-
function b64urlJsonEs256(value) {
|
|
328
|
-
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
329
|
-
}
|
|
330
|
-
function mintAgentUiUnlockTicketEs256(input) {
|
|
331
|
-
const nowMs = input.nowMs ?? Date.now();
|
|
332
|
-
const ttl = Math.min(Math.max(1e3, input.ttlMs ?? 3e5), AGENT_UI_UNLOCK_TTL_MS);
|
|
333
|
-
const payload = {
|
|
334
|
-
v: 1,
|
|
335
|
-
use: AGENT_UI_UNLOCK_USE,
|
|
336
|
-
nodeId: input.nodeId,
|
|
337
|
-
iat: nowMs,
|
|
338
|
-
exp: nowMs + ttl,
|
|
339
|
-
jti: input.jti ?? (0, node_crypto.randomBytes)(16).toString("base64url")
|
|
340
|
-
};
|
|
341
|
-
const signingInput = `${b64urlJsonEs256({
|
|
342
|
-
alg: "ES256",
|
|
343
|
-
typ: AGENT_UI_UNLOCK_TYP
|
|
344
|
-
})}.${b64urlJsonEs256(payload)}`;
|
|
345
|
-
return `${signingInput}.${(0, node_crypto.sign)("sha256", Buffer.from(signingInput, "utf8"), {
|
|
346
|
-
key: (0, node_crypto.createPrivateKey)(input.caKeyPem),
|
|
347
|
-
dsaEncoding: "ieee-p1363"
|
|
348
|
-
}).toString("base64url")}`;
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Verify a ticket against the mesh CA certificate the agent pinned. Returns the
|
|
352
|
-
* payload, or `null` when the signature, header, shape, expiry or nodeId fails
|
|
353
|
-
* (no reason string — refuse quietly).
|
|
354
|
-
*/
|
|
355
|
-
function verifyAgentUiUnlockTicketEs256(caCertPem, ticket, options) {
|
|
356
|
-
const nowMs = options.nowMs ?? Date.now();
|
|
357
|
-
const parts = ticket.split(".");
|
|
358
|
-
if (parts.length !== 3) return null;
|
|
359
|
-
const [headerB64, payloadB64, signatureB64] = parts;
|
|
360
|
-
if (headerB64 === void 0 || payloadB64 === void 0 || signatureB64 === void 0) return null;
|
|
361
|
-
let header;
|
|
362
|
-
let parsed;
|
|
363
|
-
try {
|
|
364
|
-
header = JSON.parse(Buffer.from(headerB64, "base64url").toString("utf8"));
|
|
365
|
-
parsed = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
366
|
-
} catch {
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
if (typeof header !== "object" || header === null) return null;
|
|
370
|
-
if (Reflect.get(header, "alg") !== "ES256" || Reflect.get(header, "typ") !== "camstack-agent-ui-unlock+jwt") return null;
|
|
371
|
-
let valid = false;
|
|
372
|
-
try {
|
|
373
|
-
valid = (0, node_crypto.verify)("sha256", Buffer.from(`${headerB64}.${payloadB64}`, "utf8"), {
|
|
374
|
-
key: new node_crypto.X509Certificate(caCertPem).publicKey,
|
|
375
|
-
dsaEncoding: "ieee-p1363"
|
|
376
|
-
}, Buffer.from(signatureB64, "base64url"));
|
|
377
|
-
} catch {
|
|
378
|
-
return null;
|
|
379
|
-
}
|
|
380
|
-
if (!valid) return null;
|
|
381
|
-
const payload = parsePayloadEs256(parsed);
|
|
382
|
-
if (payload === null) return null;
|
|
383
|
-
if (payload.exp <= nowMs) return null;
|
|
384
|
-
if (payload.nodeId !== options.expectedNodeId) return null;
|
|
385
|
-
if (!issuedSanely(payload, nowMs, options.notBeforeMs)) return null;
|
|
386
|
-
return payload;
|
|
387
|
-
}
|
|
388
|
-
function parsePayloadEs256(value) {
|
|
389
278
|
if (typeof value !== "object" || value === null) return null;
|
|
390
279
|
const rec = value;
|
|
391
280
|
if (rec["v"] !== 1) return null;
|
|
@@ -393,10 +282,10 @@ function parsePayloadEs256(value) {
|
|
|
393
282
|
const nodeId = rec["nodeId"];
|
|
394
283
|
const exp = rec["exp"];
|
|
395
284
|
const jti = rec["jti"];
|
|
285
|
+
const iat = rec["iat"];
|
|
396
286
|
if (typeof nodeId !== "string" || nodeId.length === 0) return null;
|
|
397
287
|
if (typeof exp !== "number" || !Number.isFinite(exp)) return null;
|
|
398
288
|
if (typeof jti !== "string" || jti.length === 0) return null;
|
|
399
|
-
const iat = rec["iat"];
|
|
400
289
|
if (typeof iat !== "number" || !Number.isFinite(iat)) return null;
|
|
401
290
|
return {
|
|
402
291
|
v: 1,
|
|
@@ -412,7 +301,7 @@ function parsePayloadEs256(value) {
|
|
|
412
301
|
* Hub mesh CA — EC P-256, key in the keychain, cert in `cluster.meshCa`.
|
|
413
302
|
*
|
|
414
303
|
* Distinct from the HTTPS local CA (`tls/cert-issue.ts`, RSA): the mesh CA
|
|
415
|
-
* signs node leaves (CN = nodeID) and
|
|
304
|
+
* signs node leaves (CN = nodeID) and unlock-ticket JWS (ES256). Issuance uses
|
|
416
305
|
* `@peculiar/x509` over WebCrypto — same library the HTTPS path already uses
|
|
417
306
|
* (installed `1.14.3`; registry latest at adoption time was `2.1.0` — stay on
|
|
418
307
|
* the pinned range already shipping).
|
|
@@ -453,7 +342,7 @@ async function exportKeyPem(key) {
|
|
|
453
342
|
function caFingerprint(certPem) {
|
|
454
343
|
return new node_crypto.X509Certificate(certPem).fingerprint256;
|
|
455
344
|
}
|
|
456
|
-
/** Compact fingerprint (lowercase hex, no colons)
|
|
345
|
+
/** Compact fingerprint (lowercase hex, no colons). */
|
|
457
346
|
function caFingerprintCompact(certPem) {
|
|
458
347
|
return (0, node_crypto.createHash)("sha256").update(new node_crypto.X509Certificate(certPem).raw).digest("hex");
|
|
459
348
|
}
|
|
@@ -1219,7 +1108,7 @@ function defaultSetTimer(fn, ms) {
|
|
|
1219
1108
|
function defaultSleep(ms) {
|
|
1220
1109
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1221
1110
|
}
|
|
1222
|
-
function message
|
|
1111
|
+
function message(error) {
|
|
1223
1112
|
return error instanceof Error ? error.message : String(error);
|
|
1224
1113
|
}
|
|
1225
1114
|
async function renewMeshCertificate(deps) {
|
|
@@ -1285,7 +1174,7 @@ async function runRenewal(deps, inFlight) {
|
|
|
1285
1174
|
csrPem = (await deps.client.prepareMeshRenewal()).csrPem;
|
|
1286
1175
|
log.info("Mesh renewal: the node generated a new key and sent its CSR", { tags });
|
|
1287
1176
|
} catch (error) {
|
|
1288
|
-
return fail("prepare", message
|
|
1177
|
+
return fail("prepare", message(error), true);
|
|
1289
1178
|
}
|
|
1290
1179
|
let issued;
|
|
1291
1180
|
try {
|
|
@@ -1299,7 +1188,7 @@ async function runRenewal(deps, inFlight) {
|
|
|
1299
1188
|
}
|
|
1300
1189
|
});
|
|
1301
1190
|
} catch (error) {
|
|
1302
|
-
return fail("issue", message
|
|
1191
|
+
return fail("issue", message(error), true);
|
|
1303
1192
|
}
|
|
1304
1193
|
const newLeaf = describeMeshLeaf(issued.certPem);
|
|
1305
1194
|
deps.registry.beginRenewal(newLeaf.fingerprint);
|
|
@@ -1339,7 +1228,7 @@ async function runRenewal(deps, inFlight) {
|
|
|
1339
1228
|
deadlineTimer.cancel();
|
|
1340
1229
|
await deps.client.rollbackMeshLeaf().catch(() => void 0);
|
|
1341
1230
|
await deps.registry.abandon(newLeaf.fingerprint);
|
|
1342
|
-
return fail("install", message
|
|
1231
|
+
return fail("install", message(error), true);
|
|
1343
1232
|
}
|
|
1344
1233
|
const deadline = now() + timeoutMs;
|
|
1345
1234
|
const registered = await registeredPromise;
|
|
@@ -1368,7 +1257,7 @@ async function runRenewal(deps, inFlight) {
|
|
|
1368
1257
|
}
|
|
1369
1258
|
confirmError = "the node did not confirm the new leaf";
|
|
1370
1259
|
} catch (error) {
|
|
1371
|
-
confirmError = message
|
|
1260
|
+
confirmError = message(error);
|
|
1372
1261
|
log.warn("Mesh renewal: confirm not accepted yet", {
|
|
1373
1262
|
tags,
|
|
1374
1263
|
meta: { error: confirmError }
|
|
@@ -1402,7 +1291,7 @@ async function runRenewal(deps, inFlight) {
|
|
|
1402
1291
|
}
|
|
1403
1292
|
/**
|
|
1404
1293
|
* Revoke every live mesh leaf of `nodeId` and cut its connection. The node cannot
|
|
1405
|
-
* reconnect: it must
|
|
1294
|
+
* reconnect: it must be paired again. The node is NOT forgotten
|
|
1406
1295
|
* (that stays `clusterNodes.forgetNode`).
|
|
1407
1296
|
*/
|
|
1408
1297
|
async function revokeMeshCertificate(deps) {
|
|
@@ -1429,7 +1318,7 @@ async function revokeMeshCertificate(deps) {
|
|
|
1429
1318
|
nodeId,
|
|
1430
1319
|
revokedSerials: serials,
|
|
1431
1320
|
disconnected,
|
|
1432
|
-
next: "The node can no longer connect.
|
|
1321
|
+
next: "The node can no longer connect. Pair it again from the hub (System -> Cluster -> Agents); to remove it from the cluster use Forget node."
|
|
1433
1322
|
};
|
|
1434
1323
|
}
|
|
1435
1324
|
//#endregion
|
|
@@ -1490,872 +1379,6 @@ function emitProcessNodeRegistered(nodeId, addonIds) {
|
|
|
1490
1379
|
} catch {}
|
|
1491
1380
|
}
|
|
1492
1381
|
//#endregion
|
|
1493
|
-
//#region ../../node_modules/jose/dist/webapi/lib/buffer_utils.js
|
|
1494
|
-
var encoder = new TextEncoder(), decoder = new TextDecoder(), strictDecoder = new TextDecoder("utf-8", { fatal: !0 });
|
|
1495
|
-
function concat(...buffers) {
|
|
1496
|
-
const size = buffers.reduce((acc, { length }) => acc + length, 0), buf = new Uint8Array(size);
|
|
1497
|
-
let i = 0;
|
|
1498
|
-
for (const buffer of buffers) buf.set(buffer, i), i += buffer.length;
|
|
1499
|
-
return buf;
|
|
1500
|
-
}
|
|
1501
|
-
var NON_ASCII = /[^\x00-\x7f]/;
|
|
1502
|
-
function encode$1(string) {
|
|
1503
|
-
if (typeof string == "string" && string.length >= 128) {
|
|
1504
|
-
if (NON_ASCII.test(string)) throw new TypeError("non-ASCII string encountered in encode()");
|
|
1505
|
-
return encoder.encode(string);
|
|
1506
|
-
}
|
|
1507
|
-
const bytes = new Uint8Array(string.length);
|
|
1508
|
-
for (let i = 0; i < string.length; i++) {
|
|
1509
|
-
const code = string.charCodeAt(i);
|
|
1510
|
-
if (code > 127) throw new TypeError("non-ASCII string encountered in encode()");
|
|
1511
|
-
bytes[i] = code;
|
|
1512
|
-
}
|
|
1513
|
-
return bytes;
|
|
1514
|
-
}
|
|
1515
|
-
function encodeBase64(input, url = !1) {
|
|
1516
|
-
if (Uint8Array.prototype.toBase64) return input.toBase64({
|
|
1517
|
-
alphabet: url ? "base64url" : "base64",
|
|
1518
|
-
omitPadding: url
|
|
1519
|
-
});
|
|
1520
|
-
const CHUNK_SIZE = 32768, arr = [];
|
|
1521
|
-
for (let i = 0; i < input.length; i += CHUNK_SIZE) arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
|
|
1522
|
-
const encoded = btoa(arr.join(""));
|
|
1523
|
-
return url ? encoded.replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_") : encoded;
|
|
1524
|
-
}
|
|
1525
|
-
function decodeBase64(encoded, url = !1) {
|
|
1526
|
-
if (Uint8Array.fromBase64) return Uint8Array.fromBase64(encoded, { alphabet: url ? "base64url" : "base64" });
|
|
1527
|
-
if (url) {
|
|
1528
|
-
if (encoded.includes("+") || encoded.includes("/")) throw new TypeError("Invalid base64url");
|
|
1529
|
-
encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
1530
|
-
}
|
|
1531
|
-
const binary = atob(encoded), bytes = new Uint8Array(binary.length);
|
|
1532
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
1533
|
-
return bytes;
|
|
1534
|
-
}
|
|
1535
|
-
//#endregion
|
|
1536
|
-
//#region ../../node_modules/jose/dist/webapi/util/errors.js
|
|
1537
|
-
var JOSEError = class extends Error {
|
|
1538
|
-
static code = "ERR_JOSE_GENERIC";
|
|
1539
|
-
code = "ERR_JOSE_GENERIC";
|
|
1540
|
-
constructor(message, options) {
|
|
1541
|
-
super(message, options), this.name = this.constructor.name, Error.captureStackTrace?.(this, this.constructor);
|
|
1542
|
-
}
|
|
1543
|
-
};
|
|
1544
|
-
var JWTClaimValidationFailed = class extends JOSEError {
|
|
1545
|
-
static code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
1546
|
-
code = "ERR_JWT_CLAIM_VALIDATION_FAILED";
|
|
1547
|
-
claim;
|
|
1548
|
-
reason;
|
|
1549
|
-
payload;
|
|
1550
|
-
constructor(message, payload, claim = "unspecified", reason = "unspecified") {
|
|
1551
|
-
super(message, { cause: {
|
|
1552
|
-
claim,
|
|
1553
|
-
reason,
|
|
1554
|
-
payload
|
|
1555
|
-
} }), this.claim = claim, this.reason = reason, this.payload = payload;
|
|
1556
|
-
}
|
|
1557
|
-
};
|
|
1558
|
-
var JWTExpired = class extends JOSEError {
|
|
1559
|
-
static code = "ERR_JWT_EXPIRED";
|
|
1560
|
-
code = "ERR_JWT_EXPIRED";
|
|
1561
|
-
claim;
|
|
1562
|
-
reason;
|
|
1563
|
-
payload;
|
|
1564
|
-
constructor(message, payload, claim = "unspecified", reason = "unspecified") {
|
|
1565
|
-
super(message, { cause: {
|
|
1566
|
-
claim,
|
|
1567
|
-
reason,
|
|
1568
|
-
payload
|
|
1569
|
-
} }), this.claim = claim, this.reason = reason, this.payload = payload;
|
|
1570
|
-
}
|
|
1571
|
-
};
|
|
1572
|
-
var JOSEAlgNotAllowed = class extends JOSEError {
|
|
1573
|
-
static code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
1574
|
-
code = "ERR_JOSE_ALG_NOT_ALLOWED";
|
|
1575
|
-
};
|
|
1576
|
-
var JOSENotSupported = class extends JOSEError {
|
|
1577
|
-
static code = "ERR_JOSE_NOT_SUPPORTED";
|
|
1578
|
-
code = "ERR_JOSE_NOT_SUPPORTED";
|
|
1579
|
-
};
|
|
1580
|
-
var JWSInvalid = class extends JOSEError {
|
|
1581
|
-
static code = "ERR_JWS_INVALID";
|
|
1582
|
-
code = "ERR_JWS_INVALID";
|
|
1583
|
-
};
|
|
1584
|
-
var JWTInvalid = class extends JOSEError {
|
|
1585
|
-
static code = "ERR_JWT_INVALID";
|
|
1586
|
-
code = "ERR_JWT_INVALID";
|
|
1587
|
-
};
|
|
1588
|
-
var JWSSignatureVerificationFailed = class extends JOSEError {
|
|
1589
|
-
static code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
1590
|
-
code = "ERR_JWS_SIGNATURE_VERIFICATION_FAILED";
|
|
1591
|
-
constructor(message = "signature verification failed", options) {
|
|
1592
|
-
super(message, options);
|
|
1593
|
-
}
|
|
1594
|
-
};
|
|
1595
|
-
//#endregion
|
|
1596
|
-
//#region ../../node_modules/jose/dist/webapi/util/base64url.js
|
|
1597
|
-
var invalid = "The input to be decoded is not correctly encoded.";
|
|
1598
|
-
function decode(input) {
|
|
1599
|
-
try {
|
|
1600
|
-
return decodeBase64(typeof input == "string" ? input : decoder.decode(input), !0);
|
|
1601
|
-
} catch (cause) {
|
|
1602
|
-
throw new TypeError(invalid, { cause });
|
|
1603
|
-
}
|
|
1604
|
-
}
|
|
1605
|
-
function encode(input) {
|
|
1606
|
-
return encodeBase64(typeof input == "string" ? encoder.encode(input) : input, !0);
|
|
1607
|
-
}
|
|
1608
|
-
//#endregion
|
|
1609
|
-
//#region ../../node_modules/jose/dist/webapi/lib/validate.js
|
|
1610
|
-
function isObject$1(input) {
|
|
1611
|
-
if (typeof input != "object" || input === null || Object.prototype.toString.call(input) !== "[object Object]") return !1;
|
|
1612
|
-
const prototype = Object.getPrototypeOf(input);
|
|
1613
|
-
return prototype === null || Object.getPrototypeOf(prototype) === null;
|
|
1614
|
-
}
|
|
1615
|
-
function isDisjoint(...headers) {
|
|
1616
|
-
const parameters = /* @__PURE__ */ new Set();
|
|
1617
|
-
for (const header of headers) if (header) for (const parameter of Object.keys(header)) {
|
|
1618
|
-
if (parameters.has(parameter)) return !1;
|
|
1619
|
-
parameters.add(parameter);
|
|
1620
|
-
}
|
|
1621
|
-
return !0;
|
|
1622
|
-
}
|
|
1623
|
-
function assertNotSet(value, name) {
|
|
1624
|
-
if (value !== void 0) throw new TypeError(`${name} can only be called once`);
|
|
1625
|
-
}
|
|
1626
|
-
function decodeBase64url(value, label, ErrorClass) {
|
|
1627
|
-
try {
|
|
1628
|
-
return decode(value);
|
|
1629
|
-
} catch {
|
|
1630
|
-
throw new ErrorClass(`Failed to base64url decode the ${label}`);
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
function encodeBase64url(value, label, ErrorClass) {
|
|
1634
|
-
try {
|
|
1635
|
-
return encode$1(value);
|
|
1636
|
-
} catch {
|
|
1637
|
-
throw new ErrorClass(`The ${label} is not a valid base64url string`);
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
function parseJoseHeader(b64, ErrorClass, message) {
|
|
1641
|
-
let parsed;
|
|
1642
|
-
try {
|
|
1643
|
-
parsed = JSON.parse(strictDecoder.decode(decode(b64)));
|
|
1644
|
-
} catch {
|
|
1645
|
-
throw new ErrorClass(message);
|
|
1646
|
-
}
|
|
1647
|
-
if (!isObject$1(parsed)) throw new ErrorClass(message);
|
|
1648
|
-
return parsed;
|
|
1649
|
-
}
|
|
1650
|
-
var JWS_RECOGNIZED = {
|
|
1651
|
-
__proto__: null,
|
|
1652
|
-
b64: !0
|
|
1653
|
-
};
|
|
1654
|
-
function validateAlgorithms(option, algorithms) {
|
|
1655
|
-
if (algorithms !== void 0 && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s != "string"))) throw new TypeError(`"${option}" option must be an array of strings`);
|
|
1656
|
-
return algorithms === void 0 ? void 0 : new Set(algorithms);
|
|
1657
|
-
}
|
|
1658
|
-
function validateCritDuplicates(Err, protectedHeader) {
|
|
1659
|
-
const { crit } = protectedHeader ?? {};
|
|
1660
|
-
if (Array.isArray(crit) && new Set(crit).size !== crit.length) throw new Err("\"crit\" (Critical) Header Parameter MUST NOT contain duplicate values");
|
|
1661
|
-
}
|
|
1662
|
-
function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
|
|
1663
|
-
if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) throw new Err("\"crit\" (Critical) Header Parameter MUST be integrity protected");
|
|
1664
|
-
if (!protectedHeader || protectedHeader.crit === void 0) return [];
|
|
1665
|
-
if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input != "string" || input.length === 0)) throw new Err("\"crit\" (Critical) Header Parameter MUST be an array of non-empty strings when present");
|
|
1666
|
-
const recognized = recognizedOption === void 0 ? recognizedDefault : {
|
|
1667
|
-
__proto__: null,
|
|
1668
|
-
...recognizedOption,
|
|
1669
|
-
...recognizedDefault
|
|
1670
|
-
};
|
|
1671
|
-
for (const parameter of protectedHeader.crit) {
|
|
1672
|
-
if (!(parameter in recognized)) throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
|
|
1673
|
-
if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === void 0) throw new Err(`Extension Header Parameter "${parameter}" is missing`);
|
|
1674
|
-
if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === void 0)) throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
|
|
1675
|
-
}
|
|
1676
|
-
return protectedHeader.crit;
|
|
1677
|
-
}
|
|
1678
|
-
function validateB64(protectedHeader, extensions) {
|
|
1679
|
-
if (extensions.includes("b64")) {
|
|
1680
|
-
const b64 = protectedHeader.b64;
|
|
1681
|
-
if (typeof b64 != "boolean") throw new JWSInvalid("The \"b64\" (base64url-encode payload) Header Parameter must be a boolean");
|
|
1682
|
-
return b64;
|
|
1683
|
-
}
|
|
1684
|
-
return !0;
|
|
1685
|
-
}
|
|
1686
|
-
function serializeJoseHeader(Err, header) {
|
|
1687
|
-
let serialized, parsed;
|
|
1688
|
-
try {
|
|
1689
|
-
serialized = JSON.stringify(header), parsed = JSON.parse(serialized);
|
|
1690
|
-
} catch (cause) {
|
|
1691
|
-
throw new Err("JOSE Header is not valid JSON", { cause });
|
|
1692
|
-
}
|
|
1693
|
-
if (!isObject$1(parsed)) throw new Err("JOSE Header is not a JSON object");
|
|
1694
|
-
return [parsed, serialized];
|
|
1695
|
-
}
|
|
1696
|
-
//#endregion
|
|
1697
|
-
//#region ../../node_modules/jose/dist/webapi/lib/key.js
|
|
1698
|
-
var tag = (key) => key[Symbol.toStringTag], jwkMatchesOp = (entry, key, usage) => {
|
|
1699
|
-
const { alg } = entry;
|
|
1700
|
-
if (key.use !== void 0) {
|
|
1701
|
-
const expected = usage === "sign" || usage === "verify" ? "sig" : "enc";
|
|
1702
|
-
if (key.use !== expected) throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
|
|
1703
|
-
}
|
|
1704
|
-
if (key.alg !== void 0 && key.alg !== alg) throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
|
|
1705
|
-
if (Array.isArray(key.key_ops)) {
|
|
1706
|
-
const expectedKeyOp = usage === "encrypt" || usage === "decrypt" ? entry.ops?.[usage === "encrypt" ? 0 : 1] : usage;
|
|
1707
|
-
if (expectedKeyOp && !key.key_ops.includes(expectedKeyOp)) throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
|
|
1708
|
-
}
|
|
1709
|
-
};
|
|
1710
|
-
async function prepareKey(entry, key, usage) {
|
|
1711
|
-
const { alg, secret } = entry, privateKey = usage === "decrypt" || usage === "sign";
|
|
1712
|
-
if (secret && key instanceof Uint8Array) return key;
|
|
1713
|
-
let normalized, keyObject;
|
|
1714
|
-
if (isObject$1(key)) {
|
|
1715
|
-
if (normalized = normalizeJwk(key), typeof normalized.kty != "string") throw invalidKeyType(alg, key, secret);
|
|
1716
|
-
if (!(secret ? normalized.kty === "oct" && typeof normalized.k == "string" : normalized.kty !== "oct" && (privateKey ? normalized.kty === "AKP" && typeof normalized.priv == "string" || typeof normalized.d == "string" : normalized.d === void 0 && normalized.priv === void 0))) throw new TypeError(secret ? "JSON Web Key for symmetric algorithms must have JWK \"kty\" (Key Type) equal to \"oct\" and the JWK \"k\" (Key Value) present" : `JSON Web Key for this operation must be a ${privateKey ? "private" : "public"} JWK`);
|
|
1717
|
-
if (jwkMatchesOp(entry, normalized, usage), normalized.kty === "oct") return decode(normalized.k);
|
|
1718
|
-
if (!Object.isFrozen(key)) {
|
|
1719
|
-
const { key_ops } = key;
|
|
1720
|
-
Array.isArray(key_ops) && Object.freeze(key_ops), Object.freeze(key);
|
|
1721
|
-
}
|
|
1722
|
-
} else {
|
|
1723
|
-
if (!isKeyLike(key)) throw invalidKeyType(alg, key, secret);
|
|
1724
|
-
const expectedType = secret ? "secret" : privateKey ? "private" : "public";
|
|
1725
|
-
if (key.type !== expectedType && (secret || [
|
|
1726
|
-
"secret",
|
|
1727
|
-
"public",
|
|
1728
|
-
"private"
|
|
1729
|
-
].includes(key.type))) throw new TypeError(`${tag(key)} instances must be of type "${expectedType}" for the ${alg} algorithm`);
|
|
1730
|
-
if (isCryptoKey(key)) return key;
|
|
1731
|
-
if (keyObject = key, keyObject.type === "secret") return keyObject.export();
|
|
1732
|
-
}
|
|
1733
|
-
cache ||= /* @__PURE__ */ new WeakMap();
|
|
1734
|
-
const cacheKey = key;
|
|
1735
|
-
let cached = cache.get(cacheKey);
|
|
1736
|
-
if (cached?.[alg]) return cached[alg];
|
|
1737
|
-
if (cached || cache.set(cacheKey, cached = {}), keyObject && typeof keyObject.toCryptoKey == "function") {
|
|
1738
|
-
const isPublic = keyObject.type === "public", crv = nist[keyObject.asymmetricKeyDetails?.namedCurve], params = entry.resolve?.({
|
|
1739
|
-
crv,
|
|
1740
|
-
asymmetricKeyType: keyObject.asymmetricKeyType
|
|
1741
|
-
}) ?? entry.subtle;
|
|
1742
|
-
return cached[alg] = keyObject.toCryptoKey(params, isPublic, entry.usages[isPublic ? 0 : 1]);
|
|
1743
|
-
}
|
|
1744
|
-
return normalized ??= keyObject.export({ format: "jwk" }), normalized.alg = alg, cached[alg] = await jwkToKey(entry, normalized);
|
|
1745
|
-
}
|
|
1746
|
-
var cache;
|
|
1747
|
-
var nist = {
|
|
1748
|
-
__proto__: null,
|
|
1749
|
-
prime256v1: "P-256",
|
|
1750
|
-
secp384r1: "P-384",
|
|
1751
|
-
secp521r1: "P-521"
|
|
1752
|
-
};
|
|
1753
|
-
var isCryptoKey = (key) => {
|
|
1754
|
-
if (key?.[Symbol.toStringTag] === "CryptoKey") return !0;
|
|
1755
|
-
try {
|
|
1756
|
-
return key instanceof CryptoKey;
|
|
1757
|
-
} catch {
|
|
1758
|
-
return !1;
|
|
1759
|
-
}
|
|
1760
|
-
}, isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject", isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
|
|
1761
|
-
function message(msg, actual, ...types) {
|
|
1762
|
-
if (types.length > 2) {
|
|
1763
|
-
const last = types.pop();
|
|
1764
|
-
msg += `one of type ${types.join(", ")}, or ${last}.`;
|
|
1765
|
-
} else types.length === 2 ? msg += `one of type ${types[0]} or ${types[1]}.` : msg += `of type ${types[0]}.`;
|
|
1766
|
-
return actual == null ? msg += ` Received ${actual}` : typeof actual == "function" && actual.name ? msg += ` Received function ${actual.name}` : typeof actual == "object" && actual != null && actual.constructor?.name && (msg += ` Received an instance of ${actual.constructor.name}`), msg;
|
|
1767
|
-
}
|
|
1768
|
-
function invalidKeyType(alg, actual, secret) {
|
|
1769
|
-
const types = [
|
|
1770
|
-
"CryptoKey",
|
|
1771
|
-
"KeyObject",
|
|
1772
|
-
"JSON Web Key"
|
|
1773
|
-
];
|
|
1774
|
-
return secret && types.push("Uint8Array"), new TypeError(message(`Key for the ${alg} algorithm must be `, actual, ...types));
|
|
1775
|
-
}
|
|
1776
|
-
var unusable = (name, prop = "algorithm.name") => /* @__PURE__ */ new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
|
|
1777
|
-
function checkUsage(key, usage) {
|
|
1778
|
-
if (usage && !key.usages.includes(usage)) throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
|
|
1779
|
-
}
|
|
1780
|
-
function checkModulusLength(alg, key) {
|
|
1781
|
-
const { modulusLength } = key.algorithm;
|
|
1782
|
-
if (typeof modulusLength != "number" || modulusLength < 2048) throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
|
|
1783
|
-
}
|
|
1784
|
-
function checkCryptoKey(key, expected, usage) {
|
|
1785
|
-
const algorithm = key.algorithm;
|
|
1786
|
-
if (algorithm.name !== expected.name) throw unusable(expected.name);
|
|
1787
|
-
if (expected.hash && algorithm.hash?.name !== expected.hash) throw unusable(expected.hash, "algorithm.hash");
|
|
1788
|
-
if (expected.namedCurve && algorithm.namedCurve !== expected.namedCurve) throw unusable(expected.namedCurve, "algorithm.namedCurve");
|
|
1789
|
-
if (expected.length !== void 0 && algorithm.length !== expected.length) throw unusable(expected.length, "algorithm.length");
|
|
1790
|
-
checkUsage(key, usage);
|
|
1791
|
-
}
|
|
1792
|
-
function snapshotJwk(jwk) {
|
|
1793
|
-
return {
|
|
1794
|
-
__proto__: null,
|
|
1795
|
-
...jwk
|
|
1796
|
-
};
|
|
1797
|
-
}
|
|
1798
|
-
function normalizeJwk(jwk) {
|
|
1799
|
-
const normalized = snapshotJwk(jwk);
|
|
1800
|
-
if (normalized.ext !== void 0 && typeof normalized.ext != "boolean") throw new TypeError("\"ext\" (Extractable) Parameter must be a boolean");
|
|
1801
|
-
if (normalized.key_ops !== void 0) {
|
|
1802
|
-
const value = normalized.key_ops, keyOps = Array.isArray(value) ? [...value] : void 0;
|
|
1803
|
-
if (!keyOps || keyOps.some((operation) => typeof operation != "string") || new Set(keyOps).size !== keyOps.length) throw new TypeError("\"key_ops\" (Key Operations) Parameter must be an array of unique strings");
|
|
1804
|
-
normalized.key_ops = keyOps;
|
|
1805
|
-
}
|
|
1806
|
-
return normalized;
|
|
1807
|
-
}
|
|
1808
|
-
async function jwkToKey(entry, jwk, extractable) {
|
|
1809
|
-
if (!entry.kty.includes(jwk.kty)) throw new JOSENotSupported("Invalid or unsupported JWK \"alg\" (Algorithm) Parameter value");
|
|
1810
|
-
const algorithm = entry.resolve?.({
|
|
1811
|
-
kty: jwk.kty,
|
|
1812
|
-
crv: jwk.crv
|
|
1813
|
-
}) ?? entry.subtle, isPrivate = !!(jwk.d || jwk.priv), keyData = {
|
|
1814
|
-
...jwk,
|
|
1815
|
-
ext: extractable ?? jwk.ext
|
|
1816
|
-
};
|
|
1817
|
-
return keyData.kty !== "AKP" && delete keyData.alg, delete keyData.use, crypto.subtle.importKey("jwk", keyData, algorithm, keyData.ext ?? !isPrivate, jwk.key_ops ?? entry.usages[isPrivate ? 1 : 0]);
|
|
1818
|
-
}
|
|
1819
|
-
async function rawKey(key, expected, usage, extractable = !1) {
|
|
1820
|
-
return key instanceof Uint8Array && (key = await crypto.subtle.importKey("raw", key, expected, extractable, [usage])), checkCryptoKey(key, expected, usage), key;
|
|
1821
|
-
}
|
|
1822
|
-
//#endregion
|
|
1823
|
-
//#region ../../node_modules/jose/dist/webapi/lib/key_descriptor.js
|
|
1824
|
-
function table(entries) {
|
|
1825
|
-
const out = { __proto__: null };
|
|
1826
|
-
for (const alg in entries) out[alg] = {
|
|
1827
|
-
...entries[alg],
|
|
1828
|
-
alg
|
|
1829
|
-
};
|
|
1830
|
-
return out;
|
|
1831
|
-
}
|
|
1832
|
-
//#endregion
|
|
1833
|
-
//#region ../../node_modules/jose/dist/webapi/lib/jws_algorithms.js
|
|
1834
|
-
var sig = [["verify"], ["sign"]];
|
|
1835
|
-
function hmac(bits) {
|
|
1836
|
-
const subtle = {
|
|
1837
|
-
name: "HMAC",
|
|
1838
|
-
hash: `SHA-${bits}`
|
|
1839
|
-
};
|
|
1840
|
-
return {
|
|
1841
|
-
kty: ["oct"],
|
|
1842
|
-
secret: !0,
|
|
1843
|
-
subtle,
|
|
1844
|
-
signing: subtle,
|
|
1845
|
-
usages: sig
|
|
1846
|
-
};
|
|
1847
|
-
}
|
|
1848
|
-
function rsa(bits, saltLength) {
|
|
1849
|
-
const subtle = {
|
|
1850
|
-
name: saltLength ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
1851
|
-
hash: `SHA-${bits}`
|
|
1852
|
-
};
|
|
1853
|
-
return {
|
|
1854
|
-
kty: ["RSA"],
|
|
1855
|
-
subtle,
|
|
1856
|
-
signing: saltLength ? {
|
|
1857
|
-
...subtle,
|
|
1858
|
-
saltLength
|
|
1859
|
-
} : subtle,
|
|
1860
|
-
usages: sig,
|
|
1861
|
-
minRsaBits: 2048
|
|
1862
|
-
};
|
|
1863
|
-
}
|
|
1864
|
-
function ecdsa(crv, bits) {
|
|
1865
|
-
return {
|
|
1866
|
-
kty: ["EC"],
|
|
1867
|
-
crv,
|
|
1868
|
-
subtle: {
|
|
1869
|
-
name: "ECDSA",
|
|
1870
|
-
namedCurve: crv
|
|
1871
|
-
},
|
|
1872
|
-
signing: {
|
|
1873
|
-
name: "ECDSA",
|
|
1874
|
-
hash: `SHA-${bits}`
|
|
1875
|
-
},
|
|
1876
|
-
usages: sig
|
|
1877
|
-
};
|
|
1878
|
-
}
|
|
1879
|
-
function eddsa() {
|
|
1880
|
-
const subtle = { name: "Ed25519" };
|
|
1881
|
-
return {
|
|
1882
|
-
kty: ["OKP"],
|
|
1883
|
-
crv: "Ed25519",
|
|
1884
|
-
subtle,
|
|
1885
|
-
signing: subtle,
|
|
1886
|
-
usages: sig
|
|
1887
|
-
};
|
|
1888
|
-
}
|
|
1889
|
-
function mldsa(bits) {
|
|
1890
|
-
const subtle = { name: `ML-DSA-${bits}` };
|
|
1891
|
-
return {
|
|
1892
|
-
kty: ["AKP"],
|
|
1893
|
-
subtle,
|
|
1894
|
-
signing: subtle,
|
|
1895
|
-
usages: sig
|
|
1896
|
-
};
|
|
1897
|
-
}
|
|
1898
|
-
var JWS = table({
|
|
1899
|
-
HS256: hmac(256),
|
|
1900
|
-
HS384: hmac(384),
|
|
1901
|
-
HS512: hmac(512),
|
|
1902
|
-
RS256: rsa(256),
|
|
1903
|
-
RS384: rsa(384),
|
|
1904
|
-
RS512: rsa(512),
|
|
1905
|
-
PS256: rsa(256, 32),
|
|
1906
|
-
PS384: rsa(384, 48),
|
|
1907
|
-
PS512: rsa(512, 64),
|
|
1908
|
-
ES256: ecdsa("P-256", 256),
|
|
1909
|
-
ES384: ecdsa("P-384", 384),
|
|
1910
|
-
ES512: ecdsa("P-521", 512),
|
|
1911
|
-
EdDSA: eddsa(),
|
|
1912
|
-
Ed25519: eddsa(),
|
|
1913
|
-
"ML-DSA-44": mldsa(44),
|
|
1914
|
-
"ML-DSA-65": mldsa(65),
|
|
1915
|
-
"ML-DSA-87": mldsa(87)
|
|
1916
|
-
});
|
|
1917
|
-
function jwsAlgorithm(alg) {
|
|
1918
|
-
const entry = typeof alg == "string" ? JWS[alg] : void 0;
|
|
1919
|
-
if (!entry) throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
|
|
1920
|
-
return entry;
|
|
1921
|
-
}
|
|
1922
|
-
//#endregion
|
|
1923
|
-
//#region ../../node_modules/jose/dist/webapi/lib/jws_verify.js
|
|
1924
|
-
function prepareVerify(options) {
|
|
1925
|
-
return [options && validateAlgorithms("algorithms", options.algorithms), options?.crit];
|
|
1926
|
-
}
|
|
1927
|
-
function parseProtectedHeader(encodedProtected) {
|
|
1928
|
-
return encodedProtected === void 0 ? {} : parseJoseHeader(encodedProtected, JWSInvalid, "JWS Protected Header is invalid");
|
|
1929
|
-
}
|
|
1930
|
-
function encodeCompactUnencodedPayload(payload) {
|
|
1931
|
-
try {
|
|
1932
|
-
return encode$1(payload);
|
|
1933
|
-
} catch {
|
|
1934
|
-
throw new JWSInvalid("JWS Compact Serialization payload must use only ASCII characters");
|
|
1935
|
-
}
|
|
1936
|
-
}
|
|
1937
|
-
async function verifySignature(jws, shared, key, encodeUnencodedPayload, parsedProtected) {
|
|
1938
|
-
const { protected: encodedProtected, header, payload: inputPayload } = jws, parsedProt = parsedProtected ?? parseProtectedHeader(encodedProtected);
|
|
1939
|
-
if (!isDisjoint(parsedProt, header)) throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
1940
|
-
const joseHeader = {
|
|
1941
|
-
...parsedProt,
|
|
1942
|
-
...header
|
|
1943
|
-
}, b64 = validateB64(parsedProt, validateCrit(JWSInvalid, JWS_RECOGNIZED, shared[1], parsedProt, joseHeader)), { alg } = joseHeader;
|
|
1944
|
-
if (typeof alg != "string" || !alg) throw new JWSInvalid("JWS \"alg\" (Algorithm) Header Parameter missing or invalid");
|
|
1945
|
-
if (shared[0] && !shared[0].has(alg)) throw new JOSEAlgNotAllowed("\"alg\" (Algorithm) Header Parameter value not allowed");
|
|
1946
|
-
if (b64) {
|
|
1947
|
-
if (typeof inputPayload != "string") throw new JWSInvalid("JWS Payload must be a string");
|
|
1948
|
-
} else if (typeof inputPayload != "string" && !(inputPayload instanceof Uint8Array)) throw new JWSInvalid("JWS Payload must be a string or an Uint8Array instance");
|
|
1949
|
-
const signingPayload = b64 || typeof inputPayload != "string" ? inputPayload : encodeUnencodedPayload(inputPayload);
|
|
1950
|
-
let resolvedKey = !1;
|
|
1951
|
-
typeof key == "function" && (key = await key(parsedProt, jws), resolvedKey = !0);
|
|
1952
|
-
const entry = jwsAlgorithm(alg), data = concat(encodedProtected !== void 0 ? encode$1(encodedProtected) : new Uint8Array(), encode$1("."), typeof signingPayload == "string" ? shared[2] ??= encodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload), signature = decodeBase64url(jws.signature, "signature", JWSInvalid), k = await prepareKey(entry, key, "verify"), cryptoKey = await rawKey(k, entry.subtle, "verify");
|
|
1953
|
-
entry.minRsaBits && checkModulusLength(entry.alg, cryptoKey);
|
|
1954
|
-
let verified = !1;
|
|
1955
|
-
try {
|
|
1956
|
-
verified = await crypto.subtle.verify(entry.signing, cryptoKey, signature, data);
|
|
1957
|
-
} catch {}
|
|
1958
|
-
if (!verified) throw new JWSSignatureVerificationFailed();
|
|
1959
|
-
const result = { payload: typeof signingPayload == "string" ? decodeBase64url(signingPayload, "payload", JWSInvalid) : signingPayload };
|
|
1960
|
-
return encodedProtected !== void 0 && (result.protectedHeader = parsedProt), header !== void 0 && (result.unprotectedHeader = header), resolvedKey ? [{
|
|
1961
|
-
...result,
|
|
1962
|
-
key: k
|
|
1963
|
-
}, b64] : [result, b64];
|
|
1964
|
-
}
|
|
1965
|
-
async function verifyCompact(jws, shared, key) {
|
|
1966
|
-
if (jws instanceof Uint8Array && (jws = decoder.decode(jws)), typeof jws != "string") throw new JWSInvalid("Compact JWS must be a string or Uint8Array");
|
|
1967
|
-
const { 0: protectedHeader, 1: payload, 2: signature, length } = jws.split(".");
|
|
1968
|
-
if (length !== 3) throw new JWSInvalid("Invalid Compact JWS");
|
|
1969
|
-
return verifySignature({
|
|
1970
|
-
payload,
|
|
1971
|
-
protected: protectedHeader,
|
|
1972
|
-
signature
|
|
1973
|
-
}, shared, key, encodeCompactUnencodedPayload);
|
|
1974
|
-
}
|
|
1975
|
-
//#endregion
|
|
1976
|
-
//#region ../../node_modules/jose/dist/webapi/lib/jwt_claims_set.js
|
|
1977
|
-
var epoch = (date) => Math.floor(date.getTime() / 1e3), multipliers = {
|
|
1978
|
-
s: 1,
|
|
1979
|
-
m: 60,
|
|
1980
|
-
h: 3600,
|
|
1981
|
-
d: 86400,
|
|
1982
|
-
w: 604800,
|
|
1983
|
-
y: 31557600
|
|
1984
|
-
}, REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i, checkFailed = "check_failed";
|
|
1985
|
-
function invalidDuration() {
|
|
1986
|
-
throw new TypeError("Invalid time period format");
|
|
1987
|
-
}
|
|
1988
|
-
function secs(str) {
|
|
1989
|
-
typeof str != "string" && invalidDuration();
|
|
1990
|
-
const matched = REGEX.exec(str);
|
|
1991
|
-
(!matched || matched[4] && matched[1]) && invalidDuration();
|
|
1992
|
-
const value = parseFloat(matched[2]), numericDate2 = Math.round(value * multipliers[matched[3][0].toLowerCase()]);
|
|
1993
|
-
return Number.isFinite(numericDate2) || invalidDuration(), matched[1] === "-" || matched[4] === "ago" ? -numericDate2 : numericDate2;
|
|
1994
|
-
}
|
|
1995
|
-
function validateInput(label, input) {
|
|
1996
|
-
if (!Number.isFinite(input)) throw new TypeError(`Invalid ${label} input`);
|
|
1997
|
-
return input;
|
|
1998
|
-
}
|
|
1999
|
-
function validateStringClaim(claim, value) {
|
|
2000
|
-
if (typeof value != "string") throw new TypeError(`"${claim}" claim must be a string`);
|
|
2001
|
-
}
|
|
2002
|
-
function validateAudienceClaim(value) {
|
|
2003
|
-
if (typeof value != "string" && (!Array.isArray(value) || Array.from(value).some((member) => typeof member != "string"))) throw new TypeError("\"aud\" claim must be a string or an array of strings");
|
|
2004
|
-
}
|
|
2005
|
-
function numericDate(value, label) {
|
|
2006
|
-
return typeof value == "number" ? validateInput(label, value) : value instanceof Date ? validateInput(label, epoch(value)) : epoch(/* @__PURE__ */ new Date()) + secs(value);
|
|
2007
|
-
}
|
|
2008
|
-
var normalizeTyp = (value) => {
|
|
2009
|
-
const normalized = value.toLowerCase();
|
|
2010
|
-
return value.includes("/") ? normalized : `application/${normalized}`;
|
|
2011
|
-
}, checkAudiencePresence = (audPayload, audOption) => typeof audPayload == "string" ? audOption.includes(audPayload) : Array.isArray(audPayload) ? audOption.some((aud) => audPayload.includes(aud)) : !1;
|
|
2012
|
-
function validateNumericDate(payload, claim, required = !1) {
|
|
2013
|
-
const value = payload[claim];
|
|
2014
|
-
if (!(value === void 0 && !required)) {
|
|
2015
|
-
if (typeof value != "number") throw new JWTClaimValidationFailed(`"${claim}" claim must be a number`, payload, claim, "invalid");
|
|
2016
|
-
return value;
|
|
2017
|
-
}
|
|
2018
|
-
}
|
|
2019
|
-
function unexpectedClaim(payload, claim) {
|
|
2020
|
-
throw new JWTClaimValidationFailed(`unexpected "${claim}" claim value`, payload, claim, checkFailed);
|
|
2021
|
-
}
|
|
2022
|
-
function validateClaimsSet(protectedHeader, encodedPayload, options = {}) {
|
|
2023
|
-
let payload;
|
|
2024
|
-
try {
|
|
2025
|
-
payload = JSON.parse(strictDecoder.decode(encodedPayload));
|
|
2026
|
-
} catch {}
|
|
2027
|
-
if (!isObject$1(payload)) throw new JWTInvalid("JWT Claims Set must be a top-level JSON object");
|
|
2028
|
-
const { typ } = options;
|
|
2029
|
-
if (typ !== void 0 && (typeof protectedHeader.typ != "string" || normalizeTyp(protectedHeader.typ) !== normalizeTyp(typ))) throw new JWTClaimValidationFailed("unexpected \"typ\" JWT header value", payload, "typ", checkFailed);
|
|
2030
|
-
const { requiredClaims = [], issuer, subject, audience, maxTokenAge } = options, presenceCheck = [...requiredClaims];
|
|
2031
|
-
maxTokenAge !== void 0 && presenceCheck.push("iat"), audience !== void 0 && presenceCheck.push("aud"), subject !== void 0 && presenceCheck.push("sub"), issuer !== void 0 && presenceCheck.push("iss");
|
|
2032
|
-
for (const claim of new Set(presenceCheck.reverse())) if (!Object.hasOwn(payload, claim)) throw new JWTClaimValidationFailed(`missing required "${claim}" claim`, payload, claim, "missing");
|
|
2033
|
-
issuer !== void 0 && !(Array.isArray(issuer) ? issuer : [issuer]).includes(payload.iss) && unexpectedClaim(payload, "iss"), subject !== void 0 && payload.sub !== subject && unexpectedClaim(payload, "sub"), audience !== void 0 && !checkAudiencePresence(payload.aud, typeof audience == "string" ? [audience] : audience) && unexpectedClaim(payload, "aud");
|
|
2034
|
-
const { clockTolerance } = options;
|
|
2035
|
-
let tolerance = 0;
|
|
2036
|
-
if (typeof clockTolerance == "string") tolerance = secs(clockTolerance);
|
|
2037
|
-
else if (clockTolerance !== void 0) {
|
|
2038
|
-
if (typeof clockTolerance != "number") throw new TypeError("Invalid clockTolerance option type");
|
|
2039
|
-
tolerance = clockTolerance;
|
|
2040
|
-
}
|
|
2041
|
-
validateInput("clockTolerance option", tolerance);
|
|
2042
|
-
const { currentDate } = options, now = validateInput("currentDate option", epoch(currentDate === void 0 ? /* @__PURE__ */ new Date() : currentDate)), iat = validateNumericDate(payload, "iat", maxTokenAge !== void 0), nbf = validateNumericDate(payload, "nbf");
|
|
2043
|
-
if (nbf !== void 0 && nbf > now + tolerance) throw new JWTClaimValidationFailed("\"nbf\" claim timestamp check failed", payload, "nbf", checkFailed);
|
|
2044
|
-
const exp = validateNumericDate(payload, "exp");
|
|
2045
|
-
if (exp !== void 0 && exp <= now - tolerance) throw new JWTExpired("\"exp\" claim timestamp check failed", payload, "exp", checkFailed);
|
|
2046
|
-
if (maxTokenAge !== void 0) {
|
|
2047
|
-
const age = now - iat, max = validateInput("maxTokenAge option", typeof maxTokenAge == "number" ? maxTokenAge : secs(maxTokenAge));
|
|
2048
|
-
if (age - tolerance > max) throw new JWTExpired("\"iat\" claim timestamp check failed (too far in the past)", payload, "iat", checkFailed);
|
|
2049
|
-
if (age < -tolerance) throw new JWTClaimValidationFailed("\"iat\" claim timestamp check failed (it should be in the past)", payload, "iat", checkFailed);
|
|
2050
|
-
}
|
|
2051
|
-
return payload;
|
|
2052
|
-
}
|
|
2053
|
-
var producerPayloads;
|
|
2054
|
-
function producerPayload(producer) {
|
|
2055
|
-
return producerPayloads.get(producer);
|
|
2056
|
-
}
|
|
2057
|
-
function jwtData(producer) {
|
|
2058
|
-
const payload = producerPayload(producer);
|
|
2059
|
-
for (const claim of [
|
|
2060
|
-
"iat",
|
|
2061
|
-
"nbf",
|
|
2062
|
-
"exp"
|
|
2063
|
-
]) {
|
|
2064
|
-
const value = payload[claim];
|
|
2065
|
-
if (typeof value == "number" && !Number.isFinite(value)) throw new TypeError(`"${claim}" claim must be a finite number`);
|
|
2066
|
-
}
|
|
2067
|
-
return encoder.encode(JSON.stringify(payload));
|
|
2068
|
-
}
|
|
2069
|
-
var JWTClaimsBuilder = class {
|
|
2070
|
-
constructor(payload = {}) {
|
|
2071
|
-
if (!isObject$1(payload)) throw new TypeError("JWT Claims Set MUST be an object");
|
|
2072
|
-
(producerPayloads ||= /* @__PURE__ */ new WeakMap()).set(this, structuredClone(payload));
|
|
2073
|
-
}
|
|
2074
|
-
setIssuer(value) {
|
|
2075
|
-
return validateStringClaim("iss", value), producerPayload(this).iss = value, this;
|
|
2076
|
-
}
|
|
2077
|
-
setSubject(value) {
|
|
2078
|
-
return validateStringClaim("sub", value), producerPayload(this).sub = value, this;
|
|
2079
|
-
}
|
|
2080
|
-
setAudience(value) {
|
|
2081
|
-
return validateAudienceClaim(value), producerPayload(this).aud = value, this;
|
|
2082
|
-
}
|
|
2083
|
-
setJti(value) {
|
|
2084
|
-
return validateStringClaim("jti", value), producerPayload(this).jti = value, this;
|
|
2085
|
-
}
|
|
2086
|
-
setNotBefore(value) {
|
|
2087
|
-
return producerPayload(this).nbf = numericDate(value, "setNotBefore"), this;
|
|
2088
|
-
}
|
|
2089
|
-
setExpirationTime(value) {
|
|
2090
|
-
return producerPayload(this).exp = numericDate(value, "setExpirationTime"), this;
|
|
2091
|
-
}
|
|
2092
|
-
setIssuedAt(value) {
|
|
2093
|
-
const payload = producerPayload(this);
|
|
2094
|
-
return value === void 0 ? payload.iat = epoch(/* @__PURE__ */ new Date()) : typeof value == "string" ? payload.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value)) : payload.iat = numericDate(value, "setIssuedAt"), this;
|
|
2095
|
-
}
|
|
2096
|
-
};
|
|
2097
|
-
//#endregion
|
|
2098
|
-
//#region ../../node_modules/jose/dist/webapi/jwt/verify.js
|
|
2099
|
-
async function jwtVerify(jwt, key, options) {
|
|
2100
|
-
const [verified, b64] = await verifyCompact(jwt, prepareVerify(options), key);
|
|
2101
|
-
if (!b64) throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
2102
|
-
const payload = validateClaimsSet(verified.protectedHeader, verified.payload, options);
|
|
2103
|
-
return {
|
|
2104
|
-
...verified,
|
|
2105
|
-
payload
|
|
2106
|
-
};
|
|
2107
|
-
}
|
|
2108
|
-
//#endregion
|
|
2109
|
-
//#region ../../node_modules/jose/dist/webapi/lib/jws_sign.js
|
|
2110
|
-
async function createSignature(input, key, rejectUnencoded) {
|
|
2111
|
-
let [payload, protectedHeader, unprotectedHeader, crit] = input, protectedHeaderString = "";
|
|
2112
|
-
if (protectedHeader !== void 0) {
|
|
2113
|
-
const normalized = serializeJoseHeader(JWSInvalid, protectedHeader);
|
|
2114
|
-
protectedHeader = normalized[0], protectedHeaderString = encode(normalized[1]);
|
|
2115
|
-
}
|
|
2116
|
-
if (unprotectedHeader !== void 0 && (unprotectedHeader = serializeJoseHeader(JWSInvalid, unprotectedHeader)[0]), !protectedHeader && !unprotectedHeader) throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
|
|
2117
|
-
if (!isDisjoint(protectedHeader, unprotectedHeader)) throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
|
|
2118
|
-
const joseHeader = {
|
|
2119
|
-
...protectedHeader,
|
|
2120
|
-
...unprotectedHeader
|
|
2121
|
-
};
|
|
2122
|
-
validateCritDuplicates(JWSInvalid, protectedHeader);
|
|
2123
|
-
const b64 = validateB64(protectedHeader, validateCrit(JWSInvalid, JWS_RECOGNIZED, crit, protectedHeader, joseHeader));
|
|
2124
|
-
b64 || rejectUnencoded?.();
|
|
2125
|
-
const { alg } = joseHeader;
|
|
2126
|
-
if (typeof alg != "string" || !alg) throw new JWSInvalid("JWS \"alg\" (Algorithm) Header Parameter missing or invalid");
|
|
2127
|
-
const entry = jwsAlgorithm(alg);
|
|
2128
|
-
let payloadS = "", payloadB = payload, data;
|
|
2129
|
-
if (b64) {
|
|
2130
|
-
const encoded = input[4];
|
|
2131
|
-
encoded ? (payloadS = encoded[0] ??= encode(payload), payloadB = encoded[1] ??= encode$1(payloadS)) : (payloadS = encode(payload), data = encoder.encode(`${protectedHeaderString}.${payloadS}`));
|
|
2132
|
-
}
|
|
2133
|
-
data ??= concat(encode$1(protectedHeaderString), encode$1("."), payloadB);
|
|
2134
|
-
const k = await rawKey(await prepareKey(entry, key, "sign"), entry.subtle, "sign");
|
|
2135
|
-
entry.minRsaBits && checkModulusLength(entry.alg, k);
|
|
2136
|
-
const jws = {
|
|
2137
|
-
signature: encode(new Uint8Array(await crypto.subtle.sign(entry.signing, k, data))),
|
|
2138
|
-
payload: payloadS
|
|
2139
|
-
};
|
|
2140
|
-
return protectedHeader && (jws.protected = protectedHeaderString), unprotectedHeader && (jws.header = unprotectedHeader), [jws, b64];
|
|
2141
|
-
}
|
|
2142
|
-
async function createCompactSignature(payload, protectedHeader, crit, key, rejectUnencoded) {
|
|
2143
|
-
const [jws] = await createSignature([
|
|
2144
|
-
payload,
|
|
2145
|
-
protectedHeader,
|
|
2146
|
-
void 0,
|
|
2147
|
-
crit
|
|
2148
|
-
], key, rejectUnencoded);
|
|
2149
|
-
return `${jws.protected}.${jws.payload}.${jws.signature}`;
|
|
2150
|
-
}
|
|
2151
|
-
//#endregion
|
|
2152
|
-
//#region ../../node_modules/jose/dist/webapi/jwt/sign.js
|
|
2153
|
-
var SignJWT_base = JWTClaimsBuilder;
|
|
2154
|
-
var SignJWT = class extends SignJWT_base {
|
|
2155
|
-
#protectedHeader;
|
|
2156
|
-
setProtectedHeader(protectedHeader) {
|
|
2157
|
-
return assertNotSet(this.#protectedHeader, "setProtectedHeader"), this.#protectedHeader = protectedHeader, this;
|
|
2158
|
-
}
|
|
2159
|
-
async sign(key, options) {
|
|
2160
|
-
return createCompactSignature(jwtData(this), this.#protectedHeader, options?.crit, key, () => {
|
|
2161
|
-
throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
|
|
2162
|
-
});
|
|
2163
|
-
}
|
|
2164
|
-
};
|
|
2165
|
-
//#endregion
|
|
2166
|
-
//#region src/kernel/moleculer/mesh-mtls/mesh-join-token.ts
|
|
2167
|
-
/**
|
|
2168
|
-
* Mesh join tokens — single-use JWS ES256 signed with the hub mesh CA key.
|
|
2169
|
-
*
|
|
2170
|
-
* Payload: `{ v, hubUrl, hubMeshAddress, caFingerprint, nodeId, jti, exp }`. The node id is MANDATORY
|
|
2171
|
-
* (D857): a token that does not name the node it is for would let its holder pick any id, `hub` included.
|
|
2172
|
-
* `exp` ≤ now + 1 h. `jti` is recorded until expiry so a token cannot be reused.
|
|
2173
|
-
*/
|
|
2174
|
-
/** In-memory + optional persist of spent `jti` until `exp`. */
|
|
2175
|
-
var JoinTokenJtiStore = class {
|
|
2176
|
-
spent = /* @__PURE__ */ new Map();
|
|
2177
|
-
/** True when `jti` was already consumed (and not yet expired). */
|
|
2178
|
-
isSpent(jti, nowSec = Math.floor(Date.now() / 1e3)) {
|
|
2179
|
-
this.gc(nowSec);
|
|
2180
|
-
return this.spent.has(jti);
|
|
2181
|
-
}
|
|
2182
|
-
/** Record a jti as used until `exp`. Returns false if already spent. */
|
|
2183
|
-
consume(jti, exp, nowSec = Math.floor(Date.now() / 1e3)) {
|
|
2184
|
-
this.gc(nowSec);
|
|
2185
|
-
if (this.spent.has(jti)) return false;
|
|
2186
|
-
this.spent.set(jti, exp);
|
|
2187
|
-
return true;
|
|
2188
|
-
}
|
|
2189
|
-
/** Test helper. */
|
|
2190
|
-
size() {
|
|
2191
|
-
return this.spent.size;
|
|
2192
|
-
}
|
|
2193
|
-
gc(nowSec) {
|
|
2194
|
-
for (const [jti, exp] of this.spent) if (exp <= nowSec) this.spent.delete(jti);
|
|
2195
|
-
}
|
|
2196
|
-
};
|
|
2197
|
-
var processJtiStore = new JoinTokenJtiStore();
|
|
2198
|
-
function processJoinTokenJtiStore() {
|
|
2199
|
-
return processJtiStore;
|
|
2200
|
-
}
|
|
2201
|
-
async function mintMeshJoinToken(input) {
|
|
2202
|
-
if (!isValidAgentNodeId(input.nodeId)) throw new Error(`a join token needs the node id it is for; "${input.nodeId}" is not one an agent may carry`);
|
|
2203
|
-
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
2204
|
-
const nowSec = Math.floor(now.getTime() / 1e3);
|
|
2205
|
-
const exp = nowSec + Math.min(Math.max(1, input.ttlSec ?? 3600), require_constants$8.MESH_JOIN_TOKEN_MAX_TTL_SEC);
|
|
2206
|
-
const jti = input.jti ?? (0, node_crypto.randomBytes)(16).toString("base64url");
|
|
2207
|
-
return new SignJWT({
|
|
2208
|
-
v: 1,
|
|
2209
|
-
hubUrl: input.hubUrl,
|
|
2210
|
-
hubMeshAddress: input.hubMeshAddress,
|
|
2211
|
-
caFingerprint: caFingerprintCompact(input.ca.certPem),
|
|
2212
|
-
nodeId: input.nodeId,
|
|
2213
|
-
jti,
|
|
2214
|
-
exp
|
|
2215
|
-
}).setProtectedHeader({
|
|
2216
|
-
alg: "ES256",
|
|
2217
|
-
typ: "JWT"
|
|
2218
|
-
}).setIssuedAt(nowSec).setExpirationTime(exp).setJti(jti).sign(input.ca.privateKey);
|
|
2219
|
-
}
|
|
2220
|
-
async function verifyMeshJoinToken(input) {
|
|
2221
|
-
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
2222
|
-
const nowSec = Math.floor(now.getTime() / 1e3);
|
|
2223
|
-
let payload;
|
|
2224
|
-
try {
|
|
2225
|
-
payload = (await jwtVerify(input.token, input.ca.publicKey, {
|
|
2226
|
-
algorithms: ["ES256"],
|
|
2227
|
-
currentDate: now
|
|
2228
|
-
})).payload;
|
|
2229
|
-
} catch (err) {
|
|
2230
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
2231
|
-
if (/exp/i.test(msg) || /timestamp/i.test(msg)) return {
|
|
2232
|
-
ok: false,
|
|
2233
|
-
reason: "token expired"
|
|
2234
|
-
};
|
|
2235
|
-
return {
|
|
2236
|
-
ok: false,
|
|
2237
|
-
reason: `token signature invalid: ${msg}`
|
|
2238
|
-
};
|
|
2239
|
-
}
|
|
2240
|
-
const claims = parseClaims$1(payload);
|
|
2241
|
-
if (claims === null) return {
|
|
2242
|
-
ok: false,
|
|
2243
|
-
reason: "token claims malformed"
|
|
2244
|
-
};
|
|
2245
|
-
if (claims.exp <= nowSec) return {
|
|
2246
|
-
ok: false,
|
|
2247
|
-
reason: "token expired"
|
|
2248
|
-
};
|
|
2249
|
-
const expectedFp = caFingerprintCompact(input.ca.certPem);
|
|
2250
|
-
if (claims.caFingerprint !== expectedFp) return {
|
|
2251
|
-
ok: false,
|
|
2252
|
-
reason: "token caFingerprint does not match this hub CA"
|
|
2253
|
-
};
|
|
2254
|
-
if (input.expectedCaFingerprint !== void 0 && claims.caFingerprint !== normalizeFp(input.expectedCaFingerprint)) return {
|
|
2255
|
-
ok: false,
|
|
2256
|
-
reason: "token caFingerprint pin mismatch"
|
|
2257
|
-
};
|
|
2258
|
-
const store = input.jtiStore ?? processJtiStore;
|
|
2259
|
-
if (input.consume !== false) {
|
|
2260
|
-
if (!store.consume(claims.jti, claims.exp, nowSec)) return {
|
|
2261
|
-
ok: false,
|
|
2262
|
-
reason: "token already used"
|
|
2263
|
-
};
|
|
2264
|
-
} else if (store.isSpent(claims.jti, nowSec)) return {
|
|
2265
|
-
ok: false,
|
|
2266
|
-
reason: "token already used"
|
|
2267
|
-
};
|
|
2268
|
-
return {
|
|
2269
|
-
ok: true,
|
|
2270
|
-
claims
|
|
2271
|
-
};
|
|
2272
|
-
}
|
|
2273
|
-
function normalizeFp(fp) {
|
|
2274
|
-
return fp.replace(/:/g, "").toLowerCase();
|
|
2275
|
-
}
|
|
2276
|
-
function parseClaims$1(payload) {
|
|
2277
|
-
if (payload["v"] !== 1) return null;
|
|
2278
|
-
const hubUrl = payload["hubUrl"];
|
|
2279
|
-
const hubMeshAddress = payload["hubMeshAddress"];
|
|
2280
|
-
const caFingerprint = payload["caFingerprint"];
|
|
2281
|
-
const jti = typeof payload.jti === "string" ? payload.jti : payload["jti"];
|
|
2282
|
-
const exp = typeof payload.exp === "number" ? payload.exp : null;
|
|
2283
|
-
if (typeof hubUrl !== "string" || hubUrl.length === 0) return null;
|
|
2284
|
-
if (typeof hubMeshAddress !== "string" || hubMeshAddress.length === 0) return null;
|
|
2285
|
-
if (typeof caFingerprint !== "string" || caFingerprint.length === 0) return null;
|
|
2286
|
-
if (typeof jti !== "string" || jti.length === 0) return null;
|
|
2287
|
-
if (exp === null) return null;
|
|
2288
|
-
const nodeId = payload["nodeId"];
|
|
2289
|
-
if (typeof nodeId !== "string" || !isValidAgentNodeId(nodeId)) return null;
|
|
2290
|
-
return {
|
|
2291
|
-
v: 1,
|
|
2292
|
-
hubUrl,
|
|
2293
|
-
hubMeshAddress,
|
|
2294
|
-
caFingerprint: normalizeFp(caFingerprint),
|
|
2295
|
-
nodeId,
|
|
2296
|
-
jti,
|
|
2297
|
-
exp
|
|
2298
|
-
};
|
|
2299
|
-
}
|
|
2300
|
-
//#endregion
|
|
2301
|
-
//#region src/kernel/moleculer/mesh-mtls/mesh-enroll.ts
|
|
2302
|
-
/**
|
|
2303
|
-
* `POST /api/mesh/enroll` — verify join token, issue a 30-day leaf from CSR.
|
|
2304
|
-
*/
|
|
2305
|
-
async function enrollMeshNode(body, deps) {
|
|
2306
|
-
if (typeof body.token !== "string" || body.token.length === 0) return {
|
|
2307
|
-
ok: false,
|
|
2308
|
-
error: "token is required",
|
|
2309
|
-
status: 400
|
|
2310
|
-
};
|
|
2311
|
-
if (typeof body.csr !== "string" || !body.csr.includes("BEGIN CERTIFICATE REQUEST")) return {
|
|
2312
|
-
ok: false,
|
|
2313
|
-
error: "csr PEM is required",
|
|
2314
|
-
status: 400
|
|
2315
|
-
};
|
|
2316
|
-
const verified = await verifyMeshJoinToken({
|
|
2317
|
-
token: body.token,
|
|
2318
|
-
ca: deps.ca,
|
|
2319
|
-
jtiStore: deps.jtiStore ?? processJoinTokenJtiStore(),
|
|
2320
|
-
now: deps.now,
|
|
2321
|
-
consume: true
|
|
2322
|
-
});
|
|
2323
|
-
if (!verified.ok) {
|
|
2324
|
-
const status = verified.reason.includes("expired") ? 401 : verified.reason.includes("already used") ? 409 : 401;
|
|
2325
|
-
return {
|
|
2326
|
-
ok: false,
|
|
2327
|
-
error: verified.reason,
|
|
2328
|
-
status
|
|
2329
|
-
};
|
|
2330
|
-
}
|
|
2331
|
-
let leaf;
|
|
2332
|
-
try {
|
|
2333
|
-
leaf = await issueMeshLeafFromCsr(deps.ca, body.csr, {
|
|
2334
|
-
expectedNodeId: verified.claims.nodeId,
|
|
2335
|
-
now: deps.now
|
|
2336
|
-
});
|
|
2337
|
-
} catch (err) {
|
|
2338
|
-
return {
|
|
2339
|
-
ok: false,
|
|
2340
|
-
error: err instanceof Error ? err.message : String(err),
|
|
2341
|
-
status: 400
|
|
2342
|
-
};
|
|
2343
|
-
}
|
|
2344
|
-
try {
|
|
2345
|
-
await deps.onIssued?.(leaf.commonName, leaf.certPem);
|
|
2346
|
-
} catch (err) {
|
|
2347
|
-
deps.onRecordFailed?.(leaf.commonName, err);
|
|
2348
|
-
}
|
|
2349
|
-
return {
|
|
2350
|
-
ok: true,
|
|
2351
|
-
cert: leaf.certPem,
|
|
2352
|
-
caCert: deps.ca.certPem,
|
|
2353
|
-
nodeId: leaf.commonName,
|
|
2354
|
-
notAfter: leaf.notAfter.toISOString(),
|
|
2355
|
-
serialNumber: leaf.serialNumber
|
|
2356
|
-
};
|
|
2357
|
-
}
|
|
2358
|
-
//#endregion
|
|
2359
1382
|
//#region src/kernel/moleculer/mesh-mtls/mesh-tls-enabler.ts
|
|
2360
1383
|
var SLOT = Symbol.for("camstack.mesh.tls-enabler");
|
|
2361
1384
|
function setProcessMeshTlsEnabler(enabler) {
|
|
@@ -27751,7 +26774,7 @@ var require_index_min = /* @__PURE__ */ require_chunk.__commonJSMin(((exports) =
|
|
|
27751
26774
|
var require_shard = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module) => {
|
|
27752
26775
|
var _ = require_lodash();
|
|
27753
26776
|
var BaseStrategy = require_base$7();
|
|
27754
|
-
var crypto$
|
|
26777
|
+
var crypto$3 = require("crypto");
|
|
27755
26778
|
var { LRUCache } = require_index_min();
|
|
27756
26779
|
var { isFunction, randomInt } = require_utils$3();
|
|
27757
26780
|
/**
|
|
@@ -27857,7 +26880,7 @@ var require_shard = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, modul
|
|
|
27857
26880
|
* @memberof ShardStrategy
|
|
27858
26881
|
*/
|
|
27859
26882
|
getHash(key) {
|
|
27860
|
-
const hash = crypto$
|
|
26883
|
+
const hash = crypto$3.createHash("md5").update(key).digest("hex");
|
|
27861
26884
|
const hashNum = parseInt(hash.substring(0, 8), 16);
|
|
27862
26885
|
return this.opts.ringSize ? hashNum % this.opts.ringSize : hashNum;
|
|
27863
26886
|
}
|
|
@@ -49115,7 +48138,7 @@ var require_validators$1 = /* @__PURE__ */ require_chunk.__commonJSMin(((exports
|
|
|
49115
48138
|
//#region ../../node_modules/moleculer/src/cachers/base.js
|
|
49116
48139
|
var require_base$2 = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module) => {
|
|
49117
48140
|
var _ = require_lodash();
|
|
49118
|
-
var crypto$
|
|
48141
|
+
var crypto$2 = require("crypto");
|
|
49119
48142
|
var { METRIC } = require_metrics$1();
|
|
49120
48143
|
var { isObject, isFunction, isDate } = require_utils$3();
|
|
49121
48144
|
/**
|
|
@@ -49379,7 +48402,7 @@ var require_base$2 = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, modu
|
|
|
49379
48402
|
const maxParamsLength = this.opts.maxParamsLength;
|
|
49380
48403
|
if (!maxParamsLength || maxParamsLength < 44 || key.length <= maxParamsLength) return key;
|
|
49381
48404
|
const prefixLength = maxParamsLength - 44;
|
|
49382
|
-
const base64Hash = crypto$
|
|
48405
|
+
const base64Hash = crypto$2.createHash("sha256").update(key).digest("base64");
|
|
49383
48406
|
if (prefixLength < 1) return base64Hash;
|
|
49384
48407
|
return key.substring(0, prefixLength) + base64Hash;
|
|
49385
48408
|
}
|
|
@@ -76127,7 +75150,7 @@ var require_hot_reload = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
76127
75150
|
//#endregion
|
|
76128
75151
|
//#region ../../node_modules/moleculer/src/middlewares/transmit/encryption.js
|
|
76129
75152
|
var require_encryption = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module) => {
|
|
76130
|
-
var crypto$
|
|
75153
|
+
var crypto$1 = require("crypto");
|
|
76131
75154
|
/**
|
|
76132
75155
|
* This is a AES encryption middleware to protect the whole
|
|
76133
75156
|
* Moleculer transporter communication with AES.
|
|
@@ -76150,14 +75173,14 @@ var require_encryption = /* @__PURE__ */ require_chunk.__commonJSMin(((exports,
|
|
|
76150
75173
|
},
|
|
76151
75174
|
transporterSend(next) {
|
|
76152
75175
|
return (topic, data, meta) => {
|
|
76153
|
-
const encrypter = iv ? crypto$
|
|
75176
|
+
const encrypter = iv ? crypto$1.createCipheriv(algorithm, password, iv) : crypto$1.createCipher(algorithm, password);
|
|
76154
75177
|
return next(topic, Buffer.concat([encrypter.update(data), encrypter.final()]), meta);
|
|
76155
75178
|
};
|
|
76156
75179
|
},
|
|
76157
75180
|
transporterReceive(next) {
|
|
76158
75181
|
return (cmd, data, s) => {
|
|
76159
75182
|
try {
|
|
76160
|
-
const decrypter = iv ? crypto$
|
|
75183
|
+
const decrypter = iv ? crypto$1.createDecipheriv(algorithm, password, iv) : crypto$1.createDecipher(algorithm, password);
|
|
76161
75184
|
return next(cmd, Buffer.concat([decrypter.update(data), decrypter.final()]), s);
|
|
76162
75185
|
} catch (err) {
|
|
76163
75186
|
logger.error("Received packet decryption error.", err);
|
|
@@ -83652,7 +82675,7 @@ var require_main = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module
|
|
|
83652
82675
|
var fs$4 = require("fs");
|
|
83653
82676
|
var path$3 = require("path");
|
|
83654
82677
|
var os$4 = require("os");
|
|
83655
|
-
var crypto
|
|
82678
|
+
var crypto = require("crypto");
|
|
83656
82679
|
var TIPS = [
|
|
83657
82680
|
"◈ encrypted .env [www.dotenvx.com]",
|
|
83658
82681
|
"◈ secrets for agents [www.dotenvx.com]",
|
|
@@ -83857,7 +82880,7 @@ var require_main = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module
|
|
|
83857
82880
|
const authTag = ciphertext.subarray(-16);
|
|
83858
82881
|
ciphertext = ciphertext.subarray(12, -16);
|
|
83859
82882
|
try {
|
|
83860
|
-
const aesgcm = crypto
|
|
82883
|
+
const aesgcm = crypto.createDecipheriv("aes-256-gcm", key, nonce);
|
|
83861
82884
|
aesgcm.setAuthTag(authTag);
|
|
83862
82885
|
return `${aesgcm.update(ciphertext)}${aesgcm.final()}`;
|
|
83863
82886
|
} catch (error) {
|
|
@@ -88018,6 +87041,11 @@ var TlsTcpTransporter = class extends TcpTransporterBase {
|
|
|
88018
87041
|
this.logger.warn("Dropping mesh packet — an enrolled agent accepts TLS from the hub only");
|
|
88019
87042
|
return;
|
|
88020
87043
|
}
|
|
87044
|
+
const wireSender = peekSender(this, type, message);
|
|
87045
|
+
if (wireSender === null || wireSender === this.nodeID) {
|
|
87046
|
+
this.logger.warn(wireSender === null ? "Dropping mesh packet - it names no sender" : "Dropping mesh packet - it claims this node as its sender");
|
|
87047
|
+
return;
|
|
87048
|
+
}
|
|
88021
87049
|
if (socket !== void 0 && isTlsSocket(socket)) {
|
|
88022
87050
|
const tlsSock = socket;
|
|
88023
87051
|
const identity = tlsSock.meshPeerCn ? {
|
|
@@ -88033,9 +87061,8 @@ var TlsTcpTransporter = class extends TcpTransporterBase {
|
|
|
88033
87061
|
tlsSock.destroy();
|
|
88034
87062
|
return;
|
|
88035
87063
|
}
|
|
88036
|
-
|
|
88037
|
-
|
|
88038
|
-
this.logger.warn(`Dropping forged mesh packet — sender=${sender} peerCN=${identity.cn}`);
|
|
87064
|
+
if (wireSender !== identity.cn) {
|
|
87065
|
+
this.logger.warn(`Dropping forged mesh packet — sender=${wireSender} peerCN=${identity.cn}`);
|
|
88039
87066
|
return;
|
|
88040
87067
|
}
|
|
88041
87068
|
tlsSock.meshPeerCn = identity.cn;
|
|
@@ -89297,170 +88324,10 @@ var HubPairing = class {
|
|
|
89297
88324
|
}
|
|
89298
88325
|
};
|
|
89299
88326
|
//#endregion
|
|
89300
|
-
//#region src/builtins/system-config/cluster-secret-keeper.ts
|
|
89301
|
-
/**
|
|
89302
|
-
* Keeps the hub's cluster-secret gate in step with System → Cluster (D797,
|
|
89303
|
-
* D802).
|
|
89304
|
-
*
|
|
89305
|
-
* The field is a `password` of `system-config`: its `system-settings` row
|
|
89306
|
-
* (`cluster.clusterSecret`) holds a keychain marker, the value lives in the
|
|
89307
|
-
* keychain (owner `system`). The gate the mesh join reads:
|
|
89308
|
-
*
|
|
89309
|
-
* - no marker → the secret is MANDATORY (D802): the keeper asks
|
|
89310
|
-
* its owner to generate one (`generateSecret`), and
|
|
89311
|
-
* until that succeeds the gate is `off` — no node can
|
|
89312
|
-
* authenticate (mesh auth is always enforced, D821);
|
|
89313
|
-
* - marker + value → `on` — nodes prove the secret;
|
|
89314
|
-
* - marker, no answer → `unknown` — refused, retryably, and retried here.
|
|
89315
|
-
* A locked keychain or a value lost to a reset NEVER opens the gate, and
|
|
89316
|
-
* never triggers a generation (the operator decides what replaces a value
|
|
89317
|
-
* the keychain lost).
|
|
89318
|
-
*
|
|
89319
|
-
* It also publishes the mesh mode (`cluster.meshAuth`, `mesh-auth-mode.ts`).
|
|
89320
|
-
*/
|
|
89321
|
-
/** The field key inside the `cluster` section. */
|
|
89322
|
-
var CLUSTER_SECRET_FIELD = "clusterSecret";
|
|
89323
|
-
var ClusterSecretKeeper = class {
|
|
89324
|
-
deps;
|
|
89325
|
-
retryTimer = null;
|
|
89326
|
-
unsubscribe = null;
|
|
89327
|
-
stopped = false;
|
|
89328
|
-
last = null;
|
|
89329
|
-
constructor(deps) {
|
|
89330
|
-
this.deps = deps;
|
|
89331
|
-
}
|
|
89332
|
-
async start() {
|
|
89333
|
-
this.unsubscribe = this.deps.secrets?.onChange((ref) => {
|
|
89334
|
-
if (ref === require_constants$8.CLUSTER_SECRET_REF) this.reload();
|
|
89335
|
-
}) ?? null;
|
|
89336
|
-
await this.reload();
|
|
89337
|
-
}
|
|
89338
|
-
stop() {
|
|
89339
|
-
this.stopped = true;
|
|
89340
|
-
if (this.retryTimer !== null) clearTimeout(this.retryTimer);
|
|
89341
|
-
this.retryTimer = null;
|
|
89342
|
-
this.unsubscribe?.();
|
|
89343
|
-
this.unsubscribe = null;
|
|
89344
|
-
}
|
|
89345
|
-
/** Re-read the row and the keychain; publish the gate. */
|
|
89346
|
-
async reload() {
|
|
89347
|
-
if (this.stopped) return;
|
|
89348
|
-
let gate = await this.compute();
|
|
89349
|
-
if (gate.kind === "off" && this.deps.generateSecret !== void 0 && !this.stopped) gate = await this.generate();
|
|
89350
|
-
if (this.stopped) return;
|
|
89351
|
-
require_constants$8.setProcessClusterSecretGate(gate);
|
|
89352
|
-
this.report(gate);
|
|
89353
|
-
if (gate.kind === "unknown" || gate.kind === "off" && this.deps.generateSecret !== void 0) this.scheduleRetry();
|
|
89354
|
-
}
|
|
89355
|
-
async generate() {
|
|
89356
|
-
try {
|
|
89357
|
-
await this.deps.generateSecret?.();
|
|
89358
|
-
} catch (err) {
|
|
89359
|
-
this.deps.logger.error("The cluster secret is mandatory but could not be generated yet — retrying. Agents cannot authenticate until it exists.", { meta: { error: errText(err) } });
|
|
89360
|
-
return { kind: "off" };
|
|
89361
|
-
}
|
|
89362
|
-
this.deps.logger.info("Generated the cluster secret (none was stored). Reveal it on System → Cluster and enter it in each agent.");
|
|
89363
|
-
return this.compute();
|
|
89364
|
-
}
|
|
89365
|
-
async compute() {
|
|
89366
|
-
let section;
|
|
89367
|
-
try {
|
|
89368
|
-
section = await this.deps.readSection();
|
|
89369
|
-
} catch (err) {
|
|
89370
|
-
return {
|
|
89371
|
-
kind: "unknown",
|
|
89372
|
-
reason: `settings unreadable: ${errText(err)}`
|
|
89373
|
-
};
|
|
89374
|
-
}
|
|
89375
|
-
setProcessMeshAuthMode("enforced");
|
|
89376
|
-
const stored = section[CLUSTER_SECRET_FIELD];
|
|
89377
|
-
if (stored === void 0 || stored === null || stored === "") return { kind: "off" };
|
|
89378
|
-
if (!require_dist.isSecretMarker(stored)) return {
|
|
89379
|
-
kind: "unknown",
|
|
89380
|
-
reason: "stored inline, not in the keychain — set it again in System → Cluster"
|
|
89381
|
-
};
|
|
89382
|
-
const secrets = this.deps.secrets;
|
|
89383
|
-
if (secrets === null) return {
|
|
89384
|
-
kind: "unknown",
|
|
89385
|
-
reason: "no keychain door in this process"
|
|
89386
|
-
};
|
|
89387
|
-
let entry;
|
|
89388
|
-
try {
|
|
89389
|
-
entry = (await secrets.resolve([require_constants$8.CLUSTER_SECRET_REF]))[require_constants$8.CLUSTER_SECRET_REF];
|
|
89390
|
-
} catch (err) {
|
|
89391
|
-
return {
|
|
89392
|
-
kind: "unknown",
|
|
89393
|
-
reason: errText(err)
|
|
89394
|
-
};
|
|
89395
|
-
}
|
|
89396
|
-
if (entry === void 0) return {
|
|
89397
|
-
kind: "unknown",
|
|
89398
|
-
reason: "no-answer"
|
|
89399
|
-
};
|
|
89400
|
-
switch (entry.kind) {
|
|
89401
|
-
case "value": return {
|
|
89402
|
-
kind: "on",
|
|
89403
|
-
hash: require_constants$8.hashClusterSecret(entry.value)
|
|
89404
|
-
};
|
|
89405
|
-
case "unavailable": return {
|
|
89406
|
-
kind: "unknown",
|
|
89407
|
-
reason: entry.reason
|
|
89408
|
-
};
|
|
89409
|
-
case "missing": return {
|
|
89410
|
-
kind: "unknown",
|
|
89411
|
-
reason: "the stored value is gone — set it again in System → Cluster"
|
|
89412
|
-
};
|
|
89413
|
-
case "forbidden": return {
|
|
89414
|
-
kind: "unknown",
|
|
89415
|
-
reason: "forbidden"
|
|
89416
|
-
};
|
|
89417
|
-
}
|
|
89418
|
-
}
|
|
89419
|
-
report(gate) {
|
|
89420
|
-
const changed = this.last !== gate.kind;
|
|
89421
|
-
this.last = gate.kind;
|
|
89422
|
-
if (gate.kind === "unknown") {
|
|
89423
|
-
this.deps.logger.error("Agents cannot register: a cluster secret is set but cannot be read from the keychain. Registrations are refused until it can (no fallback).", { meta: { reason: gate.reason } });
|
|
89424
|
-
return;
|
|
89425
|
-
}
|
|
89426
|
-
if (changed) this.deps.logger.info(gate.kind === "on" ? "Cluster secret set — agents prove it to join the mesh" : "No cluster secret yet — no node can authenticate to the mesh");
|
|
89427
|
-
}
|
|
89428
|
-
scheduleRetry() {
|
|
89429
|
-
if (this.stopped || this.retryTimer !== null) return;
|
|
89430
|
-
this.retryTimer = setTimeout(() => {
|
|
89431
|
-
this.retryTimer = null;
|
|
89432
|
-
this.reload();
|
|
89433
|
-
}, this.deps.retryMs ?? 3e4);
|
|
89434
|
-
this.retryTimer.unref?.();
|
|
89435
|
-
}
|
|
89436
|
-
};
|
|
89437
|
-
function errText(err) {
|
|
89438
|
-
return err instanceof Error ? err.message : String(err);
|
|
89439
|
-
}
|
|
89440
|
-
//#endregion
|
|
89441
88327
|
//#region src/builtins/system-config/mesh-actions.ts
|
|
89442
88328
|
/**
|
|
89443
|
-
* System → Cluster —
|
|
89444
|
-
* agent-ui unlock tickets (D821).
|
|
88329
|
+
* System → Cluster — agent-ui unlock tickets (D821).
|
|
89445
88330
|
*/
|
|
89446
|
-
var mintJoinTokenInputSchema = zod.z.object({
|
|
89447
|
-
/** The node id the token is for - mandatory: the CSR CN must be exactly this. */
|
|
89448
|
-
nodeId: zod.z.string().min(1),
|
|
89449
|
-
/** Override hub HTTPS base (default: local-network publicEndpoint). */
|
|
89450
|
-
hubUrl: zod.z.string().url().optional(),
|
|
89451
|
-
/** Override `host:6443` TLS mesh address carried in the token. */
|
|
89452
|
-
hubMeshAddress: zod.z.string().min(3).optional(),
|
|
89453
|
-
/** Seconds until expiry; capped at 1 h. */
|
|
89454
|
-
ttlSec: zod.z.number().int().positive().max(3600).optional()
|
|
89455
|
-
});
|
|
89456
|
-
var mintJoinTokenOutputSchema = zod.z.object({
|
|
89457
|
-
token: zod.z.string().min(1),
|
|
89458
|
-
exp: zod.z.number().int(),
|
|
89459
|
-
hubUrl: zod.z.string(),
|
|
89460
|
-
hubMeshAddress: zod.z.string(),
|
|
89461
|
-
caFingerprint: zod.z.string(),
|
|
89462
|
-
nodeId: zod.z.string()
|
|
89463
|
-
});
|
|
89464
88331
|
var mintAgentUiUnlockInputSchema = zod.z.object({
|
|
89465
88332
|
nodeId: zod.z.string().min(1),
|
|
89466
88333
|
/**
|
|
@@ -89475,17 +88342,12 @@ var mintAgentUiUnlockOutputSchema = zod.z.object({
|
|
|
89475
88342
|
nodeId: zod.z.string().min(1),
|
|
89476
88343
|
dashboardUrl: zod.z.string().url().optional()
|
|
89477
88344
|
});
|
|
89478
|
-
var systemConfigMeshActions = require_dist.defineCustomActions({
|
|
89479
|
-
|
|
89480
|
-
|
|
89481
|
-
|
|
89482
|
-
|
|
89483
|
-
|
|
89484
|
-
mintAgentUiUnlockTicket: require_dist.customAction(mintAgentUiUnlockInputSchema, mintAgentUiUnlockOutputSchema, {
|
|
89485
|
-
kind: "mutation",
|
|
89486
|
-
auth: "admin"
|
|
89487
|
-
})
|
|
89488
|
-
});
|
|
88345
|
+
var systemConfigMeshActions = require_dist.defineCustomActions({
|
|
88346
|
+
/** Hub admin → short-lived ticket the agent redeems for a tab session (D821). */
|
|
88347
|
+
mintAgentUiUnlockTicket: require_dist.customAction(mintAgentUiUnlockInputSchema, mintAgentUiUnlockOutputSchema, {
|
|
88348
|
+
kind: "mutation",
|
|
88349
|
+
auth: "admin"
|
|
88350
|
+
}) });
|
|
89489
88351
|
//#endregion
|
|
89490
88352
|
//#region src/builtins/system-config/system-config.addon.ts
|
|
89491
88353
|
/** How often superseded and expired mesh certificate rows are reaped. */
|
|
@@ -89503,10 +88365,9 @@ var MESH_REAP_MS = 24 * 36e5;
|
|
|
89503
88365
|
* - server (port, host, dataPath — READ-ONLY, loaded from config.yaml at bootstrap)
|
|
89504
88366
|
* - auth (tokenExpiry = session lifetime, accessTokenExpiry, trustedProxies,
|
|
89505
88367
|
* trustedNetworks)
|
|
89506
|
-
* - cluster (
|
|
89507
|
-
*
|
|
89508
|
-
*
|
|
89509
|
-
* boot; `meshAuth` — transition / enforced. D802)
|
|
88368
|
+
* - cluster (no operator field remains: the cluster secret and the mesh auth
|
|
88369
|
+
* mode were removed by D857 — a node's identity is its mesh
|
|
88370
|
+
* certificate, and agents are paired, not given a secret)
|
|
89510
88371
|
*
|
|
89511
88372
|
* Sections NOT exposed (each owned by the addon that implements them):
|
|
89512
88373
|
* - logging → `winston-logging` addon (level + retention)
|
|
@@ -89549,12 +88410,13 @@ var KEY_TO_SECTION = {
|
|
|
89549
88410
|
tokenExpiry: "auth",
|
|
89550
88411
|
accessTokenExpiry: "auth",
|
|
89551
88412
|
trustedProxies: "auth",
|
|
89552
|
-
trustedNetworks: "auth"
|
|
89553
|
-
[CLUSTER_SECRET_FIELD]: "cluster",
|
|
89554
|
-
[MESH_AUTH_MODE_FIELD]: "cluster"
|
|
88413
|
+
trustedNetworks: "auth"
|
|
89555
88414
|
};
|
|
89556
|
-
/**
|
|
89557
|
-
|
|
88415
|
+
/**
|
|
88416
|
+
* Keys a pre-D857 form may still send. They are dropped with a line, never
|
|
88417
|
+
* written: the cluster secret and the mesh auth mode no longer exist.
|
|
88418
|
+
*/
|
|
88419
|
+
var RETIRED_CLUSTER_KEYS = new Set(["clusterSecret", "meshAuth"]);
|
|
89558
88420
|
/**
|
|
89559
88421
|
* Auth keys holding a list of networks (CIDR or single address). A save with
|
|
89560
88422
|
* an entry that does not parse is REFUSED whole: dropping it would trust less
|
|
@@ -89565,7 +88427,6 @@ var CIDR_LIST_KEYS = new Set(["trustedProxies", "trustedNetworks"]);
|
|
|
89565
88427
|
var SYSTEM_CONFIG_CLUSTER_SECTION_ID = "system-config-cluster";
|
|
89566
88428
|
var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
89567
88429
|
id = "system-config";
|
|
89568
|
-
clusterSecretKeeper = null;
|
|
89569
88430
|
meshCaKeeper = null;
|
|
89570
88431
|
meshReapTimer = null;
|
|
89571
88432
|
meshGateTimers = /* @__PURE__ */ new Set();
|
|
@@ -89575,20 +88436,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89575
88436
|
super({});
|
|
89576
88437
|
}
|
|
89577
88438
|
async onInitialize() {
|
|
89578
|
-
this.clusterSecretKeeper = new ClusterSecretKeeper({
|
|
89579
|
-
secrets: this.systemSecrets(),
|
|
89580
|
-
readSection: async () => await this.ctx.settings?.getSection("cluster") ?? {},
|
|
89581
|
-
logger: this.ctx.logger,
|
|
89582
|
-
generateSecret: () => this.generateClusterSecret()
|
|
89583
|
-
});
|
|
89584
|
-
setProcessMeshEnforcer(async (reason) => {
|
|
89585
|
-
await this.writeMeshAuthMode("enforced");
|
|
89586
|
-
this.ctx.logger.info("Mesh authentication is now ENFORCED", { meta: { reason } });
|
|
89587
|
-
});
|
|
89588
|
-
await this.clusterSecretKeeper.start();
|
|
89589
|
-
try {
|
|
89590
|
-
await this.writeMeshAuthMode("enforced");
|
|
89591
|
-
} catch {}
|
|
89592
88439
|
this.meshCaKeeper = new MeshCaKeeper({
|
|
89593
88440
|
secrets: this.systemSecrets(),
|
|
89594
88441
|
readClusterSection: async () => await this.ctx.settings?.getSection("cluster") ?? {},
|
|
@@ -89602,14 +88449,10 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89602
88449
|
this.ctx.logger.info("Initialized — exposes yml-backed sections via getGlobalSettings");
|
|
89603
88450
|
return {
|
|
89604
88451
|
customActions: systemConfigMeshActions,
|
|
89605
|
-
actionHandlers: {
|
|
89606
|
-
mintJoinToken: async (input) => this.mintJoinToken(parseMintJoinTokenInput(input)),
|
|
89607
|
-
mintAgentUiUnlockTicket: async (input) => this.mintAgentUiUnlock(parseMintUnlockInput(input))
|
|
89608
|
-
}
|
|
88452
|
+
actionHandlers: { mintAgentUiUnlockTicket: async (input) => this.mintAgentUiUnlock(parseMintUnlockInput(input)) }
|
|
89609
88453
|
};
|
|
89610
88454
|
}
|
|
89611
88455
|
async onShutdown() {
|
|
89612
|
-
setProcessMeshEnforcer(null);
|
|
89613
88456
|
setProcessMeshCertificateRegistry(null);
|
|
89614
88457
|
setProcessMeshTlsListenerState(null);
|
|
89615
88458
|
require_agent_https.setProcessAgentHttpsNames(null);
|
|
@@ -89620,8 +88463,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89620
88463
|
this.meshGateTimers.clear();
|
|
89621
88464
|
this.meshCaKeeper?.stop();
|
|
89622
88465
|
this.meshCaKeeper = null;
|
|
89623
|
-
this.clusterSecretKeeper?.stop();
|
|
89624
|
-
this.clusterSecretKeeper = null;
|
|
89625
88466
|
}
|
|
89626
88467
|
/**
|
|
89627
88468
|
* The hub's record of mesh leaves (D856): declared and loaded BEFORE the TLS
|
|
@@ -89712,32 +88553,9 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89712
88553
|
onError: (err) => this.ctx.logger.error("Mesh certificate registry failed to load", { meta: { error: err instanceof Error ? err.message : String(err) } })
|
|
89713
88554
|
});
|
|
89714
88555
|
}
|
|
89715
|
-
async mintJoinToken(input) {
|
|
89716
|
-
const ca = requireProcessMeshCa();
|
|
89717
|
-
const hubUrl = input.hubUrl ?? await this.resolveHubUrl();
|
|
89718
|
-
const hubMeshAddress = input.hubMeshAddress ?? await this.resolveHubMeshAddress();
|
|
89719
|
-
const token = await mintMeshJoinToken({
|
|
89720
|
-
ca,
|
|
89721
|
-
hubUrl,
|
|
89722
|
-
hubMeshAddress,
|
|
89723
|
-
nodeId: input.nodeId,
|
|
89724
|
-
...input.ttlSec !== void 0 ? { ttlSec: input.ttlSec } : {}
|
|
89725
|
-
});
|
|
89726
|
-
return {
|
|
89727
|
-
token,
|
|
89728
|
-
exp: readJwtExp(token),
|
|
89729
|
-
hubUrl,
|
|
89730
|
-
hubMeshAddress,
|
|
89731
|
-
caFingerprint: caFingerprintCompact(ca.certPem),
|
|
89732
|
-
nodeId: input.nodeId
|
|
89733
|
-
};
|
|
89734
|
-
}
|
|
89735
88556
|
/** D821 — short-lived ticket for the agent's `:4444` unlock session. */
|
|
89736
88557
|
async mintAgentUiUnlock(input) {
|
|
89737
|
-
const
|
|
89738
|
-
if (secrets === null) throw new Error("system-config: no keychain door — cannot mint an unlock ticket");
|
|
89739
|
-
const entry = (await secrets.resolve([require_constants$8.CLUSTER_SECRET_REF]))[require_constants$8.CLUSTER_SECRET_REF];
|
|
89740
|
-
if (entry?.kind !== "value") throw new Error("system-config: cluster secret is not available — cannot mint an unlock ticket");
|
|
88558
|
+
const ca = requireProcessMeshCa();
|
|
89741
88559
|
if (input.dashboardBaseUrl !== void 0) {
|
|
89742
88560
|
const origins = await this.readAgentDashboardOrigins();
|
|
89743
88561
|
if (!isAllowedAgentDashboardReturnTo(input.dashboardBaseUrl, origins)) throw new Error("dashboardBaseUrl is not an allowed agent dashboard origin (:4444 or agentDashboardOrigins)");
|
|
@@ -89745,10 +88563,10 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89745
88563
|
if (!isKnownAgentAddress(input.dashboardBaseUrl, known, origins)) throw new Error(`dashboardBaseUrl is not an address this hub knows for "${input.nodeId}" - open the agent at its own address`);
|
|
89746
88564
|
}
|
|
89747
88565
|
const ticket = mintAgentUiUnlockTicket({
|
|
89748
|
-
|
|
88566
|
+
caKeyPem: ca.keyPem,
|
|
89749
88567
|
nodeId: input.nodeId
|
|
89750
88568
|
});
|
|
89751
|
-
const payloadJson = Buffer.from(ticket.split(".")[
|
|
88569
|
+
const payloadJson = Buffer.from(ticket.split(".")[1] ?? "", "base64url").toString("utf8");
|
|
89752
88570
|
const exp = JSON.parse(payloadJson).exp ?? 0;
|
|
89753
88571
|
const dashboardUrl = input.dashboardBaseUrl === void 0 ? void 0 : (() => {
|
|
89754
88572
|
const u = new URL(input.dashboardBaseUrl);
|
|
@@ -89769,24 +88587,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89769
88587
|
return [];
|
|
89770
88588
|
}
|
|
89771
88589
|
}
|
|
89772
|
-
async resolveHubUrl() {
|
|
89773
|
-
try {
|
|
89774
|
-
const book = await this.ctx.api?.localNetwork?.getAddresses?.query({ scheme: "https" });
|
|
89775
|
-
const url = book?.roles?.publicEndpoint?.resolved ?? book?.roles?.internal?.resolved ?? null;
|
|
89776
|
-
if (typeof url === "string" && url.length > 0) return url;
|
|
89777
|
-
} catch {}
|
|
89778
|
-
const host = (await this.ctx.settings?.getSection("server"))?.["host"];
|
|
89779
|
-
const port = (await this.ctx.settings?.getSection("server"))?.["port"];
|
|
89780
|
-
return `https://${typeof host === "string" && host.length > 0 && host !== "0.0.0.0" ? host : "127.0.0.1"}:${typeof port === "number" ? port : Number(port) || 4443}`;
|
|
89781
|
-
}
|
|
89782
|
-
async resolveHubMeshAddress() {
|
|
89783
|
-
try {
|
|
89784
|
-
const base = (await this.ctx.api?.localNetwork?.getAddresses?.query({}))?.roles?.internal?.resolved;
|
|
89785
|
-
if (typeof base === "string" && base.length > 0) return `${new URL(base).hostname}:${require_constants$8.DEFAULT_HUB_TLS_TCP_PORT}`;
|
|
89786
|
-
} catch {}
|
|
89787
|
-
const host = (await this.ctx.settings?.getSection("server"))?.["host"];
|
|
89788
|
-
return `${typeof host === "string" && host.length > 0 && host !== "0.0.0.0" ? host : "127.0.0.1"}:${require_constants$8.DEFAULT_HUB_TLS_TCP_PORT}`;
|
|
89789
|
-
}
|
|
89790
88590
|
/** The keychain handle for owner `system`; `null` where there is no door. */
|
|
89791
88591
|
systemSecrets() {
|
|
89792
88592
|
const forOwner = this.ctx.secrets?.forOwner ?? null;
|
|
@@ -89879,14 +88679,9 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89879
88679
|
{
|
|
89880
88680
|
id: SYSTEM_CONFIG_CLUSTER_SECTION_ID,
|
|
89881
88681
|
title: SECTION_TITLES["cluster"],
|
|
89882
|
-
description: "Agents
|
|
88682
|
+
description: "Agents join this hub by pairing (System → Cluster → Agents): the hub signs a certificate for the agent after the operator confirms the same 6-digit code on the hub and in the agent's own page. There is no shared cluster secret.",
|
|
89883
88683
|
columns: 1,
|
|
89884
|
-
fields: [
|
|
89885
|
-
type: "password",
|
|
89886
|
-
key: CLUSTER_SECRET_FIELD,
|
|
89887
|
-
label: "Cluster secret",
|
|
89888
|
-
description: "Reveal and copy into each agent to pair. Saving a new value rotates it for every agent."
|
|
89889
|
-
}]
|
|
88684
|
+
fields: []
|
|
89890
88685
|
}
|
|
89891
88686
|
] };
|
|
89892
88687
|
}
|
|
@@ -89909,9 +88704,9 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89909
88704
|
}
|
|
89910
88705
|
/**
|
|
89911
88706
|
* The admin UI / `addonSettings` cap prefer {@link BaseAddon.updateGlobalSettingsAsOperator}.
|
|
89912
|
-
* That BaseAddon path writes the generic addon store and never reaches
|
|
89913
|
-
*
|
|
89914
|
-
*
|
|
88707
|
+
* That BaseAddon path writes the generic addon store and never reaches the
|
|
88708
|
+
* yml sections. Route the operator write through the same section-aware path
|
|
88709
|
+
* as {@link updateGlobalSettings}.
|
|
89915
88710
|
*/
|
|
89916
88711
|
async updateGlobalSettingsAsOperator(patch, _nodeId) {
|
|
89917
88712
|
await this.updateGlobalSettings(patch);
|
|
@@ -89928,6 +88723,10 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89928
88723
|
this.ctx.logger.warn("cluster.agentDashboardOrigins is no longer writable from settings — ignoring this patch");
|
|
89929
88724
|
continue;
|
|
89930
88725
|
}
|
|
88726
|
+
if (RETIRED_CLUSTER_KEYS.has(key)) {
|
|
88727
|
+
this.ctx.logger.warn(`cluster.${key} is retired (D857) — agents are paired by certificate; ignoring this patch`);
|
|
88728
|
+
continue;
|
|
88729
|
+
}
|
|
89931
88730
|
const section = KEY_TO_SECTION[key];
|
|
89932
88731
|
if (section === void 0) {
|
|
89933
88732
|
this.ctx.logger.warn("update ignored unknown key (not mapped to any section)", { meta: { key } });
|
|
@@ -89949,10 +88748,6 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89949
88748
|
bucket[key] = value;
|
|
89950
88749
|
}
|
|
89951
88750
|
for (const [section, sectionPatch] of perSection) {
|
|
89952
|
-
if (section === "cluster") {
|
|
89953
|
-
await this.writeClusterSection(sectionPatch);
|
|
89954
|
-
continue;
|
|
89955
|
-
}
|
|
89956
88751
|
await this.ctx.settings.setSection(section, sectionPatch);
|
|
89957
88752
|
this.ctx.logger.info("Wrote keys to section", { meta: {
|
|
89958
88753
|
section,
|
|
@@ -89960,79 +88755,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
|
|
|
89960
88755
|
} });
|
|
89961
88756
|
}
|
|
89962
88757
|
}
|
|
89963
|
-
/**
|
|
89964
|
-
* The cluster secret's save path: the value goes to the keychain (owner
|
|
89965
|
-
* `system`), the row gets the marker; `''` / a view keeps. `$secretClear` is
|
|
89966
|
-
* REFUSED: the secret is mandatory (D802). A value the keychain cannot store
|
|
89967
|
-
* is REFUSED — never written inline (D787, P5). Mesh auth mode is always
|
|
89968
|
-
* enforced (D821) — a legacy `meshAuth` in the patch is ignored.
|
|
89969
|
-
*/
|
|
89970
|
-
async writeClusterSection(patch) {
|
|
89971
|
-
const { [MESH_AUTH_MODE_FIELD]: _legacyMode, ...secretPatch } = patch;
|
|
89972
|
-
await this.writeMeshAuthMode("enforced");
|
|
89973
|
-
if (Object.keys(secretPatch).length === 0) return;
|
|
89974
|
-
if (require_dist.isSecretClear(secretPatch["clusterSecret"])) throw new Error("The cluster secret is mandatory and cannot be cleared — save a new value to rotate it");
|
|
89975
|
-
await this.storeClusterSecret(secretPatch);
|
|
89976
|
-
this.ctx.logger.info("Cluster secret updated");
|
|
89977
|
-
await this.clusterSecretKeeper?.reload();
|
|
89978
|
-
}
|
|
89979
|
-
/** Persist + publish mesh auth mode (always `enforced` after D821). */
|
|
89980
|
-
async writeMeshAuthMode(mode) {
|
|
89981
|
-
await this.ctx.settings.setSection("cluster", { [MESH_AUTH_MODE_FIELD]: mode });
|
|
89982
|
-
setProcessMeshAuthMode(mode);
|
|
89983
|
-
}
|
|
89984
|
-
/**
|
|
89985
|
-
* First boot, or a keychain reset that cleared the marker (D802): a fresh
|
|
89986
|
-
* random secret, stored like an operator save. Mesh auth stays enforced
|
|
89987
|
-
* (D821) — every agent must present the secret; there is no transition window.
|
|
89988
|
-
*/
|
|
89989
|
-
async generateClusterSecret() {
|
|
89990
|
-
const settings = this.ctx.settings;
|
|
89991
|
-
const secrets = this.systemSecrets();
|
|
89992
|
-
if (!settings || secrets === null) throw new Error("system-config: no keychain door — the cluster secret cannot be generated");
|
|
89993
|
-
const existing = (await secrets.resolve([require_constants$8.CLUSTER_SECRET_REF]))[require_constants$8.CLUSTER_SECRET_REF];
|
|
89994
|
-
if (existing?.kind === "value") {
|
|
89995
|
-
await settings.setSection("cluster", { [CLUSTER_SECRET_FIELD]: require_dist.makeSecretMarker(require_constants$8.CLUSTER_SECRET_REF) });
|
|
89996
|
-
this.ctx.logger.warn("The cluster secret row was empty but the keychain holds a value — re-adopted it");
|
|
89997
|
-
return;
|
|
89998
|
-
}
|
|
89999
|
-
if (existing?.kind !== "missing") throw new Error(`the keychain cannot answer for the cluster secret (${existing?.kind ?? "no answer"})`);
|
|
90000
|
-
const value = (0, node_crypto.randomBytes)(GENERATED_SECRET_BYTES).toString("base64url");
|
|
90001
|
-
await this.storeClusterSecret({ [CLUSTER_SECRET_FIELD]: value });
|
|
90002
|
-
await settings.setSection("cluster", { [MESH_AUTH_MODE_FIELD]: "enforced" });
|
|
90003
|
-
setProcessMeshAuthMode("enforced");
|
|
90004
|
-
}
|
|
90005
|
-
async storeClusterSecret(patch) {
|
|
90006
|
-
const settings = this.ctx.settings;
|
|
90007
|
-
if (!settings) throw new Error("system-config: ctx.settings not available");
|
|
90008
|
-
const secrets = this.systemSecrets();
|
|
90009
|
-
if (secrets === null) throw new Error("system-config: no keychain door — the cluster secret cannot be stored");
|
|
90010
|
-
const stored = await settings.getSection("cluster");
|
|
90011
|
-
const result = await require_dist.transformSecretWrite({
|
|
90012
|
-
tree: require_dist.secretTreeFromSchema(this.buildGlobalSchema()),
|
|
90013
|
-
secrets,
|
|
90014
|
-
patch,
|
|
90015
|
-
stored,
|
|
90016
|
-
operatorWrite: true
|
|
90017
|
-
});
|
|
90018
|
-
if (Object.keys(result.patch).length > 0) await settings.setSection("cluster", result.patch);
|
|
90019
|
-
const { orphaned } = await result.afterWrite();
|
|
90020
|
-
if (orphaned.length > 0) this.ctx.logger.warn("an old cluster secret value could not be deleted from the keychain", { meta: { refs: orphaned } });
|
|
90021
|
-
}
|
|
90022
88758
|
};
|
|
90023
|
-
function parseMintJoinTokenInput(input) {
|
|
90024
|
-
if (input === null || input === void 0 || typeof input !== "object") throw new Error("system-config: mintJoinToken requires { nodeId }");
|
|
90025
|
-
const nodeId = Reflect.get(input, "nodeId");
|
|
90026
|
-
if (typeof nodeId !== "string" || nodeId.length === 0) throw new Error("system-config: mintJoinToken requires { nodeId } - the node the token is for");
|
|
90027
|
-
const out = { nodeId };
|
|
90028
|
-
const hubUrl = Reflect.get(input, "hubUrl");
|
|
90029
|
-
const hubMeshAddress = Reflect.get(input, "hubMeshAddress");
|
|
90030
|
-
const ttlSec = Reflect.get(input, "ttlSec");
|
|
90031
|
-
if (typeof hubUrl === "string") out.hubUrl = hubUrl;
|
|
90032
|
-
if (typeof hubMeshAddress === "string") out.hubMeshAddress = hubMeshAddress;
|
|
90033
|
-
if (typeof ttlSec === "number") out.ttlSec = ttlSec;
|
|
90034
|
-
return out;
|
|
90035
|
-
}
|
|
90036
88759
|
function parseMintUnlockInput(input) {
|
|
90037
88760
|
if (input === null || typeof input !== "object") throw new Error("system-config: mintAgentUiUnlockTicket requires { nodeId }");
|
|
90038
88761
|
const nodeId = Reflect.get(input, "nodeId");
|
|
@@ -90043,19 +88766,8 @@ function parseMintUnlockInput(input) {
|
|
|
90043
88766
|
...typeof dashboardBaseUrl === "string" ? { dashboardBaseUrl } : {}
|
|
90044
88767
|
};
|
|
90045
88768
|
}
|
|
90046
|
-
/** Read `exp` from an unencrypted JWT payload (no verify — already minted here). */
|
|
90047
|
-
function readJwtExp(token) {
|
|
90048
|
-
const parts = token.split(".");
|
|
90049
|
-
if (parts.length < 2 || parts[1] === void 0) return 0;
|
|
90050
|
-
const json = Buffer.from(parts[1], "base64url").toString("utf8");
|
|
90051
|
-
const payload = JSON.parse(json);
|
|
90052
|
-
if (payload === null || typeof payload !== "object") return 0;
|
|
90053
|
-
const exp = Reflect.get(payload, "exp");
|
|
90054
|
-
return typeof exp === "number" ? exp : 0;
|
|
90055
|
-
}
|
|
90056
88769
|
//#endregion
|
|
90057
88770
|
exports.AGENT_DASHBOARD_ORIGINS_FIELD = AGENT_DASHBOARD_ORIGINS_FIELD;
|
|
90058
|
-
exports.AGENT_UI_UNLOCK_DOMAIN = AGENT_UI_UNLOCK_DOMAIN;
|
|
90059
88771
|
exports.AGENT_UI_UNLOCK_TTL_MS = AGENT_UI_UNLOCK_TTL_MS;
|
|
90060
88772
|
exports.AGENT_UI_UNLOCK_TYP = AGENT_UI_UNLOCK_TYP;
|
|
90061
88773
|
exports.AGENT_UI_UNLOCK_USE = AGENT_UI_UNLOCK_USE;
|
|
@@ -90063,8 +88775,6 @@ exports.AGENT_UI_UNLOCK_VERSION = AGENT_UI_UNLOCK_VERSION;
|
|
|
90063
88775
|
exports.AgentPairing = AgentPairing;
|
|
90064
88776
|
exports.Errors = Errors;
|
|
90065
88777
|
exports.HubPairing = HubPairing;
|
|
90066
|
-
exports.JoinTokenJtiStore = JoinTokenJtiStore;
|
|
90067
|
-
exports.MESH_AUTH_MODE_FIELD = MESH_AUTH_MODE_FIELD;
|
|
90068
88778
|
exports.MESH_NODE_CERTIFICATES_COLLECTION = MESH_NODE_CERTIFICATES_COLLECTION;
|
|
90069
88779
|
exports.MESH_NODE_CERTIFICATES_COLUMNS = MESH_NODE_CERTIFICATES_COLUMNS;
|
|
90070
88780
|
exports.MESH_TLS_PORT_HELLO_FIELD = MESH_TLS_PORT_HELLO_FIELD;
|
|
@@ -90085,7 +88795,6 @@ exports.ServiceBroker = ServiceBroker;
|
|
|
90085
88795
|
exports.SystemConfigAddon = SystemConfigAddon;
|
|
90086
88796
|
exports.default = SystemConfigAddon;
|
|
90087
88797
|
exports.TlsTcpTransporter = TlsTcpTransporter;
|
|
90088
|
-
exports.Transporters = Transporters;
|
|
90089
88798
|
exports.UnlockTicketJtiStore = UnlockTicketJtiStore;
|
|
90090
88799
|
exports.caFingerprint = caFingerprint;
|
|
90091
88800
|
exports.caFingerprintCompact = caFingerprintCompact;
|
|
@@ -90097,12 +88806,9 @@ exports.describeCsr = describeCsr;
|
|
|
90097
88806
|
exports.describeMeshLeaf = describeMeshLeaf;
|
|
90098
88807
|
exports.dropProcessPeer = dropProcessPeer;
|
|
90099
88808
|
exports.emitProcessNodeRegistered = emitProcessNodeRegistered;
|
|
90100
|
-
exports.enrollMeshNode = enrollMeshNode;
|
|
90101
88809
|
exports.exportMeshPrivateKeyPem = exportMeshPrivateKeyPem;
|
|
90102
88810
|
exports.generateMeshCa = generateMeshCa;
|
|
90103
88811
|
exports.generateMeshKeyPair = generateMeshKeyPair;
|
|
90104
|
-
exports.getProcessMeshAuthMode = getProcessMeshAuthMode;
|
|
90105
|
-
exports.getProcessMeshAuthStatus = getProcessMeshAuthStatus;
|
|
90106
88812
|
exports.getProcessMeshCaState = getProcessMeshCaState;
|
|
90107
88813
|
exports.getProcessMeshCertificateRegistry = getProcessMeshCertificateRegistry;
|
|
90108
88814
|
exports.getProcessMeshTlsListenerState = getProcessMeshTlsListenerState;
|
|
@@ -90110,7 +88816,6 @@ exports.getProcessNodeMeshTransport = getProcessNodeMeshTransport;
|
|
|
90110
88816
|
exports.getProcessPeerLeaf = getProcessPeerLeaf;
|
|
90111
88817
|
exports.hubHostFromMeshAddress = hubHostFromMeshAddress;
|
|
90112
88818
|
exports.isAllowedAgentDashboardReturnTo = isAllowedAgentDashboardReturnTo;
|
|
90113
|
-
exports.isMeshAuthMode = isMeshAuthMode;
|
|
90114
88819
|
exports.isProcessVerifiedMeshPeer = isProcessVerifiedMeshPeer;
|
|
90115
88820
|
exports.isValidAgentNodeId = isValidAgentNodeId;
|
|
90116
88821
|
exports.issueMeshLeafForNode = issueMeshLeafForNode;
|
|
@@ -90118,31 +88823,21 @@ exports.issueMeshLeafFromCsr = issueMeshLeafFromCsr;
|
|
|
90118
88823
|
exports.keyFingerprintShort = keyFingerprintShort;
|
|
90119
88824
|
exports.loadMeshCa = loadMeshCa;
|
|
90120
88825
|
exports.mintAgentUiUnlockTicket = mintAgentUiUnlockTicket;
|
|
90121
|
-
exports.mintAgentUiUnlockTicketEs256 = mintAgentUiUnlockTicketEs256;
|
|
90122
|
-
exports.mintMeshJoinToken = mintMeshJoinToken;
|
|
90123
88826
|
exports.normalizeIp = normalizeIp;
|
|
90124
88827
|
exports.onProcessNodeRegistered = onProcessNodeRegistered;
|
|
90125
88828
|
exports.openMeshTlsWhenRevocationsLoaded = openMeshTlsWhenRevocationsLoaded;
|
|
90126
88829
|
exports.parseAgentDashboardOrigins = parseAgentDashboardOrigins;
|
|
90127
88830
|
exports.parseCidrList = parseCidrList;
|
|
90128
|
-
exports.parseMeshAuthMode = parseMeshAuthMode;
|
|
90129
|
-
exports.processJoinTokenJtiStore = processJoinTokenJtiStore;
|
|
90130
88831
|
exports.processMeshCrl = processMeshCrl;
|
|
90131
88832
|
exports.readCidrSetting = readCidrSetting;
|
|
90132
88833
|
exports.renewMeshCertificate = renewMeshCertificate;
|
|
90133
|
-
exports.requestProcessMeshEnforcement = requestProcessMeshEnforcement;
|
|
90134
88834
|
exports.requireProcessMeshCa = requireProcessMeshCa;
|
|
90135
88835
|
exports.revokeMeshCertificate = revokeMeshCertificate;
|
|
90136
|
-
exports.setProcessMeshAuthMode = setProcessMeshAuthMode;
|
|
90137
|
-
exports.setProcessMeshAuthStatusSource = setProcessMeshAuthStatusSource;
|
|
90138
88836
|
exports.setProcessMeshCertificateRegistry = setProcessMeshCertificateRegistry;
|
|
90139
|
-
exports.setProcessMeshEnforcer = setProcessMeshEnforcer;
|
|
90140
88837
|
exports.setProcessMeshPeerTransportLookup = setProcessMeshPeerTransportLookup;
|
|
90141
88838
|
exports.setProcessMeshTlsEnabler = setProcessMeshTlsEnabler;
|
|
90142
88839
|
exports.setProcessMeshTlsListenerState = setProcessMeshTlsListenerState;
|
|
90143
88840
|
exports.signPairingProof = signPairingProof;
|
|
90144
88841
|
exports.systemConfigMeshActions = systemConfigMeshActions;
|
|
90145
88842
|
exports.verifyAgentUiUnlockTicket = verifyAgentUiUnlockTicket;
|
|
90146
|
-
exports.verifyAgentUiUnlockTicketEs256 = verifyAgentUiUnlockTicketEs256;
|
|
90147
|
-
exports.verifyMeshJoinToken = verifyMeshJoinToken;
|
|
90148
88843
|
exports.verifyPairingProof = verifyPairingProof;
|