@camstack/system 1.2.428 → 1.2.429
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/agent-https-names-CpUSuP4w.js +120 -0
- package/dist/agent-https-names-uetr4OQl.mjs +91 -0
- package/dist/auth/auth-audit-log.d.ts +1 -1
- package/dist/auth/device-ca-store.d.ts +57 -0
- package/dist/auth/device-ca.d.ts +75 -0
- package/dist/auth/device-credential-manager.d.ts +154 -0
- package/dist/auth/login-session-manager.d.ts +14 -2
- package/dist/auth/user-management-internal.d.ts +10 -1
- 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 +10 -6
- package/dist/builtins/keychain/index.mjs +8 -4
- 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.d.ts +6 -0
- package/dist/builtins/local-auth/local-auth.addon.js +955 -47
- package/dist/builtins/local-auth/local-auth.addon.mjs +946 -41
- package/dist/builtins/local-network/local-network.addon.js +2 -2
- package/dist/builtins/local-network/local-network.addon.mjs +2 -2
- 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 +18 -0
- package/dist/builtins/system-config/system-config.addon.js +834 -18
- package/dist/builtins/system-config/system-config.addon.mjs +819 -19
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{composition-sources-DvCGZEUI.js → composition-sources-C2VNX6tF.js} +1 -1
- package/dist/{composition-sources-BQNxXQZG.mjs → composition-sources-SYtYuAgh.mjs} +1 -1
- package/dist/{constants-CR4If_lP.mjs → constants-CKuWoWvc.mjs} +1 -1
- package/dist/{constants-CCSJGnjs.js → constants-RI-hGP5S.js} +1 -1
- package/dist/device-ca-BWfdDB3k.js +462 -0
- package/dist/device-ca-R7DKKZL6.mjs +355 -0
- package/dist/{dist-BQG3QFg7.js → dist-Bgy_AmwX.js} +554 -0
- package/dist/{dist-DHSJV4Qc.mjs → dist-CSSfTM18.mjs} +507 -1
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +59 -12
- package/dist/index.mjs +10 -9
- package/dist/kernel/index.d.ts +2 -2
- package/dist/kernel/moleculer/mesh-mtls/index.d.ts +4 -1
- package/dist/kernel/moleculer/mesh-mtls/mesh-certificate-registry.d.ts +91 -0
- package/dist/kernel/moleculer/mesh-mtls/mesh-enroll.d.ts +4 -0
- package/dist/kernel/moleculer/mesh-mtls/mesh-peer-transport.d.ts +23 -0
- package/dist/kernel/moleculer/mesh-mtls/mesh-renewal.d.ts +126 -0
- package/dist/kernel/moleculer/mesh-mtls/mesh-tls-gate.d.ts +40 -0
- package/dist/kernel/moleculer/mesh-mtls/tls-tcp-transporter.d.ts +15 -0
- package/dist/{restore-archive-DH1Pxq_1.mjs → restore-archive-AIwMHO5_.mjs} +1 -1
- package/dist/{restore-archive-Dccm8lkA.js → restore-archive-BYUEMsog.js} +1 -1
- package/dist/{retired-settings-keys-BfGaSeQI.js → retired-settings-keys-BTPkRLTS.js} +1 -1
- package/dist/{retired-settings-keys-CPz7zpza.mjs → retired-settings-keys-H0rYXT27.mjs} +1 -1
- package/dist/tls/agent-https-names.d.ts +27 -0
- package/dist/tls/agent-https.d.ts +111 -0
- package/dist/tls/cert-issue.d.ts +7 -0
- package/dist/tls/index.d.ts +3 -0
- package/dist/{tls-BgImdxCO.js → tls-C5IYg3V5.js} +406 -0
- package/dist/{tls-CaOLZ09W.mjs → tls-CpcGkeJV.mjs} +314 -4
- package/dist/{wal-maintenance-DItkuOvu.js → wal-maintenance-BSGsxKW7.js} +0 -0
- package/dist/{wal-maintenance-Drqhcjit.mjs → wal-maintenance-DW0FfGV7.mjs} +0 -0
- package/package.json +4 -1
- package/dist/jwt-signing-key-BZm055IP.js +0 -174
- package/dist/jwt-signing-key-DL-qk1SM.mjs +0 -127
|
@@ -3,7 +3,7 @@ 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-Bgy_AmwX.js");
|
|
7
7
|
const require_formatter = require("../../formatter-DqAKDlvN.js");
|
|
8
8
|
let node_path = require("node:path");
|
|
9
9
|
node_path = require_chunk.__toESM(node_path);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _r as BaseAddon, an as logDestinationCapability } from "../../dist-CSSfTM18.mjs";
|
|
2
2
|
import { t as formatLogLine } from "../../formatter-B7qW8bPJ.mjs";
|
|
3
3
|
import * as path$1 from "node:path";
|
|
4
4
|
import path from "node:path";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { gr as errMsg, lr as compositionSourceKey } from "./dist-CSSfTM18.mjs";
|
|
2
2
|
//#region src/builtins/core-blocks/composition-sources.ts
|
|
3
3
|
/**
|
|
4
4
|
* Describe what a composition reads and writes for SAVE-time validation
|
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
const require_dist = require("./dist-Bgy_AmwX.js");
|
|
2
|
+
const require_x509_es = require("./x509.es-Dzl0BbmG.js");
|
|
3
|
+
let node_crypto = require("node:crypto");
|
|
4
|
+
//#region src/auth/jwt-signing-key.ts
|
|
5
|
+
/**
|
|
6
|
+
* The hub's session signing key — the HMAC key every JWT this hub mints
|
|
7
|
+
* (sessions, SSO bridge, TOTP challenges, service tokens) is signed with.
|
|
8
|
+
*
|
|
9
|
+
* It lives in the keychain, owner `system` ({@link JWT_SIGNING_KEY_REF}), and
|
|
10
|
+
* nowhere else: no environment variable, no `config.yaml` key (D797). The
|
|
11
|
+
* hub's `local-auth` builtin loads it after the keychain booted and registers
|
|
12
|
+
* it here; every `AuthManager` in the process asks this slot on every mint and
|
|
13
|
+
* every verify, so a key that arrives (or changes) after construction is used
|
|
14
|
+
* from the next call on.
|
|
15
|
+
*
|
|
16
|
+
* ## A locked keychain fails closed, visibly
|
|
17
|
+
*
|
|
18
|
+
* While the key cannot be read, sessions can be neither minted nor verified:
|
|
19
|
+
* {@link JwtSigningKeySource.current} throws {@link JwtSigningKeyUnavailableError}
|
|
20
|
+
* (a login answers that error, a bearer check reads it as "not authenticated").
|
|
21
|
+
* There is deliberately NO fallback — not an env var, and not a fresh random
|
|
22
|
+
* key, which would invalidate every session and every app token without
|
|
23
|
+
* anyone having asked for it. A key is generated ONLY when the keychain
|
|
24
|
+
* answers that none is stored (`missing`), i.e. on a fresh hub.
|
|
25
|
+
*
|
|
26
|
+
* Process-global through a registered symbol, like the desktop platform key,
|
|
27
|
+
* so a second copy of this module (an addon bundle) sees the same key.
|
|
28
|
+
*/
|
|
29
|
+
/** The keychain owner of every system-held secret. */
|
|
30
|
+
var SYSTEM_SECRET_OWNER = "system";
|
|
31
|
+
/** `secret://system/global/jwtSigningKey`. */
|
|
32
|
+
var JWT_SIGNING_KEY_REF = require_dist.buildSecretRef({
|
|
33
|
+
owner: SYSTEM_SECRET_OWNER,
|
|
34
|
+
scope: { kind: "global" },
|
|
35
|
+
fieldPath: "jwtSigningKey"
|
|
36
|
+
});
|
|
37
|
+
/** Sessions cannot be minted or verified: the signing key is not loaded. */
|
|
38
|
+
var JwtSigningKeyUnavailableError = class extends Error {
|
|
39
|
+
reason;
|
|
40
|
+
constructor(reason) {
|
|
41
|
+
super(`sessions are unavailable: the session signing key could not be read from the keychain (${reason}). Unlock the keychain (System → Secrets, or fix keychain.keyFile and restart).`);
|
|
42
|
+
this.reason = reason;
|
|
43
|
+
this.name = "JwtSigningKeyUnavailableError";
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var SLOT = Symbol.for("camstack.auth.jwt-signing-key");
|
|
47
|
+
var NOT_LOADED = {
|
|
48
|
+
state: "unavailable",
|
|
49
|
+
reason: "not-loaded"
|
|
50
|
+
};
|
|
51
|
+
function isState(value) {
|
|
52
|
+
if (value === null || typeof value !== "object") return false;
|
|
53
|
+
const state = Reflect.get(value, "state");
|
|
54
|
+
if (state === "ready") return typeof Reflect.get(value, "key") === "string";
|
|
55
|
+
return state === "unavailable" && typeof Reflect.get(value, "reason") === "string";
|
|
56
|
+
}
|
|
57
|
+
/** Register the loaded (or unloadable) key. Called by the hub's `local-auth`. */
|
|
58
|
+
function setProcessJwtSigningKey(state) {
|
|
59
|
+
Reflect.set(globalThis, SLOT, state);
|
|
60
|
+
}
|
|
61
|
+
function getProcessJwtSigningKeyState() {
|
|
62
|
+
const value = Reflect.get(globalThis, SLOT);
|
|
63
|
+
return isState(value) ? value : NOT_LOADED;
|
|
64
|
+
}
|
|
65
|
+
/** The process slot — the default source of every `AuthManager`. */
|
|
66
|
+
var processJwtSigningKey = { current() {
|
|
67
|
+
const state = getProcessJwtSigningKeyState();
|
|
68
|
+
if (state.state === "ready") return state.key;
|
|
69
|
+
throw new JwtSigningKeyUnavailableError(state.reason);
|
|
70
|
+
} };
|
|
71
|
+
/** A fixed key — tests, and nothing else. */
|
|
72
|
+
function staticJwtSigningKey(key) {
|
|
73
|
+
return { current: () => key };
|
|
74
|
+
}
|
|
75
|
+
/** 32 random bytes, hex. */
|
|
76
|
+
function generateJwtSigningKey() {
|
|
77
|
+
return (0, node_crypto.randomBytes)(32).toString("hex");
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Read the key from the keychain; generate and store one ONLY when the
|
|
81
|
+
* keychain answers that none exists. Never throws.
|
|
82
|
+
*/
|
|
83
|
+
async function loadJwtSigningKey(deps) {
|
|
84
|
+
let entry;
|
|
85
|
+
try {
|
|
86
|
+
entry = (await deps.secrets.resolve([JWT_SIGNING_KEY_REF]))[JWT_SIGNING_KEY_REF];
|
|
87
|
+
} catch (err) {
|
|
88
|
+
return {
|
|
89
|
+
state: "unavailable",
|
|
90
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
if (entry === void 0) return {
|
|
94
|
+
state: "unavailable",
|
|
95
|
+
reason: "no-answer"
|
|
96
|
+
};
|
|
97
|
+
switch (entry.kind) {
|
|
98
|
+
case "value": return {
|
|
99
|
+
state: "ready",
|
|
100
|
+
key: entry.value
|
|
101
|
+
};
|
|
102
|
+
case "unavailable": return {
|
|
103
|
+
state: "unavailable",
|
|
104
|
+
reason: entry.reason
|
|
105
|
+
};
|
|
106
|
+
case "forbidden": return {
|
|
107
|
+
state: "unavailable",
|
|
108
|
+
reason: "forbidden"
|
|
109
|
+
};
|
|
110
|
+
case "missing": {
|
|
111
|
+
const key = (deps.generate ?? generateJwtSigningKey)();
|
|
112
|
+
try {
|
|
113
|
+
await deps.secrets.put(JWT_SIGNING_KEY_REF, key);
|
|
114
|
+
} catch (err) {
|
|
115
|
+
return {
|
|
116
|
+
state: "unavailable",
|
|
117
|
+
reason: `could not store a new key: ${err instanceof Error ? err.message : String(err)}`
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
state: "ready",
|
|
122
|
+
key
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//#endregion
|
|
128
|
+
//#region src/auth/device-ca.ts
|
|
129
|
+
require_x509_es.cryptoProvider.set(node_crypto.webcrypto);
|
|
130
|
+
var MS_PER_DAY = 864e5;
|
|
131
|
+
var CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2";
|
|
132
|
+
/** `secret://system/global/deviceCaKey` — EC P-256 PKCS#8 PEM of the device CA. */
|
|
133
|
+
var DEVICE_CA_KEY_REF = require_dist.buildSecretRef({
|
|
134
|
+
owner: "system",
|
|
135
|
+
scope: { kind: "global" },
|
|
136
|
+
fieldPath: "deviceCaKey"
|
|
137
|
+
});
|
|
138
|
+
/** Settings section / field holding the public CA certificate PEM (beside `cluster.meshCa`). */
|
|
139
|
+
var DEVICE_CA_SETTINGS_SECTION = "cluster";
|
|
140
|
+
var DEVICE_CA_FIELD = "deviceCa";
|
|
141
|
+
var DEVICE_CA_COMMON_NAME = "CamStack Device CA";
|
|
142
|
+
var DEVICE_CA_VALIDITY_DAYS = 3650;
|
|
143
|
+
var KEY_ALGORITHM = {
|
|
144
|
+
name: "ECDSA",
|
|
145
|
+
namedCurve: "P-256"
|
|
146
|
+
};
|
|
147
|
+
var SIGNING_ALGORITHM = {
|
|
148
|
+
name: "ECDSA",
|
|
149
|
+
hash: "SHA-256"
|
|
150
|
+
};
|
|
151
|
+
function freshSerial() {
|
|
152
|
+
return `00${(0, node_crypto.randomBytes)(16).toString("hex")}`;
|
|
153
|
+
}
|
|
154
|
+
function certPemOf(cert) {
|
|
155
|
+
return `${cert.toString("pem")}\n`;
|
|
156
|
+
}
|
|
157
|
+
async function generateDeviceCa(now = /* @__PURE__ */ new Date()) {
|
|
158
|
+
const keys = await node_crypto.webcrypto.subtle.generateKey(KEY_ALGORITHM, true, ["sign", "verify"]);
|
|
159
|
+
const extensions = [
|
|
160
|
+
new require_x509_es.BasicConstraintsExtension(true, 0, true),
|
|
161
|
+
new require_x509_es.KeyUsagesExtension(require_x509_es.KeyUsageFlags.keyCertSign | require_x509_es.KeyUsageFlags.cRLSign, true),
|
|
162
|
+
await require_x509_es.SubjectKeyIdentifierExtension.create(keys.publicKey)
|
|
163
|
+
];
|
|
164
|
+
const cert = await require_x509_es.X509CertificateGenerator.createSelfSigned({
|
|
165
|
+
serialNumber: freshSerial(),
|
|
166
|
+
name: `CN=${DEVICE_CA_COMMON_NAME}`,
|
|
167
|
+
notBefore: now,
|
|
168
|
+
notAfter: new Date(now.getTime() + DEVICE_CA_VALIDITY_DAYS * MS_PER_DAY),
|
|
169
|
+
keys,
|
|
170
|
+
signingAlgorithm: SIGNING_ALGORITHM,
|
|
171
|
+
extensions
|
|
172
|
+
});
|
|
173
|
+
const pkcs8 = await node_crypto.webcrypto.subtle.exportKey("pkcs8", keys.privateKey);
|
|
174
|
+
return {
|
|
175
|
+
certPem: certPemOf(cert),
|
|
176
|
+
keyPem: `${require_x509_es.PemConverter.encode(pkcs8, "PRIVATE KEY")}\n`,
|
|
177
|
+
cert,
|
|
178
|
+
privateKey: keys.privateKey
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
async function loadDeviceCa(certPem, keyPem) {
|
|
182
|
+
return {
|
|
183
|
+
certPem,
|
|
184
|
+
keyPem,
|
|
185
|
+
cert: new require_x509_es.X509Certificate(certPem),
|
|
186
|
+
privateKey: await node_crypto.webcrypto.subtle.importKey("pkcs8", require_x509_es.PemConverter.decodeFirst(keyPem), KEY_ALGORITHM, true, ["sign"])
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* A new self-signed certificate for the SAME key pair as `keyPem` (same
|
|
191
|
+
* subject, so leaves already issued still verify): completes a CA creation that
|
|
192
|
+
* died between its key write and its certificate write.
|
|
193
|
+
*/
|
|
194
|
+
async function rebuildDeviceCaCertificate(keyPem) {
|
|
195
|
+
const privateKey = await node_crypto.webcrypto.subtle.importKey("pkcs8", require_x509_es.PemConverter.decodeFirst(keyPem), KEY_ALGORITHM, true, ["sign"]);
|
|
196
|
+
const jwk = await node_crypto.webcrypto.subtle.exportKey("jwk", privateKey);
|
|
197
|
+
const publicKey = await node_crypto.webcrypto.subtle.importKey("jwk", {
|
|
198
|
+
kty: jwk.kty,
|
|
199
|
+
crv: jwk.crv,
|
|
200
|
+
x: jwk.x,
|
|
201
|
+
y: jwk.y
|
|
202
|
+
}, KEY_ALGORITHM, true, ["verify"]);
|
|
203
|
+
const now = /* @__PURE__ */ new Date();
|
|
204
|
+
const cert = await require_x509_es.X509CertificateGenerator.createSelfSigned({
|
|
205
|
+
serialNumber: freshSerial(),
|
|
206
|
+
name: `CN=${DEVICE_CA_COMMON_NAME}`,
|
|
207
|
+
notBefore: now,
|
|
208
|
+
notAfter: new Date(now.getTime() + DEVICE_CA_VALIDITY_DAYS * MS_PER_DAY),
|
|
209
|
+
keys: {
|
|
210
|
+
privateKey,
|
|
211
|
+
publicKey
|
|
212
|
+
},
|
|
213
|
+
signingAlgorithm: SIGNING_ALGORITHM,
|
|
214
|
+
extensions: [
|
|
215
|
+
new require_x509_es.BasicConstraintsExtension(true, 0, true),
|
|
216
|
+
new require_x509_es.KeyUsagesExtension(require_x509_es.KeyUsageFlags.keyCertSign | require_x509_es.KeyUsageFlags.cRLSign, true),
|
|
217
|
+
await require_x509_es.SubjectKeyIdentifierExtension.create(publicKey)
|
|
218
|
+
]
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
certPem: certPemOf(cert),
|
|
222
|
+
keyPem,
|
|
223
|
+
cert,
|
|
224
|
+
privateKey
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/** Import (and thereby validate) a device public key: SPKI DER, ECDSA P-256. */
|
|
228
|
+
async function importDevicePublicKey(spki) {
|
|
229
|
+
return node_crypto.webcrypto.subtle.importKey("spki", spki, KEY_ALGORITHM, true, ["verify"]);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Sign a device leaf: CN = credential id; SAN URIs `camstack:credential:<id>`
|
|
233
|
+
* and `camstack:user:<userId>`; EKU clientAuth; 365 days by default.
|
|
234
|
+
*/
|
|
235
|
+
async function issueDeviceLeaf(ca, input) {
|
|
236
|
+
const publicKey = await importDevicePublicKey(input.publicKeySpki);
|
|
237
|
+
const notBefore = input.now ?? /* @__PURE__ */ new Date();
|
|
238
|
+
const notAfter = new Date(notBefore.getTime() + (input.validDays ?? 365) * MS_PER_DAY);
|
|
239
|
+
const serialNumber = freshSerial();
|
|
240
|
+
const extensions = [
|
|
241
|
+
new require_x509_es.BasicConstraintsExtension(false, void 0, true),
|
|
242
|
+
new require_x509_es.KeyUsagesExtension(require_x509_es.KeyUsageFlags.digitalSignature, true),
|
|
243
|
+
new require_x509_es.ExtendedKeyUsageExtension([CLIENT_AUTH_OID]),
|
|
244
|
+
new require_x509_es.SubjectAlternativeNameExtension([{
|
|
245
|
+
type: "url",
|
|
246
|
+
value: `${require_dist.DEVICE_SAN_CREDENTIAL_PREFIX}${input.credentialId}`
|
|
247
|
+
}, {
|
|
248
|
+
type: "url",
|
|
249
|
+
value: `${require_dist.DEVICE_SAN_USER_PREFIX}${input.userId}`
|
|
250
|
+
}]),
|
|
251
|
+
await require_x509_es.SubjectKeyIdentifierExtension.create(publicKey),
|
|
252
|
+
await require_x509_es.AuthorityKeyIdentifierExtension.create(ca.cert)
|
|
253
|
+
];
|
|
254
|
+
const pem = certPemOf(await require_x509_es.X509CertificateGenerator.create({
|
|
255
|
+
serialNumber,
|
|
256
|
+
subject: `CN=${input.credentialId}`,
|
|
257
|
+
issuer: ca.cert.subject,
|
|
258
|
+
notBefore,
|
|
259
|
+
notAfter,
|
|
260
|
+
publicKey,
|
|
261
|
+
signingKey: ca.privateKey,
|
|
262
|
+
signingAlgorithm: SIGNING_ALGORITHM,
|
|
263
|
+
extensions
|
|
264
|
+
}));
|
|
265
|
+
return {
|
|
266
|
+
certPem: pem,
|
|
267
|
+
serialNumber,
|
|
268
|
+
notBefore,
|
|
269
|
+
notAfter,
|
|
270
|
+
fingerprint: new node_crypto.X509Certificate(pem).fingerprint256
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
function sanValues(cert) {
|
|
274
|
+
const san = cert.getExtension(require_x509_es.SubjectAlternativeNameExtension);
|
|
275
|
+
if (san === null) return [];
|
|
276
|
+
return san.names.items.filter((n) => n.type === "url").map((n) => n.value);
|
|
277
|
+
}
|
|
278
|
+
/** Chain (signature by the device CA), validity window, EKU and identity of a presented leaf. */
|
|
279
|
+
async function verifyDeviceLeaf(caCertPem, leafPem, now = /* @__PURE__ */ new Date()) {
|
|
280
|
+
let leaf;
|
|
281
|
+
let ca;
|
|
282
|
+
try {
|
|
283
|
+
leaf = new require_x509_es.X509Certificate(leafPem);
|
|
284
|
+
ca = new require_x509_es.X509Certificate(caCertPem);
|
|
285
|
+
} catch {
|
|
286
|
+
return {
|
|
287
|
+
ok: false,
|
|
288
|
+
reason: "malformed-certificate"
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
if (!await leaf.verify({
|
|
292
|
+
publicKey: ca,
|
|
293
|
+
signatureOnly: true
|
|
294
|
+
}, node_crypto.webcrypto) || leaf.issuer !== ca.subject) return {
|
|
295
|
+
ok: false,
|
|
296
|
+
reason: "not-issued-by-device-ca"
|
|
297
|
+
};
|
|
298
|
+
if (now < leaf.notBefore) return {
|
|
299
|
+
ok: false,
|
|
300
|
+
reason: "not-yet-valid"
|
|
301
|
+
};
|
|
302
|
+
if (now > leaf.notAfter) return {
|
|
303
|
+
ok: false,
|
|
304
|
+
reason: "expired"
|
|
305
|
+
};
|
|
306
|
+
const eku = leaf.getExtension(require_x509_es.ExtendedKeyUsageExtension);
|
|
307
|
+
if (eku === null || !eku.usages.includes(CLIENT_AUTH_OID)) return {
|
|
308
|
+
ok: false,
|
|
309
|
+
reason: "missing-client-auth"
|
|
310
|
+
};
|
|
311
|
+
const sans = sanValues(leaf);
|
|
312
|
+
const credentialId = sans.find((v) => v.startsWith(require_dist.DEVICE_SAN_CREDENTIAL_PREFIX))?.slice(require_dist.DEVICE_SAN_CREDENTIAL_PREFIX.length);
|
|
313
|
+
if (credentialId === void 0 || credentialId === "") return {
|
|
314
|
+
ok: false,
|
|
315
|
+
reason: "missing-credential-san"
|
|
316
|
+
};
|
|
317
|
+
return {
|
|
318
|
+
ok: true,
|
|
319
|
+
credentialId,
|
|
320
|
+
userId: sans.find((v) => v.startsWith("camstack:user:"))?.slice(14) ?? null,
|
|
321
|
+
publicKeySpki: Buffer.from(leaf.publicKey.rawData),
|
|
322
|
+
serialNumber: leaf.serialNumber,
|
|
323
|
+
fingerprint: new node_crypto.X509Certificate(leafPem).fingerprint256,
|
|
324
|
+
notAfter: leaf.notAfter
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* ECDSA P-256 / SHA-256 over `message`. Accepts the raw `r||s` form WebCrypto
|
|
329
|
+
* and Android emit (64 bytes) and the DER form the Secure Enclave emits.
|
|
330
|
+
*/
|
|
331
|
+
function verifyDeviceSignature(publicKeySpki, message, signatureBase64Url) {
|
|
332
|
+
let signature;
|
|
333
|
+
try {
|
|
334
|
+
signature = Buffer.from(signatureBase64Url, "base64url");
|
|
335
|
+
} catch {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
if (signature.length === 0) return false;
|
|
339
|
+
try {
|
|
340
|
+
const key = (0, node_crypto.createPublicKey)({
|
|
341
|
+
key: Buffer.from(publicKeySpki),
|
|
342
|
+
format: "der",
|
|
343
|
+
type: "spki"
|
|
344
|
+
});
|
|
345
|
+
const dsaEncoding = signature.length === 64 ? "ieee-p1363" : "der";
|
|
346
|
+
return (0, node_crypto.verify)("sha256", Buffer.from(message, "utf8"), {
|
|
347
|
+
key,
|
|
348
|
+
dsaEncoding
|
|
349
|
+
}, signature);
|
|
350
|
+
} catch {
|
|
351
|
+
return false;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
//#endregion
|
|
355
|
+
Object.defineProperty(exports, "DEVICE_CA_FIELD", {
|
|
356
|
+
enumerable: true,
|
|
357
|
+
get: function() {
|
|
358
|
+
return DEVICE_CA_FIELD;
|
|
359
|
+
}
|
|
360
|
+
});
|
|
361
|
+
Object.defineProperty(exports, "DEVICE_CA_KEY_REF", {
|
|
362
|
+
enumerable: true,
|
|
363
|
+
get: function() {
|
|
364
|
+
return DEVICE_CA_KEY_REF;
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
Object.defineProperty(exports, "DEVICE_CA_SETTINGS_SECTION", {
|
|
368
|
+
enumerable: true,
|
|
369
|
+
get: function() {
|
|
370
|
+
return DEVICE_CA_SETTINGS_SECTION;
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
Object.defineProperty(exports, "JWT_SIGNING_KEY_REF", {
|
|
374
|
+
enumerable: true,
|
|
375
|
+
get: function() {
|
|
376
|
+
return JWT_SIGNING_KEY_REF;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
Object.defineProperty(exports, "JwtSigningKeyUnavailableError", {
|
|
380
|
+
enumerable: true,
|
|
381
|
+
get: function() {
|
|
382
|
+
return JwtSigningKeyUnavailableError;
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
Object.defineProperty(exports, "SYSTEM_SECRET_OWNER", {
|
|
386
|
+
enumerable: true,
|
|
387
|
+
get: function() {
|
|
388
|
+
return SYSTEM_SECRET_OWNER;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
Object.defineProperty(exports, "generateDeviceCa", {
|
|
392
|
+
enumerable: true,
|
|
393
|
+
get: function() {
|
|
394
|
+
return generateDeviceCa;
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
Object.defineProperty(exports, "getProcessJwtSigningKeyState", {
|
|
398
|
+
enumerable: true,
|
|
399
|
+
get: function() {
|
|
400
|
+
return getProcessJwtSigningKeyState;
|
|
401
|
+
}
|
|
402
|
+
});
|
|
403
|
+
Object.defineProperty(exports, "importDevicePublicKey", {
|
|
404
|
+
enumerable: true,
|
|
405
|
+
get: function() {
|
|
406
|
+
return importDevicePublicKey;
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
Object.defineProperty(exports, "issueDeviceLeaf", {
|
|
410
|
+
enumerable: true,
|
|
411
|
+
get: function() {
|
|
412
|
+
return issueDeviceLeaf;
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
Object.defineProperty(exports, "loadDeviceCa", {
|
|
416
|
+
enumerable: true,
|
|
417
|
+
get: function() {
|
|
418
|
+
return loadDeviceCa;
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
Object.defineProperty(exports, "loadJwtSigningKey", {
|
|
422
|
+
enumerable: true,
|
|
423
|
+
get: function() {
|
|
424
|
+
return loadJwtSigningKey;
|
|
425
|
+
}
|
|
426
|
+
});
|
|
427
|
+
Object.defineProperty(exports, "processJwtSigningKey", {
|
|
428
|
+
enumerable: true,
|
|
429
|
+
get: function() {
|
|
430
|
+
return processJwtSigningKey;
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
Object.defineProperty(exports, "rebuildDeviceCaCertificate", {
|
|
434
|
+
enumerable: true,
|
|
435
|
+
get: function() {
|
|
436
|
+
return rebuildDeviceCaCertificate;
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
Object.defineProperty(exports, "setProcessJwtSigningKey", {
|
|
440
|
+
enumerable: true,
|
|
441
|
+
get: function() {
|
|
442
|
+
return setProcessJwtSigningKey;
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
Object.defineProperty(exports, "staticJwtSigningKey", {
|
|
446
|
+
enumerable: true,
|
|
447
|
+
get: function() {
|
|
448
|
+
return staticJwtSigningKey;
|
|
449
|
+
}
|
|
450
|
+
});
|
|
451
|
+
Object.defineProperty(exports, "verifyDeviceLeaf", {
|
|
452
|
+
enumerable: true,
|
|
453
|
+
get: function() {
|
|
454
|
+
return verifyDeviceLeaf;
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
Object.defineProperty(exports, "verifyDeviceSignature", {
|
|
458
|
+
enumerable: true,
|
|
459
|
+
get: function() {
|
|
460
|
+
return verifyDeviceSignature;
|
|
461
|
+
}
|
|
462
|
+
});
|