@camstack/system 1.2.356 → 1.2.357
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/local-network/local-network.addon.d.ts +7 -0
- package/dist/builtins/local-network/local-network.addon.js +42 -23
- package/dist/builtins/local-network/local-network.addon.mjs +42 -23
- package/dist/index.js +20 -9
- package/dist/index.mjs +9 -10
- package/dist/kernel/config-schema.d.ts +0 -2
- package/dist/tls/boot-tls.d.ts +29 -0
- package/dist/tls/https-listener.d.ts +30 -0
- package/dist/tls/index.d.ts +4 -1
- package/dist/tls/tls-actions.d.ts +29 -0
- package/dist/tls/tls-status.d.ts +12 -1
- package/dist/{tls-ue_Xefmv.js → tls-CCMX7MjX.js} +319 -54
- package/dist/{tls-DTlVWwAI.mjs → tls-CJHogwTl.mjs} +246 -53
- package/package.json +1 -1
|
@@ -11249,7 +11249,7 @@ var Pkcs10CertificateRequest = class extends PemData {
|
|
|
11249
11249
|
_Pkcs10CertificateRequest_tbs = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_subjectName = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_subject = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_signatureAlgorithm = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_signature = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_publicKey = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_attributes = /* @__PURE__ */ new WeakMap(), _Pkcs10CertificateRequest_extensions = /* @__PURE__ */ new WeakMap();
|
|
11250
11250
|
Pkcs10CertificateRequest.NAME = "PKCS#10 Certificate Request";
|
|
11251
11251
|
var _X509Certificate_tbs, _X509Certificate_serialNumber, _X509Certificate_subjectName, _X509Certificate_subject, _X509Certificate_issuerName, _X509Certificate_issuer, _X509Certificate_notBefore, _X509Certificate_notAfter, _X509Certificate_signatureAlgorithm, _X509Certificate_signature, _X509Certificate_extensions, _X509Certificate_publicKey;
|
|
11252
|
-
var X509Certificate$
|
|
11252
|
+
var X509Certificate$4 = class extends PemData {
|
|
11253
11253
|
get publicKey() {
|
|
11254
11254
|
if (!__classPrivateFieldGet(this, _X509Certificate_publicKey, "f")) __classPrivateFieldSet(this, _X509Certificate_publicKey, new PublicKey(this.asn.tbsCertificate.subjectPublicKeyInfo), "f");
|
|
11255
11255
|
return __classPrivateFieldGet(this, _X509Certificate_publicKey, "f");
|
|
@@ -11449,7 +11449,7 @@ var X509Certificate$3 = class extends PemData {
|
|
|
11449
11449
|
}
|
|
11450
11450
|
};
|
|
11451
11451
|
_X509Certificate_tbs = /* @__PURE__ */ new WeakMap(), _X509Certificate_serialNumber = /* @__PURE__ */ new WeakMap(), _X509Certificate_subjectName = /* @__PURE__ */ new WeakMap(), _X509Certificate_subject = /* @__PURE__ */ new WeakMap(), _X509Certificate_issuerName = /* @__PURE__ */ new WeakMap(), _X509Certificate_issuer = /* @__PURE__ */ new WeakMap(), _X509Certificate_notBefore = /* @__PURE__ */ new WeakMap(), _X509Certificate_notAfter = /* @__PURE__ */ new WeakMap(), _X509Certificate_signatureAlgorithm = /* @__PURE__ */ new WeakMap(), _X509Certificate_signature = /* @__PURE__ */ new WeakMap(), _X509Certificate_extensions = /* @__PURE__ */ new WeakMap(), _X509Certificate_publicKey = /* @__PURE__ */ new WeakMap();
|
|
11452
|
-
X509Certificate$
|
|
11452
|
+
X509Certificate$4.NAME = "Certificate";
|
|
11453
11453
|
function generateCertificateSerialNumber(input, crypto = cryptoProvider.get()) {
|
|
11454
11454
|
const inputView = BufferSourceConverter.toUint8Array(Convert.FromHex(input || ""));
|
|
11455
11455
|
let serialNumber = inputView && inputView.length && inputView.some((o) => o > 0) ? new Uint8Array(inputView) : void 0;
|
|
@@ -11530,7 +11530,7 @@ var X509CertificateGenerator = class {
|
|
|
11530
11530
|
}
|
|
11531
11531
|
if (!asnSignature) throw Error("Cannot convert ASN.1 signature value to WebCrypto format");
|
|
11532
11532
|
asnX509.signatureValue = asnSignature;
|
|
11533
|
-
return new X509Certificate$
|
|
11533
|
+
return new X509Certificate$4(AsnConvert.serialize(asnX509));
|
|
11534
11534
|
}
|
|
11535
11535
|
};
|
|
11536
11536
|
var X509CrlReason;
|
|
@@ -11646,7 +11646,7 @@ async function loadCa(certPem, keyPem) {
|
|
|
11646
11646
|
return {
|
|
11647
11647
|
certPem,
|
|
11648
11648
|
keyPem,
|
|
11649
|
-
cert: new X509Certificate$
|
|
11649
|
+
cert: new X509Certificate$4(certPem),
|
|
11650
11650
|
privateKey: await node_crypto.webcrypto.subtle.importKey("pkcs8", PemConverter.decodeFirst(keyPem), SIGNING_ALGORITHM, true, ["sign"])
|
|
11651
11651
|
};
|
|
11652
11652
|
}
|
|
@@ -11862,45 +11862,6 @@ function loadTlsCert(certPath, keyPath) {
|
|
|
11862
11862
|
};
|
|
11863
11863
|
}
|
|
11864
11864
|
//#endregion
|
|
11865
|
-
//#region src/tls/uploaded-cert.ts
|
|
11866
|
-
/**
|
|
11867
|
-
* Operator-supplied material must parse, match its key, and carry
|
|
11868
|
-
* `extendedKeyUsage = serverAuth` — the same leaf defects D227 refused
|
|
11869
|
-
* to keep generating.
|
|
11870
|
-
*/
|
|
11871
|
-
function validateUploadedTls(certPem, keyPem) {
|
|
11872
|
-
let leaf;
|
|
11873
|
-
try {
|
|
11874
|
-
leaf = new node_crypto.X509Certificate(certPem);
|
|
11875
|
-
} catch {
|
|
11876
|
-
return {
|
|
11877
|
-
ok: false,
|
|
11878
|
-
error: "Certificate PEM could not be parsed."
|
|
11879
|
-
};
|
|
11880
|
-
}
|
|
11881
|
-
try {
|
|
11882
|
-
if (!leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem))) return {
|
|
11883
|
-
ok: false,
|
|
11884
|
-
error: "Private key does not match the certificate."
|
|
11885
|
-
};
|
|
11886
|
-
} catch {
|
|
11887
|
-
return {
|
|
11888
|
-
ok: false,
|
|
11889
|
-
error: "Private key PEM could not be parsed."
|
|
11890
|
-
};
|
|
11891
|
-
}
|
|
11892
|
-
const eku = leaf.keyUsage;
|
|
11893
|
-
if (eku === void 0 || !eku.includes("1.3.6.1.5.5.7.3.1")) return {
|
|
11894
|
-
ok: false,
|
|
11895
|
-
error: "Certificate is missing extendedKeyUsage = serverAuth."
|
|
11896
|
-
};
|
|
11897
|
-
return {
|
|
11898
|
-
ok: true,
|
|
11899
|
-
fingerprintSha256: leaf.fingerprint256,
|
|
11900
|
-
validTo: new Date(leaf.validTo).toISOString()
|
|
11901
|
-
};
|
|
11902
|
-
}
|
|
11903
|
-
//#endregion
|
|
11904
11865
|
//#region src/tls/tls-status.ts
|
|
11905
11866
|
function tlsDir(dataDir) {
|
|
11906
11867
|
return (0, node_path.join)(dataDir, "tls");
|
|
@@ -11933,10 +11894,51 @@ function writeExtraSans(dataDir, sans) {
|
|
|
11933
11894
|
(0, node_fs.mkdirSync)(tlsDir(dataDir), { recursive: true });
|
|
11934
11895
|
(0, node_fs.writeFileSync)((0, node_path.join)(tlsDir(dataDir), "extra-sans.json"), `${JSON.stringify(sans)}\n`, "utf-8");
|
|
11935
11896
|
}
|
|
11936
|
-
|
|
11897
|
+
/** Where an upload's own CA is kept — never over the local CA's `camstack-ca.crt`. */
|
|
11898
|
+
var UPLOADED_CA_FILE = "uploaded-ca.crt";
|
|
11899
|
+
/** Every certificate in a PEM bundle, in order. */
|
|
11900
|
+
function splitPemCertificates(pem) {
|
|
11901
|
+
const blocks = pem.match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g);
|
|
11902
|
+
return blocks === null ? [] : blocks.map((block) => `${block}\n`);
|
|
11903
|
+
}
|
|
11904
|
+
/**
|
|
11905
|
+
* The certificate that signed `leaf`, from the upload itself: the CA the
|
|
11906
|
+
* operator supplied, else the rest of the uploaded chain. `null` when the
|
|
11907
|
+
* upload did not include it — and then nothing may stand in for it: the
|
|
11908
|
+
* local CA did not sign an uploaded leaf, so handing it out as "the CA" would
|
|
11909
|
+
* tell a client to trust a root that verifies nothing it is served.
|
|
11910
|
+
*/
|
|
11911
|
+
function uploadedIssuer(dir, leaf, chainPem) {
|
|
11912
|
+
const caPath = (0, node_path.join)(dir, UPLOADED_CA_FILE);
|
|
11913
|
+
const candidates = [...(0, node_fs.existsSync)(caPath) ? splitPemCertificates((0, node_fs.readFileSync)(caPath, "utf-8")) : [], ...splitPemCertificates(chainPem).slice(1)];
|
|
11914
|
+
for (const pem of candidates) try {
|
|
11915
|
+
const cert = new node_crypto.X509Certificate(pem);
|
|
11916
|
+
if (leaf.checkIssued(cert) && leaf.verify(cert.publicKey)) return {
|
|
11917
|
+
pem,
|
|
11918
|
+
cert
|
|
11919
|
+
};
|
|
11920
|
+
} catch {}
|
|
11921
|
+
return null;
|
|
11922
|
+
}
|
|
11923
|
+
function generatedIssuer(dir) {
|
|
11924
|
+
const caPath = (0, node_path.join)(dir, "camstack-ca.crt");
|
|
11925
|
+
if (!(0, node_fs.existsSync)(caPath)) return null;
|
|
11926
|
+
const pem = (0, node_fs.readFileSync)(caPath, "utf-8");
|
|
11927
|
+
return {
|
|
11928
|
+
pem,
|
|
11929
|
+
cert: new node_crypto.X509Certificate(pem)
|
|
11930
|
+
};
|
|
11931
|
+
}
|
|
11932
|
+
/**
|
|
11933
|
+
* What the node's certificate is, and whether the listener serves it.
|
|
11934
|
+
* `servedLeafFingerprint` is the leaf the HTTPS listener presents right now
|
|
11935
|
+
* (`servedHttpsLeafFingerprint()`), or `null` when unknown; a restart is
|
|
11936
|
+
* required exactly when the listener serves a different leaf than the one
|
|
11937
|
+
* on disk — a measured fact, not a flag a mutation remembered to set.
|
|
11938
|
+
*/
|
|
11939
|
+
function readTlsAccessStatus(dataDir, servedLeafFingerprint) {
|
|
11937
11940
|
const dir = tlsDir(dataDir);
|
|
11938
11941
|
const certPath = (0, node_path.join)(dir, "camstack.crt");
|
|
11939
|
-
const caPath = (0, node_path.join)(dir, "camstack-ca.crt");
|
|
11940
11942
|
const mode = readTlsMode(dataDir);
|
|
11941
11943
|
if (!(0, node_fs.existsSync)(certPath)) return {
|
|
11942
11944
|
mode: "disabled",
|
|
@@ -11944,24 +11946,24 @@ function readTlsAccessStatus(dataDir, restartRequired = false) {
|
|
|
11944
11946
|
caFingerprintSha256: null,
|
|
11945
11947
|
validTo: null,
|
|
11946
11948
|
sans: [],
|
|
11947
|
-
caCertPem: (
|
|
11949
|
+
caCertPem: (mode === "uploaded" ? null : generatedIssuer(dir))?.pem ?? null,
|
|
11948
11950
|
reissueError: null,
|
|
11949
|
-
restartRequired
|
|
11951
|
+
restartRequired: false
|
|
11950
11952
|
};
|
|
11951
11953
|
try {
|
|
11952
|
-
const
|
|
11953
|
-
const
|
|
11954
|
-
const ca =
|
|
11954
|
+
const chainPem = (0, node_fs.readFileSync)(certPath, "utf-8");
|
|
11955
|
+
const leaf = new node_crypto.X509Certificate(chainPem);
|
|
11956
|
+
const ca = mode === "uploaded" ? uploadedIssuer(dir, leaf, chainPem) : generatedIssuer(dir);
|
|
11955
11957
|
const san = leaf.subjectAltName ?? "";
|
|
11956
11958
|
return {
|
|
11957
11959
|
mode,
|
|
11958
11960
|
leafFingerprintSha256: leaf.fingerprint256,
|
|
11959
|
-
caFingerprintSha256: ca?.fingerprint256 ?? null,
|
|
11961
|
+
caFingerprintSha256: ca?.cert.fingerprint256 ?? null,
|
|
11960
11962
|
validTo: new Date(leaf.validTo).toISOString(),
|
|
11961
11963
|
sans: san === "" ? [] : san.split(", "),
|
|
11962
|
-
caCertPem:
|
|
11964
|
+
caCertPem: ca?.pem ?? null,
|
|
11963
11965
|
reissueError: null,
|
|
11964
|
-
restartRequired
|
|
11966
|
+
restartRequired: servedLeafFingerprint !== null && servedLeafFingerprint !== leaf.fingerprint256
|
|
11965
11967
|
};
|
|
11966
11968
|
} catch {
|
|
11967
11969
|
return {
|
|
@@ -11972,11 +11974,202 @@ function readTlsAccessStatus(dataDir, restartRequired = false) {
|
|
|
11972
11974
|
sans: [],
|
|
11973
11975
|
caCertPem: null,
|
|
11974
11976
|
reissueError: "Certificate on disk could not be parsed.",
|
|
11975
|
-
restartRequired
|
|
11977
|
+
restartRequired: false
|
|
11976
11978
|
};
|
|
11977
11979
|
}
|
|
11978
11980
|
}
|
|
11979
11981
|
//#endregion
|
|
11982
|
+
//#region src/tls/boot-tls.ts
|
|
11983
|
+
/**
|
|
11984
|
+
* Decide what the listener serves at boot. The admin UI (Network → Local
|
|
11985
|
+
* access) is the only way to set a certificate (D726): it either leaves the
|
|
11986
|
+
* hub on its generated local-CA leaf (D227) or uploads one, recorded by the
|
|
11987
|
+
* `tls/mode` marker. An uploaded certificate is served verbatim — running it
|
|
11988
|
+
* through `ensureTlsCert` would replace it on the first restart, because a
|
|
11989
|
+
* leaf the local root did not issue is one of that rule's reissue triggers.
|
|
11990
|
+
*/
|
|
11991
|
+
async function prepareBootTls(dataDir, options) {
|
|
11992
|
+
const certPath = (0, node_path.join)(dataDir, "tls", "camstack.crt");
|
|
11993
|
+
const keyPath = (0, node_path.join)(dataDir, "tls", "camstack.key");
|
|
11994
|
+
const marked = readTlsMode(dataDir);
|
|
11995
|
+
if (marked === "uploaded" && (0, node_fs.existsSync)(certPath) && (0, node_fs.existsSync)(keyPath)) return {
|
|
11996
|
+
mode: "uploaded",
|
|
11997
|
+
pair: loadTlsCert(certPath, keyPath),
|
|
11998
|
+
ensured: void 0,
|
|
11999
|
+
uploadedMissing: false
|
|
12000
|
+
};
|
|
12001
|
+
const uploadedMissing = marked === "uploaded";
|
|
12002
|
+
if (uploadedMissing) writeTlsMode(dataDir, "generated");
|
|
12003
|
+
const ensured = await ensureTlsCert(dataDir, options);
|
|
12004
|
+
return {
|
|
12005
|
+
mode: "generated",
|
|
12006
|
+
pair: loadTlsCert(ensured.certPath, ensured.keyPath),
|
|
12007
|
+
ensured,
|
|
12008
|
+
uploadedMissing
|
|
12009
|
+
};
|
|
12010
|
+
}
|
|
12011
|
+
//#endregion
|
|
12012
|
+
//#region src/tls/https-listener.ts
|
|
12013
|
+
var SLOT_KEY = Symbol.for("camstack.tls.https-listener");
|
|
12014
|
+
var EMPTY_SLOT = {
|
|
12015
|
+
reload: null,
|
|
12016
|
+
servedLeafFingerprint: null
|
|
12017
|
+
};
|
|
12018
|
+
function isSlot(value) {
|
|
12019
|
+
if (typeof value !== "object" || value === null) return false;
|
|
12020
|
+
if (!("reload" in value) || !("servedLeafFingerprint" in value)) return false;
|
|
12021
|
+
const reload = value.reload;
|
|
12022
|
+
const served = value.servedLeafFingerprint;
|
|
12023
|
+
return (reload === null || typeof reload === "function") && (served === null || typeof served === "string");
|
|
12024
|
+
}
|
|
12025
|
+
function readSlot() {
|
|
12026
|
+
const current = Reflect.get(globalThis, SLOT_KEY);
|
|
12027
|
+
return isSlot(current) ? current : EMPTY_SLOT;
|
|
12028
|
+
}
|
|
12029
|
+
function writeSlot(next) {
|
|
12030
|
+
Reflect.set(globalThis, SLOT_KEY, next);
|
|
12031
|
+
}
|
|
12032
|
+
/** SHA-256 fingerprint of the first certificate (the leaf) in a PEM chain. */
|
|
12033
|
+
function leafFingerprintOf(chain) {
|
|
12034
|
+
return new node_crypto.X509Certificate(chain).fingerprint256;
|
|
12035
|
+
}
|
|
12036
|
+
/**
|
|
12037
|
+
* Called once by the server after its HTTPS listener is up, with the pair it
|
|
12038
|
+
* was started on. From here on a certificate action swaps the served
|
|
12039
|
+
* certificate in place (`setSecureContext`) — new handshakes get the new
|
|
12040
|
+
* leaf, open connections keep theirs, nothing restarts.
|
|
12041
|
+
*/
|
|
12042
|
+
function registerHttpsListener(server, pair) {
|
|
12043
|
+
writeSlot({
|
|
12044
|
+
reload: (next) => server.setSecureContext({
|
|
12045
|
+
cert: next.cert,
|
|
12046
|
+
key: next.key
|
|
12047
|
+
}),
|
|
12048
|
+
servedLeafFingerprint: leafFingerprintOf(pair.cert)
|
|
12049
|
+
});
|
|
12050
|
+
}
|
|
12051
|
+
/** Forget the listener — on shutdown, and between specs. */
|
|
12052
|
+
function clearHttpsListener() {
|
|
12053
|
+
writeSlot(EMPTY_SLOT);
|
|
12054
|
+
}
|
|
12055
|
+
/**
|
|
12056
|
+
* The leaf the HTTPS listener serves now, or `null` when this process has no
|
|
12057
|
+
* registered listener (TLS off, or a process that does not own one) — in
|
|
12058
|
+
* which case nobody can say, and `null` is the honest answer.
|
|
12059
|
+
*/
|
|
12060
|
+
function servedHttpsLeafFingerprint() {
|
|
12061
|
+
return readSlot().servedLeafFingerprint;
|
|
12062
|
+
}
|
|
12063
|
+
/** Serve `pair` from now on. Never throws: the outcome says what happened. */
|
|
12064
|
+
function reloadHttpsListener(pair) {
|
|
12065
|
+
const slot = readSlot();
|
|
12066
|
+
if (slot.reload === null) return { kind: "no-listener" };
|
|
12067
|
+
try {
|
|
12068
|
+
const servedLeafFingerprint = leafFingerprintOf(pair.cert);
|
|
12069
|
+
slot.reload(pair);
|
|
12070
|
+
writeSlot({
|
|
12071
|
+
reload: slot.reload,
|
|
12072
|
+
servedLeafFingerprint
|
|
12073
|
+
});
|
|
12074
|
+
return {
|
|
12075
|
+
kind: "reloaded",
|
|
12076
|
+
servedLeafFingerprint
|
|
12077
|
+
};
|
|
12078
|
+
} catch (err) {
|
|
12079
|
+
return {
|
|
12080
|
+
kind: "failed",
|
|
12081
|
+
error: err instanceof Error ? err.message : String(err)
|
|
12082
|
+
};
|
|
12083
|
+
}
|
|
12084
|
+
}
|
|
12085
|
+
//#endregion
|
|
12086
|
+
//#region src/tls/uploaded-cert.ts
|
|
12087
|
+
/**
|
|
12088
|
+
* Operator-supplied material must parse, match its key, and carry
|
|
12089
|
+
* `extendedKeyUsage = serverAuth` — the same leaf defects D227 refused
|
|
12090
|
+
* to keep generating.
|
|
12091
|
+
*/
|
|
12092
|
+
function validateUploadedTls(certPem, keyPem) {
|
|
12093
|
+
let leaf;
|
|
12094
|
+
try {
|
|
12095
|
+
leaf = new node_crypto.X509Certificate(certPem);
|
|
12096
|
+
} catch {
|
|
12097
|
+
return {
|
|
12098
|
+
ok: false,
|
|
12099
|
+
error: "Certificate PEM could not be parsed."
|
|
12100
|
+
};
|
|
12101
|
+
}
|
|
12102
|
+
try {
|
|
12103
|
+
if (!leaf.checkPrivateKey((0, node_crypto.createPrivateKey)(keyPem))) return {
|
|
12104
|
+
ok: false,
|
|
12105
|
+
error: "Private key does not match the certificate."
|
|
12106
|
+
};
|
|
12107
|
+
} catch {
|
|
12108
|
+
return {
|
|
12109
|
+
ok: false,
|
|
12110
|
+
error: "Private key PEM could not be parsed."
|
|
12111
|
+
};
|
|
12112
|
+
}
|
|
12113
|
+
const eku = leaf.keyUsage;
|
|
12114
|
+
if (eku === void 0 || !eku.includes("1.3.6.1.5.5.7.3.1")) return {
|
|
12115
|
+
ok: false,
|
|
12116
|
+
error: "Certificate is missing extendedKeyUsage = serverAuth."
|
|
12117
|
+
};
|
|
12118
|
+
return {
|
|
12119
|
+
ok: true,
|
|
12120
|
+
fingerprintSha256: leaf.fingerprint256,
|
|
12121
|
+
validTo: new Date(leaf.validTo).toISOString()
|
|
12122
|
+
};
|
|
12123
|
+
}
|
|
12124
|
+
//#endregion
|
|
12125
|
+
//#region src/tls/tls-actions.ts
|
|
12126
|
+
function withNewline(pem) {
|
|
12127
|
+
return pem.endsWith("\n") ? pem : `${pem}\n`;
|
|
12128
|
+
}
|
|
12129
|
+
/**
|
|
12130
|
+
* Store an operator's certificate. The leaf (or chain) and key replace the
|
|
12131
|
+
* served pair; a CA, when given, goes to its own file. The local CA
|
|
12132
|
+
* (`camstack-ca.crt` + key) is never touched — it did not sign the upload,
|
|
12133
|
+
* and it is what "Revert to generated" and every device that trusts it
|
|
12134
|
+
* still need.
|
|
12135
|
+
*/
|
|
12136
|
+
async function storeUploadedCertificate(dataDir, input) {
|
|
12137
|
+
const valid = validateUploadedTls(input.certPem, input.keyPem);
|
|
12138
|
+
if (!valid.ok) throw new Error(valid.error);
|
|
12139
|
+
const dir = (0, node_path.join)(dataDir, "tls");
|
|
12140
|
+
await (0, node_fs_promises.mkdir)(dir, { recursive: true });
|
|
12141
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(dir, "camstack.crt"), withNewline(input.certPem));
|
|
12142
|
+
await (0, node_fs_promises.writeFile)((0, node_path.join)(dir, "camstack.key"), withNewline(input.keyPem), { mode: 384 });
|
|
12143
|
+
const caPath = (0, node_path.join)(dir, UPLOADED_CA_FILE);
|
|
12144
|
+
if (input.caPem !== void 0 && input.caPem.trim() !== "") await (0, node_fs_promises.writeFile)(caPath, withNewline(input.caPem));
|
|
12145
|
+
else (0, node_fs.rmSync)(caPath, { force: true });
|
|
12146
|
+
writeTlsMode(dataDir, "uploaded");
|
|
12147
|
+
}
|
|
12148
|
+
/** Issue a new generated leaf under the local CA. Refused while an upload is served. */
|
|
12149
|
+
async function regenerateCertificate(dataDir, options) {
|
|
12150
|
+
if (readTlsMode(dataDir) === "uploaded") throw new Error("Cannot regenerate an uploaded certificate — revert to generated first.");
|
|
12151
|
+
await reissueTlsLeaf(dataDir, options);
|
|
12152
|
+
}
|
|
12153
|
+
/** Drop the upload and serve the generated local-CA leaf again (D227). */
|
|
12154
|
+
async function revertToGeneratedCertificate(dataDir, options) {
|
|
12155
|
+
writeTlsMode(dataDir, "generated");
|
|
12156
|
+
(0, node_fs.rmSync)((0, node_path.join)(dataDir, "tls", UPLOADED_CA_FILE), { force: true });
|
|
12157
|
+
await ensureTlsCert(dataDir, options);
|
|
12158
|
+
}
|
|
12159
|
+
/**
|
|
12160
|
+
* Put the pair on disk on the HTTPS listener. Called after every action, so
|
|
12161
|
+
* "the certificate changed" and "clients see it" are the same moment.
|
|
12162
|
+
*/
|
|
12163
|
+
function applyCertificateToListener(dataDir) {
|
|
12164
|
+
const certPath = (0, node_path.join)(dataDir, "tls", "camstack.crt");
|
|
12165
|
+
const keyPath = (0, node_path.join)(dataDir, "tls", "camstack.key");
|
|
12166
|
+
if (!(0, node_fs.existsSync)(certPath) || !(0, node_fs.existsSync)(keyPath)) return {
|
|
12167
|
+
kind: "failed",
|
|
12168
|
+
error: `No certificate pair under ${(0, node_path.join)(dataDir, "tls")}`
|
|
12169
|
+
};
|
|
12170
|
+
return reloadHttpsListener(loadTlsCert(certPath, keyPath));
|
|
12171
|
+
}
|
|
12172
|
+
//#endregion
|
|
11980
12173
|
Object.defineProperty(exports, "CA_COMMON_NAME", {
|
|
11981
12174
|
enumerable: true,
|
|
11982
12175
|
get: function() {
|
|
@@ -12013,12 +12206,24 @@ Object.defineProperty(exports, "SERVER_AUTH_OID", {
|
|
|
12013
12206
|
return SERVER_AUTH_OID;
|
|
12014
12207
|
}
|
|
12015
12208
|
});
|
|
12209
|
+
Object.defineProperty(exports, "UPLOADED_CA_FILE", {
|
|
12210
|
+
enumerable: true,
|
|
12211
|
+
get: function() {
|
|
12212
|
+
return UPLOADED_CA_FILE;
|
|
12213
|
+
}
|
|
12214
|
+
});
|
|
12016
12215
|
Object.defineProperty(exports, "allFamiliesListenHost", {
|
|
12017
12216
|
enumerable: true,
|
|
12018
12217
|
get: function() {
|
|
12019
12218
|
return allFamiliesListenHost;
|
|
12020
12219
|
}
|
|
12021
12220
|
});
|
|
12221
|
+
Object.defineProperty(exports, "applyCertificateToListener", {
|
|
12222
|
+
enumerable: true,
|
|
12223
|
+
get: function() {
|
|
12224
|
+
return applyCertificateToListener;
|
|
12225
|
+
}
|
|
12226
|
+
});
|
|
12022
12227
|
Object.defineProperty(exports, "applyLanHttp", {
|
|
12023
12228
|
enumerable: true,
|
|
12024
12229
|
get: function() {
|
|
@@ -12031,6 +12236,12 @@ Object.defineProperty(exports, "bindPendingLanHttp", {
|
|
|
12031
12236
|
return bindPendingLanHttp;
|
|
12032
12237
|
}
|
|
12033
12238
|
});
|
|
12239
|
+
Object.defineProperty(exports, "clearHttpsListener", {
|
|
12240
|
+
enumerable: true,
|
|
12241
|
+
get: function() {
|
|
12242
|
+
return clearHttpsListener;
|
|
12243
|
+
}
|
|
12244
|
+
});
|
|
12034
12245
|
Object.defineProperty(exports, "closeLanHttp", {
|
|
12035
12246
|
enumerable: true,
|
|
12036
12247
|
get: function() {
|
|
@@ -12055,12 +12266,24 @@ Object.defineProperty(exports, "evaluateExistingCert", {
|
|
|
12055
12266
|
return evaluateExistingCert;
|
|
12056
12267
|
}
|
|
12057
12268
|
});
|
|
12269
|
+
Object.defineProperty(exports, "leafFingerprintOf", {
|
|
12270
|
+
enumerable: true,
|
|
12271
|
+
get: function() {
|
|
12272
|
+
return leafFingerprintOf;
|
|
12273
|
+
}
|
|
12274
|
+
});
|
|
12058
12275
|
Object.defineProperty(exports, "loadTlsCert", {
|
|
12059
12276
|
enumerable: true,
|
|
12060
12277
|
get: function() {
|
|
12061
12278
|
return loadTlsCert;
|
|
12062
12279
|
}
|
|
12063
12280
|
});
|
|
12281
|
+
Object.defineProperty(exports, "prepareBootTls", {
|
|
12282
|
+
enumerable: true,
|
|
12283
|
+
get: function() {
|
|
12284
|
+
return prepareBootTls;
|
|
12285
|
+
}
|
|
12286
|
+
});
|
|
12064
12287
|
Object.defineProperty(exports, "readExtraSans", {
|
|
12065
12288
|
enumerable: true,
|
|
12066
12289
|
get: function() {
|
|
@@ -12085,6 +12308,18 @@ Object.defineProperty(exports, "readTlsMode", {
|
|
|
12085
12308
|
return readTlsMode;
|
|
12086
12309
|
}
|
|
12087
12310
|
});
|
|
12311
|
+
Object.defineProperty(exports, "regenerateCertificate", {
|
|
12312
|
+
enumerable: true,
|
|
12313
|
+
get: function() {
|
|
12314
|
+
return regenerateCertificate;
|
|
12315
|
+
}
|
|
12316
|
+
});
|
|
12317
|
+
Object.defineProperty(exports, "registerHttpsListener", {
|
|
12318
|
+
enumerable: true,
|
|
12319
|
+
get: function() {
|
|
12320
|
+
return registerHttpsListener;
|
|
12321
|
+
}
|
|
12322
|
+
});
|
|
12088
12323
|
Object.defineProperty(exports, "registerLanHttpHandler", {
|
|
12089
12324
|
enumerable: true,
|
|
12090
12325
|
get: function() {
|
|
@@ -12097,6 +12332,36 @@ Object.defineProperty(exports, "reissueTlsLeaf", {
|
|
|
12097
12332
|
return reissueTlsLeaf;
|
|
12098
12333
|
}
|
|
12099
12334
|
});
|
|
12335
|
+
Object.defineProperty(exports, "reloadHttpsListener", {
|
|
12336
|
+
enumerable: true,
|
|
12337
|
+
get: function() {
|
|
12338
|
+
return reloadHttpsListener;
|
|
12339
|
+
}
|
|
12340
|
+
});
|
|
12341
|
+
Object.defineProperty(exports, "revertToGeneratedCertificate", {
|
|
12342
|
+
enumerable: true,
|
|
12343
|
+
get: function() {
|
|
12344
|
+
return revertToGeneratedCertificate;
|
|
12345
|
+
}
|
|
12346
|
+
});
|
|
12347
|
+
Object.defineProperty(exports, "servedHttpsLeafFingerprint", {
|
|
12348
|
+
enumerable: true,
|
|
12349
|
+
get: function() {
|
|
12350
|
+
return servedHttpsLeafFingerprint;
|
|
12351
|
+
}
|
|
12352
|
+
});
|
|
12353
|
+
Object.defineProperty(exports, "splitPemCertificates", {
|
|
12354
|
+
enumerable: true,
|
|
12355
|
+
get: function() {
|
|
12356
|
+
return splitPemCertificates;
|
|
12357
|
+
}
|
|
12358
|
+
});
|
|
12359
|
+
Object.defineProperty(exports, "storeUploadedCertificate", {
|
|
12360
|
+
enumerable: true,
|
|
12361
|
+
get: function() {
|
|
12362
|
+
return storeUploadedCertificate;
|
|
12363
|
+
}
|
|
12364
|
+
});
|
|
12100
12365
|
Object.defineProperty(exports, "validateUploadedTls", {
|
|
12101
12366
|
enumerable: true,
|
|
12102
12367
|
get: function() {
|