@camstack/system 1.2.437 → 1.2.439
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addon-runner.js +64 -12
- package/dist/addon-runner.mjs +65 -13
- package/dist/{agent-https-BZIwS4xF.js → agent-https-DlpTMDqA.js} +252 -22
- package/dist/{agent-https-BPfHrI4c.mjs → agent-https-U0d4uvn2.mjs} +211 -23
- 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 +7 -1
- package/dist/builtins/alerts/alerts.addon.mjs +7 -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 +9 -1
- package/dist/builtins/camera-grid/index.mjs +9 -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 +12 -5
- package/dist/builtins/console-logging/index.mjs +12 -5
- 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.d.ts +5 -0
- package/dist/builtins/device-manager/device-manager.addon.js +717 -28
- package/dist/builtins/device-manager/device-manager.addon.mjs +717 -28
- package/dist/builtins/device-manager/device-meta-types.d.ts +4 -0
- package/dist/builtins/device-manager/device-provider-context.d.ts +9 -0
- package/dist/builtins/device-manager/device-removal-hooks.d.ts +103 -0
- package/dist/builtins/device-manager/device-row-store.d.ts +1 -0
- package/dist/builtins/device-manager/device-tombstone-store.d.ts +68 -0
- package/dist/builtins/device-manager/removal-cleanup.d.ts +50 -0
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +37 -4
- package/dist/builtins/keychain/index.mjs +37 -4
- package/dist/builtins/keychain/keychain-service.d.ts +14 -0
- package/dist/builtins/keychain/keychain-store.d.ts +1 -1
- 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 +12 -12
- package/dist/builtins/local-auth/local-auth.addon.mjs +12 -12
- package/dist/builtins/local-network/local-network.addon.js +16 -2
- package/dist/builtins/local-network/local-network.addon.mjs +16 -2
- package/dist/builtins/loki-logging/index.js +28 -5
- package/dist/builtins/loki-logging/index.mjs +28 -5
- package/dist/builtins/native-metrics/native-metrics.addon.js +11 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +11 -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 +11 -1
- package/dist/builtins/snapshot/index.mjs +11 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +4 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +4 -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.js +22 -4
- package/dist/builtins/system-config/system-config.addon.mjs +22 -4
- package/dist/builtins/winston-logging/index.js +14 -5
- package/dist/builtins/winston-logging/index.mjs +14 -5
- package/dist/{composition-sources-BIT8IUKm.js → composition-sources-B4jC2FC7.js} +1 -1
- package/dist/{composition-sources-tpYR0f1x.mjs → composition-sources-BGOSCGWa.mjs} +1 -1
- package/dist/{constants-Bc6trhoW.mjs → constants-B92BjObl.mjs} +1 -1
- package/dist/{constants-CwRY32Nx.js → constants-BRsjQwi-.js} +1 -1
- package/dist/{device-ca-BhdBByGD.mjs → device-ca-46BUsWD1.mjs} +2 -2
- package/dist/{device-ca-DImD8IzR.js → device-ca-DHG9OW2m.js} +2 -2
- package/dist/{dist-CEAyXW3Q.js → dist-BOWdLjoK.js} +341 -13
- package/dist/{dist-m5JkT8UN.mjs → dist-yI6kF6r6.mjs} +306 -14
- package/dist/file-host-worker.js +1 -1
- package/dist/file-host-worker.mjs +1 -1
- package/dist/{hub-mdns-ciao-CBLvq2oj.js → hub-mdns-ciao-D7S5AJRU.js} +377 -69
- package/dist/{hub-mdns-ciao-DMlQTdPU.mjs → hub-mdns-ciao-DGwVc2uh.mjs} +344 -72
- package/dist/i18n/catalog-registry.d.ts +35 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +698 -22
- package/dist/index.mjs +681 -24
- package/dist/kernel/gc-census.d.ts +18 -1
- package/dist/kernel/settings-view-types.d.ts +2 -0
- package/dist/kernel/transport/local-transport.d.ts +3 -0
- package/dist/kernel/transport/peer-answered-error.d.ts +5 -1
- package/dist/{lib-NNxHSOIE.js → lib-8oZrELLm.js} +1 -1
- package/dist/{lib-BeGzVQcd.mjs → lib-DK38ompL.mjs} +1 -1
- package/dist/{restore-archive-DNxAStrJ.mjs → restore-archive-CpdUO-uS.mjs} +1 -1
- package/dist/{restore-archive-C75srVbG.js → restore-archive-DiGiI6Jp.js} +1 -1
- package/dist/{retired-settings-keys-DNfV28R_.js → retired-settings-keys-CyQ7uvta.js} +1 -1
- package/dist/{retired-settings-keys-C5qP9QIf.mjs → retired-settings-keys-UsVtLOT0.mjs} +1 -1
- package/dist/tls/agent-https.d.ts +2 -2
- package/dist/tls/boot-tls.d.ts +6 -0
- package/dist/tls/cert-evaluation.d.ts +1 -1
- package/dist/tls/cert-issue.d.ts +5 -1
- package/dist/tls/cert-manager.d.ts +18 -0
- package/dist/tls/cert-name-constraints.d.ts +53 -0
- package/dist/tls/index.d.ts +5 -4
- package/dist/tls/tls-actions.d.ts +27 -7
- package/dist/tls/tls-status.d.ts +22 -0
- package/dist/tls/uploaded-cert.d.ts +36 -4
- package/dist/{wal-maintenance-Ch79gy9S.js → wal-maintenance-DEL_jeG0.js} +0 -0
- package/dist/{wal-maintenance-DvnVO5IK.mjs → wal-maintenance-xsvdT5Go.mjs} +0 -0
- package/dist/{x509.es-r7Ht1thA.js → x509.es-C4cOo48M.js} +36 -0
- package/dist/{x509.es-CDvj67p1.mjs → x509.es-DK__ETIe.mjs} +1 -1
- package/package.json +3 -1
|
@@ -59,6 +59,14 @@ export interface GcCensusWindow {
|
|
|
59
59
|
readonly pauseMs: number;
|
|
60
60
|
/** How long the window was, so a rate can be computed from the line. */
|
|
61
61
|
readonly windowMs: number;
|
|
62
|
+
/**
|
|
63
|
+
* Cycles in the window by V8 trigger flag NAME (`ALL_EXTERNAL_MEMORY`,
|
|
64
|
+
* `FORCED`, ...). A cycle can carry several flags and counts under each. This
|
|
65
|
+
* is what separates "driven by external-memory pressure" from "the heap is
|
|
66
|
+
* filling" ON THE LINE, instead of by inference from the rate (D867).
|
|
67
|
+
* Absent = the runtime reported no flag names.
|
|
68
|
+
*/
|
|
69
|
+
readonly flags?: Readonly<Record<string, number>>;
|
|
62
70
|
}
|
|
63
71
|
/**
|
|
64
72
|
* A census that accumulates until it is read, then starts a new window.
|
|
@@ -76,6 +84,13 @@ export interface GcCensus {
|
|
|
76
84
|
export interface GcObservation {
|
|
77
85
|
readonly kind: number;
|
|
78
86
|
readonly durationMs: number;
|
|
87
|
+
/** `detail.flags` bitmask; absent when the entry carried none. */
|
|
88
|
+
readonly flags?: number;
|
|
89
|
+
}
|
|
90
|
+
/** One V8 GC flag: its Node constant name (without the prefix) and its bit. */
|
|
91
|
+
export interface GcFlagBit {
|
|
92
|
+
readonly name: string;
|
|
93
|
+
readonly bit: number;
|
|
79
94
|
}
|
|
80
95
|
/**
|
|
81
96
|
* How the census is fed. Injectable so a spec can pose a sequence of
|
|
@@ -115,11 +130,13 @@ export declare const GC_CENSUS_MIN_WINDOW_MS = 1e3;
|
|
|
115
130
|
* observed and a process that is not collecting look identical on the line, and
|
|
116
131
|
* they are the two answers furthest apart.
|
|
117
132
|
*/
|
|
118
|
-
export declare function createGcCensus(install: GcObserverInstall, kinds: GcKinds, startedAt: number): GcCensus | undefined;
|
|
133
|
+
export declare function createGcCensus(install: GcObserverInstall, kinds: GcKinds, startedAt: number, flagBits?: readonly GcFlagBit[]): GcCensus | undefined;
|
|
119
134
|
/** The real Node observer and the real kind constants, wrapped so they can be replaced in a spec. */
|
|
120
135
|
export interface NodeGcObserver {
|
|
121
136
|
readonly install: GcObserverInstall;
|
|
122
137
|
readonly kinds: GcKinds;
|
|
138
|
+
/** Names of the flag bits `detail.flags` can carry. Empty = unreadable. */
|
|
139
|
+
readonly flagBits?: readonly GcFlagBit[];
|
|
123
140
|
}
|
|
124
141
|
/**
|
|
125
142
|
* The observer this process actually gets.
|
|
@@ -16,6 +16,8 @@ export interface AddonSettingsView {
|
|
|
16
16
|
* here for the same reason: only the door-backed view can answer it in one
|
|
17
17
|
* range scan, and a caller must fall back rather than refuse. */
|
|
18
18
|
readDeviceStoreBatch?(deviceIds: readonly number[]): Promise<ReadonlyMap<number, Record<string, unknown>>>;
|
|
19
|
+
/** See `IAddonContext['settings'].listDeviceStoreIds` — door-backed views only. */
|
|
20
|
+
listDeviceStoreIds?(): Promise<readonly number[]>;
|
|
19
21
|
writeDeviceStore(deviceId: number, patch: Record<string, unknown>): Promise<void>;
|
|
20
22
|
clearDeviceStore(deviceId: number): Promise<void>;
|
|
21
23
|
getSection(section: string): Promise<Record<string, unknown>>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ErrorI18nPayload } from "@camstack/types";
|
|
1
2
|
import type { CapActionChannelObserver } from "./cap-action-census.js";
|
|
2
3
|
import type { SocketTrafficSample } from "./socket-traffic.js";
|
|
3
4
|
/**
|
|
@@ -25,6 +26,8 @@ export type Frame = {
|
|
|
25
26
|
readonly id: number;
|
|
26
27
|
readonly ok: false;
|
|
27
28
|
readonly err: string;
|
|
29
|
+
/** Stable error code + params (D863), when the thrown error carried one. */
|
|
30
|
+
readonly i18n?: ErrorI18nPayload;
|
|
28
31
|
} | {
|
|
29
32
|
readonly k: "evt";
|
|
30
33
|
readonly body: unknown;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ErrorI18nPayload, TranslationParams } from "@camstack/types";
|
|
1
2
|
/**
|
|
2
3
|
* An error the FAR END of a channel answered with.
|
|
3
4
|
*
|
|
@@ -13,5 +14,8 @@
|
|
|
13
14
|
* node had answered (2026-09-25, device 3836).
|
|
14
15
|
*/
|
|
15
16
|
export declare class PeerAnsweredError extends Error {
|
|
16
|
-
|
|
17
|
+
/** The far end's stable error code (D863), carried so the hub can translate it. */
|
|
18
|
+
readonly i18nCode: string | undefined;
|
|
19
|
+
readonly i18nParams: TranslationParams | undefined;
|
|
20
|
+
constructor(message: string, i18n?: ErrorI18nPayload);
|
|
17
21
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_x509_es = require("./x509.es-
|
|
2
|
+
const require_x509_es = require("./x509.es-C4cOo48M.js");
|
|
3
3
|
const require_src$1 = require("./src-CnAqG6EF.js");
|
|
4
4
|
//#region ../../node_modules/source-map/lib/base64.js
|
|
5
5
|
var require_base64 = /* @__PURE__ */ require_chunk.__commonJSMin(((exports) => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as __toCommonJS, i as __require, n as __esmMin, r as __exportAll, t as __commonJSMin } from "./chunk-CNf5ZN-e.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { b as tslib_es6_exports, y as init_tslib_es6 } from "./x509.es-DK__ETIe.mjs";
|
|
3
3
|
import { t as require_src } from "./src-hG4grMU4.mjs";
|
|
4
4
|
//#region ../../node_modules/source-map/lib/base64.js
|
|
5
5
|
var require_base64 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as DATABASE_SNAPSHOT_SUFFIX } from "./dist-yI6kF6r6.mjs";
|
|
2
2
|
import { createCipheriv, createDecipheriv, createHash, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes } from "node:crypto";
|
|
3
3
|
import { Buffer as Buffer$1 } from "buffer";
|
|
4
4
|
import * as fsp from "node:fs/promises";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const require_chunk = require("./chunk-Cek0wNdY.js");
|
|
2
|
-
const require_dist = require("./dist-
|
|
2
|
+
const require_dist = require("./dist-BOWdLjoK.js");
|
|
3
3
|
let node_crypto = require("node:crypto");
|
|
4
4
|
let buffer = require("buffer");
|
|
5
5
|
let node_fs_promises = require("node:fs/promises");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { HttpsLeafInfo } from "@camstack/types";
|
|
2
2
|
import { type CertIdentity, type HostFacts } from "./cert-identity.js";
|
|
3
|
+
import { isLocalOnlyHostname } from "./cert-name-constraints.js";
|
|
3
4
|
export interface AgentHttpsPaths {
|
|
4
5
|
readonly dir: string;
|
|
5
6
|
/** The one atomic file: key + leaf + pinned CA. */
|
|
@@ -63,8 +64,7 @@ export declare function describeHttpsLeaf(certPem: string): HttpsLeafInfo;
|
|
|
63
64
|
export declare function isPrivateAddress(address: string): boolean;
|
|
64
65
|
/** The default docker bridge network (172.17.0.0/16): identical on every host, so it names nothing. */
|
|
65
66
|
export declare function isContainerBridgeAddress(address: string): boolean;
|
|
66
|
-
|
|
67
|
-
export declare function isLocalOnlyHostname(name: string): boolean;
|
|
67
|
+
export { isLocalOnlyHostname };
|
|
68
68
|
export interface AcceptedSans {
|
|
69
69
|
readonly identity: CertIdentity;
|
|
70
70
|
readonly accepted: readonly string[];
|
package/dist/tls/boot-tls.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ export interface BootTls {
|
|
|
17
17
|
* a certificate source that changed under the operator is never silent.
|
|
18
18
|
*/
|
|
19
19
|
readonly uploadedMissing: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* True when an UNCONSTRAINED local CA kept beside an uploaded certificate was replaced
|
|
22
|
+
* by a constrained one (D873). The served pair is untouched; agents' leaves chain to
|
|
23
|
+
* the new CA and clients that trusted the old one must re-trust. The caller logs it.
|
|
24
|
+
*/
|
|
25
|
+
readonly dormantCaReplaced: boolean;
|
|
20
26
|
}
|
|
21
27
|
/**
|
|
22
28
|
* Decide what the listener serves at boot. The admin UI (Network → Local
|
|
@@ -20,7 +20,7 @@ export declare const CA_RENEWAL_WINDOW_DAYS: number;
|
|
|
20
20
|
* verbatim — an operator who trusted the old certificate by hand learns
|
|
21
21
|
* from this string, not from a browser error.
|
|
22
22
|
*/
|
|
23
|
-
export type CertRegenerationReason = "missing" | "unreadable" | "no-local-ca" | "ca-expiring" | "key-mismatch" | "expiring" | "missing-server-auth-eku" | "not-issued-by-local-ca" | "validity-too-long" | "san-coverage-gap";
|
|
23
|
+
export type CertRegenerationReason = "missing" | "unreadable" | "no-local-ca" | "ca-expiring" | "ca-unconstrained" | "key-mismatch" | "expiring" | "missing-server-auth-eku" | "not-issued-by-local-ca" | "validity-too-long" | "san-coverage-gap";
|
|
24
24
|
export interface CertEvaluationInput {
|
|
25
25
|
/** Contents of `camstack.crt` — leaf first, then the issuing CA. */
|
|
26
26
|
readonly chainPem: string;
|
package/dist/tls/cert-issue.d.ts
CHANGED
|
@@ -19,8 +19,12 @@ export interface CaSigner {
|
|
|
19
19
|
* A local root: 10 years, `pathlen:0` so it can sign leaves and nothing
|
|
20
20
|
* else, and **no EKU** — Apple rejects an anchor asserting
|
|
21
21
|
* `anyExtendedKeyUsage`, and a root with no EKU constrains nothing.
|
|
22
|
+
*
|
|
23
|
+
* It carries a CRITICAL `nameConstraints` extension (D873): private address
|
|
24
|
+
* ranges and local-only DNS names, plus `hostnames` (the hub's own single-label
|
|
25
|
+
* names at creation). A leaked key therefore cannot vouch for a public site.
|
|
22
26
|
*/
|
|
23
|
-
export declare function generateCa(now: Date): Promise<CaSigner>;
|
|
27
|
+
export declare function generateCa(now: Date, hostnames?: readonly string[]): Promise<CaSigner>;
|
|
24
28
|
/** Re-open a root already on disk so a leaf can be issued under it. */
|
|
25
29
|
export declare function loadCa(certPem: string, keyPem: string): Promise<CaSigner>;
|
|
26
30
|
/**
|
|
@@ -27,6 +27,11 @@ export interface EnsureTlsResult {
|
|
|
27
27
|
readonly validTo: string;
|
|
28
28
|
readonly sans: readonly string[];
|
|
29
29
|
/**
|
|
30
|
+
* SAN values the local CA's name constraints (D873) do not permit, left out of the
|
|
31
|
+
* leaf. Empty when everything the machine answers to is certifiable.
|
|
32
|
+
*/
|
|
33
|
+
readonly droppedNames: readonly string[];
|
|
34
|
+
/**
|
|
30
35
|
* Set when a reissue was needed and FAILED, and the previous material is
|
|
31
36
|
* still being served. Never null-and-degraded silently: this is the line
|
|
32
37
|
* that says the certificate is not what the rule wants it to be.
|
|
@@ -91,6 +96,19 @@ export declare function ensureTlsCert(dataDir: string, options?: CertOptions): P
|
|
|
91
96
|
*/
|
|
92
97
|
export declare function reissueTlsLeaf(dataDir: string, options?: CertOptions): Promise<EnsureTlsResult>;
|
|
93
98
|
/**
|
|
99
|
+
* Uploaded mode keeps a generated CA beside the upload (agents' leaves are still signed
|
|
100
|
+
* by it). When that CA is unconstrained, replace it alone (D873): the served pair is the
|
|
101
|
+
* operator's and is never touched. Returns whether the CA was replaced.
|
|
102
|
+
*/
|
|
103
|
+
export declare function replaceUnconstrainedLocalCa(dataDir: string, options?: CertOptions): Promise<boolean>;
|
|
104
|
+
/** Marker path for the status reader and the retire step. */
|
|
105
|
+
export declare function caReplacementMarkerFile(dataDir: string): string;
|
|
106
|
+
/**
|
|
107
|
+
* Called once the HTTPS listener serves the leaf of the replacement CA: drop the retired
|
|
108
|
+
* unconstrained CA, key first. Idempotent; returns whether anything was removed.
|
|
109
|
+
*/
|
|
110
|
+
export declare function retirePreviousLocalCa(dataDir: string): boolean;
|
|
111
|
+
/**
|
|
94
112
|
* Load TLS cert+key from files. Returns Buffers suitable for Node.js TLS
|
|
95
113
|
* options. `certPath` is a full chain, so the listener presents the local
|
|
96
114
|
* root alongside the leaf.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Extension, type X509Certificate as PeculiarCertificate } from "@peculiar/x509";
|
|
2
|
+
import type { CertIdentity } from "./cert-identity.js";
|
|
3
|
+
/** `id-ce-nameConstraints`. */
|
|
4
|
+
export declare const NAME_CONSTRAINTS_OID = "2.5.29.30";
|
|
5
|
+
/** The address space the generated CA may certify. 100.64.0.0/10 is CGNAT, which Tailscale hands out. Loopback is for the hub's own `127.0.0.1` / `::1` SANs. */
|
|
6
|
+
export declare const PERMITTED_IP_RANGES: readonly string[];
|
|
7
|
+
/**
|
|
8
|
+
* Local-only DNS suffixes: none of them is delegated in public DNS. A leading
|
|
9
|
+
* dot permits every name under the suffix and not the suffix itself.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PERMITTED_DNS_SUFFIXES: readonly string[];
|
|
12
|
+
/** A name that cannot collide with public DNS: a single label, or under a local-only suffix. */
|
|
13
|
+
export declare function isLocalOnlyHostname(name: string): boolean;
|
|
14
|
+
/** What a CA may certify, as read from (or written into) its extension. */
|
|
15
|
+
export interface NameConstraintSet {
|
|
16
|
+
/** `ip/prefix` strings. */
|
|
17
|
+
readonly ipRanges: readonly string[];
|
|
18
|
+
/** Lower-cased DNS constraints: `.suffix` for a subtree, a bare name for the name and its subdomains. */
|
|
19
|
+
readonly dnsNames: readonly string[];
|
|
20
|
+
readonly critical: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* The constraint set for a new CA. `hostnames` are the hub's own local-only
|
|
24
|
+
* names at creation time (a single-label OS hostname has no suffix to hide
|
|
25
|
+
* under), added as exact entries; anything that could collide with public DNS
|
|
26
|
+
* is dropped here, never constrained in.
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildNameConstraintSet(hostnames: readonly string[]): NameConstraintSet;
|
|
29
|
+
/** The `nameConstraints` extension for a CA: permitted subtrees only, marked critical. */
|
|
30
|
+
export declare function createNameConstraintsExtension(set: NameConstraintSet): Extension;
|
|
31
|
+
/** The CA's constraint set, or `null` when the certificate carries no `nameConstraints`. */
|
|
32
|
+
export declare function readNameConstraints(cert: PeculiarCertificate): NameConstraintSet | null;
|
|
33
|
+
/**
|
|
34
|
+
* True when a CA is safe to keep as the hub's anchor: constrained to a
|
|
35
|
+
* non-empty permitted set AND marked critical. A non-critical constraint is
|
|
36
|
+
* ignored by clients that do not know the extension, which is the same as none.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isConstrainedCa(cert: PeculiarCertificate): boolean;
|
|
39
|
+
/** Is this SAN value (an IP literal or a DNS name) inside the permitted set? */
|
|
40
|
+
export declare function permitsName(set: NameConstraintSet, value: string): boolean;
|
|
41
|
+
export interface ConstrainedIdentity {
|
|
42
|
+
readonly identity: CertIdentity;
|
|
43
|
+
/** SAN values the CA's constraints do not permit, dropped from the leaf. */
|
|
44
|
+
readonly dropped: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The part of an identity the CA is allowed to certify. A leaf naming
|
|
48
|
+
* anything outside the constraints makes the WHOLE chain fail validation in
|
|
49
|
+
* OpenSSL, so such names are dropped (and reported), never signed. The
|
|
50
|
+
* required lists shrink the same way: otherwise a name the CA cannot certify
|
|
51
|
+
* would count as a permanent SAN gap and reissue the leaf on every boot.
|
|
52
|
+
*/
|
|
53
|
+
export declare function permitsIdentity(set: NameConstraintSet, identity: CertIdentity): ConstrainedIdentity;
|
package/dist/tls/index.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
export { CA_VALIDITY_DAYS, type CertEvaluationInput, LEAF_RENEWAL_WINDOW_DAYS, SERVER_AUTH_OID } from "./cert-evaluation.js";
|
|
2
|
-
export { type CertIdentity, type CertOptions, type HostFacts, type CertRegenerationReason, collectCertIdentity, type EnsureTlsResult, ensureTlsCert, reissueTlsLeaf, evaluateExistingCert, loadTlsCert, MAX_LEAF_VALIDITY_DAYS, type TlsCertPair } from "./cert-manager.js";
|
|
2
|
+
export { type CertIdentity, type CertOptions, type HostFacts, type CertRegenerationReason, collectCertIdentity, type EnsureTlsResult, ensureTlsCert, reissueTlsLeaf, replaceUnconstrainedLocalCa, retirePreviousLocalCa, caReplacementMarkerFile, evaluateExistingCert, loadTlsCert, MAX_LEAF_VALIDITY_DAYS, type TlsCertPair } from "./cert-manager.js";
|
|
3
3
|
export { type BootTls, type BootTlsMode, prepareBootTls } from "./boot-tls.js";
|
|
4
4
|
export { clearHttpsListener, type HttpsReloadOutcome, leafFingerprintOf, registerHttpsListener, reloadHttpsListener, servedHttpsLeafFingerprint } from "./https-listener.js";
|
|
5
|
-
export { applyCertificateToListener, regenerateCertificate, revertToGeneratedCertificate, storeUploadedCertificate, type UploadCertificateInput } from "./tls-actions.js";
|
|
5
|
+
export { applyCertificateToListener, regenerateCertificate, revertToGeneratedCertificate, storeUploadedCertificate, type UploadCertificateInput, useStoredUploadedCertificate } from "./tls-actions.js";
|
|
6
6
|
export { CA_COMMON_NAME } from "./cert-issue.js";
|
|
7
|
-
export { validateUploadedTls, type UploadedTlsValidation } from "./uploaded-cert.js";
|
|
8
|
-
export {
|
|
7
|
+
export { checkUploadedCa, chainsToPublicRoot, validateUploadedTls, type UploadedCaCheck, type UploadedTlsErrorCode, type UploadedTlsValidation } from "./uploaded-cert.js";
|
|
8
|
+
export { buildNameConstraintSet, isConstrainedCa, type NameConstraintSet, permitsIdentity, permitsName, readNameConstraints, PERMITTED_DNS_SUFFIXES, PERMITTED_IP_RANGES } from "./cert-name-constraints.js";
|
|
9
|
+
export { type StoredUploadInfo, type TlsAccessStatus, readTlsAccessStatus, splitPemCertificates, UPLOADED_CA_FILE, writeTlsMode, readTlsMode, readExtraSans, writeExtraSans } from "./tls-status.js";
|
|
9
10
|
export { acceptAgentSans, type AcceptedSans, AgentHttpsInstallError, type AgentHttpsMaterial, type AgentHttpsPaths, type AgentHttpsRequest, type AgentNames, agentHttpsPaths, certificateNames, collectAgentNames, createAgentHttpsRequest, describeHttpsLeaf, installAgentHttps, isContainerBridgeAddress, isLocalOnlyHostname, isPrivateAddress, issueAgentHttpsLeaf, type IssuedAgentHttps, loadAgentHttps, pemDigest, pinnedHttpsCaFingerprint } from "./agent-https.js";
|
|
10
11
|
export { AGENT_HTTPS_NAMES_COLLECTION, AGENT_HTTPS_NAMES_COLUMNS, AgentHttpsNames, getProcessAgentHttpsNames, setProcessAgentHttpsNames } from "./agent-https-names.js";
|
|
11
12
|
export { systemHostFacts } from "./cert-identity.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { X509Certificate } from "node:crypto";
|
|
1
2
|
import { type CertOptions } from "./cert-manager.js";
|
|
2
3
|
import { type HttpsReloadOutcome } from "./https-listener.js";
|
|
3
4
|
/**
|
|
@@ -10,17 +11,36 @@ export interface UploadCertificateInput {
|
|
|
10
11
|
readonly keyPem: string;
|
|
11
12
|
readonly caPem?: string | undefined;
|
|
12
13
|
}
|
|
14
|
+
/** Test seam: the trust anchors that count as "public". Defaults to the ones Node ships. */
|
|
15
|
+
export interface UploadCertificateOptions {
|
|
16
|
+
readonly publicRoots?: readonly X509Certificate[];
|
|
17
|
+
readonly now?: Date;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Store an operator's certificate (D873). The material is validated first, and a
|
|
21
|
+
* certificate that does not lead to a public CA must come with the CA that signed it
|
|
22
|
+
* (validated: it is a CA, in date, and issued the leaf) - otherwise "Download CA" would
|
|
23
|
+
* have nothing to hand out. Nothing is written when anything is refused.
|
|
24
|
+
*
|
|
25
|
+
* The leaf (or chain) and key are written twice: as the served pair, and as a kept copy
|
|
26
|
+
* (`uploaded.crt` / `uploaded.key`, with the issuing CA in `uploaded-ca.crt`) that
|
|
27
|
+
* "Revert to generated" leaves in place so the upload can be selected again. The local
|
|
28
|
+
* CA (`camstack-ca.crt` + key) is never touched - it did not sign the upload, and it is
|
|
29
|
+
* what every device that trusts it still needs.
|
|
30
|
+
*/
|
|
31
|
+
export declare function storeUploadedCertificate(dataDir: string, input: UploadCertificateInput, options?: UploadCertificateOptions): Promise<void>;
|
|
13
32
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* (`camstack-ca.crt` + key) is never touched — it did not sign the upload,
|
|
17
|
-
* and it is what "Revert to generated" and every device that trusts it
|
|
18
|
-
* still need.
|
|
33
|
+
* Serve the kept upload again after a revert (D873). Refused with a clear error when none
|
|
34
|
+
* is kept; the generated material stays on disk and is untouched.
|
|
19
35
|
*/
|
|
20
|
-
export declare function
|
|
36
|
+
export declare function useStoredUploadedCertificate(dataDir: string): Promise<void>;
|
|
21
37
|
/** Issue a new generated leaf under the local CA. Refused while an upload is served. */
|
|
22
38
|
export declare function regenerateCertificate(dataDir: string, options: CertOptions): Promise<void>;
|
|
23
|
-
/**
|
|
39
|
+
/**
|
|
40
|
+
* Serve the generated local-CA leaf again (D227). The uploaded certificate and its CA stay
|
|
41
|
+
* on disk (D873) so it can be selected again; an upload made before they were kept is
|
|
42
|
+
* copied aside first, from the pair being served.
|
|
43
|
+
*/
|
|
24
44
|
export declare function revertToGeneratedCertificate(dataDir: string, options: CertOptions): Promise<void>;
|
|
25
45
|
/**
|
|
26
46
|
* Put the pair on disk on the HTTPS listener. Called after every action, so
|
package/dist/tls/tls-status.d.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
export type TlsMode = "generated" | "uploaded" | "disabled";
|
|
2
|
+
/** An uploaded certificate kept on disk (D873): selectable again after "Revert to generated". */
|
|
3
|
+
export interface StoredUploadInfo {
|
|
4
|
+
readonly leafFingerprintSha256: string;
|
|
5
|
+
readonly validTo: string;
|
|
6
|
+
/** Whether a CA that signed it is kept with it. */
|
|
7
|
+
readonly hasCa: boolean;
|
|
8
|
+
}
|
|
2
9
|
export interface TlsAccessStatus {
|
|
3
10
|
readonly mode: TlsMode;
|
|
4
11
|
readonly leafFingerprintSha256: string | null;
|
|
@@ -8,11 +15,26 @@ export interface TlsAccessStatus {
|
|
|
8
15
|
readonly caCertPem: string | null;
|
|
9
16
|
readonly reissueError: string | null;
|
|
10
17
|
readonly restartRequired: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* An uploaded certificate is served but no CA that signed it is kept and the chain does
|
|
20
|
+
* not lead to a public CA: "Download CA" has nothing to hand out, so devices cannot be
|
|
21
|
+
* made to trust the hub (D873). `false` otherwise.
|
|
22
|
+
*/
|
|
23
|
+
readonly caMissing: boolean;
|
|
24
|
+
/** Does the hub's own generated CA carry a critical name constraint? `null` while it has no CA. */
|
|
25
|
+
readonly localCaConstrained: boolean | null;
|
|
26
|
+
/** ISO time the generated CA was replaced by a constrained one; devices must re-trust it. */
|
|
27
|
+
readonly caReplacedAt: string | null;
|
|
28
|
+
/** The uploaded certificate kept on disk, whether or not it is the one served. */
|
|
29
|
+
readonly storedUpload: StoredUploadInfo | null;
|
|
11
30
|
}
|
|
12
31
|
export declare function readTlsMode(dataDir: string): TlsMode;
|
|
13
32
|
export declare function writeTlsMode(dataDir: string, mode: TlsMode): void;
|
|
14
33
|
export declare function readExtraSans(dataDir: string): readonly string[];
|
|
15
34
|
export declare function writeExtraSans(dataDir: string, sans: readonly string[]): void;
|
|
35
|
+
/** The kept copy of the last upload: the chain and key as the operator supplied them. */
|
|
36
|
+
export declare const STORED_UPLOAD_CERT_FILE = "uploaded.crt";
|
|
37
|
+
export declare const STORED_UPLOAD_KEY_FILE = "uploaded.key";
|
|
16
38
|
/** Where an upload's own CA is kept — never over the local CA's `camstack-ca.crt`. */
|
|
17
39
|
export declare const UPLOADED_CA_FILE = "uploaded-ca.crt";
|
|
18
40
|
/** Every certificate in a PEM bundle, in order. */
|
|
@@ -1,14 +1,46 @@
|
|
|
1
|
+
import { X509Certificate } from "node:crypto";
|
|
2
|
+
/** Stable codes of the `server` i18n catalog (D863); the English text always travels beside them. */
|
|
3
|
+
export type UploadedTlsErrorCode = "tls.cert-unparsable" | "tls.key-unparsable" | "tls.key-mismatch" | "tls.missing-server-auth" | "tls.ca-required" | "tls.ca-unparsable" | "tls.ca-not-issuer" | "tls.ca-not-a-ca" | "tls.ca-expired";
|
|
4
|
+
export interface UploadedTlsFailure {
|
|
5
|
+
readonly ok: false;
|
|
6
|
+
readonly code: UploadedTlsErrorCode;
|
|
7
|
+
/** English text; the hub translates by `code`. */
|
|
8
|
+
readonly error: string;
|
|
9
|
+
}
|
|
1
10
|
export type UploadedTlsValidation = {
|
|
2
11
|
readonly ok: true;
|
|
3
12
|
readonly fingerprintSha256: string;
|
|
4
13
|
readonly validTo: string;
|
|
5
|
-
} |
|
|
6
|
-
readonly ok: false;
|
|
7
|
-
readonly error: string;
|
|
8
|
-
};
|
|
14
|
+
} | UploadedTlsFailure;
|
|
9
15
|
/**
|
|
10
16
|
* Operator-supplied material must parse, match its key, and carry
|
|
11
17
|
* `extendedKeyUsage = serverAuth` — the same leaf defects D227 refused
|
|
12
18
|
* to keep generating.
|
|
13
19
|
*/
|
|
14
20
|
export declare function validateUploadedTls(certPem: string, keyPem: string): UploadedTlsValidation;
|
|
21
|
+
/** Every certificate in a PEM bundle, in order. */
|
|
22
|
+
export declare function pemCertificates(pem: string): readonly string[];
|
|
23
|
+
/** The trust anchors of public CAs that ship with Node. */
|
|
24
|
+
export declare function publicRootCertificates(): readonly X509Certificate[];
|
|
25
|
+
/**
|
|
26
|
+
* True when the served chain leads to a public CA that clients already trust:
|
|
27
|
+
* the leaf, or one of the chain's own certificates, is signed by a public root.
|
|
28
|
+
* Such a certificate needs nothing installed on a device, so no CA is required.
|
|
29
|
+
*/
|
|
30
|
+
export declare function chainsToPublicRoot(chainPem: string, roots?: readonly X509Certificate[]): boolean;
|
|
31
|
+
export type UploadedCaCheck = {
|
|
32
|
+
readonly ok: true;
|
|
33
|
+
/** The CA that signed the leaf, to be kept for "Download CA"; `null` for a public chain with none supplied. */
|
|
34
|
+
readonly issuerPem: string | null;
|
|
35
|
+
readonly publicChain: boolean;
|
|
36
|
+
} | UploadedTlsFailure;
|
|
37
|
+
/**
|
|
38
|
+
* The CA rule for an upload (D873). A CA the operator supplies must parse, be a CA, be in
|
|
39
|
+
* date and actually have signed the leaf. Without one, the upload is accepted only when
|
|
40
|
+
* its own chain carries the issuer or leads to a public root; anything else is refused,
|
|
41
|
+
* because a device cannot be told to trust a certificate nobody can hand it the CA of.
|
|
42
|
+
*/
|
|
43
|
+
export declare function checkUploadedCa(chainPem: string, caPem: string | undefined, options?: {
|
|
44
|
+
readonly now?: Date;
|
|
45
|
+
readonly publicRoots?: readonly X509Certificate[];
|
|
46
|
+
}): UploadedCaCheck;
|
|
Binary file
|
|
Binary file
|
|
@@ -11913,6 +11913,12 @@ AsnEcSignatureFormatter.namedCurveSize.set("K-256", 32);
|
|
|
11913
11913
|
AsnEcSignatureFormatter.namedCurveSize.set("P-384", 48);
|
|
11914
11914
|
AsnEcSignatureFormatter.namedCurveSize.set("P-521", 66);
|
|
11915
11915
|
//#endregion
|
|
11916
|
+
Object.defineProperty(exports, "AsnConvert", {
|
|
11917
|
+
enumerable: true,
|
|
11918
|
+
get: function() {
|
|
11919
|
+
return AsnConvert;
|
|
11920
|
+
}
|
|
11921
|
+
});
|
|
11916
11922
|
Object.defineProperty(exports, "AuthorityKeyIdentifierExtension", {
|
|
11917
11923
|
enumerable: true,
|
|
11918
11924
|
get: function() {
|
|
@@ -11931,6 +11937,30 @@ Object.defineProperty(exports, "ExtendedKeyUsageExtension", {
|
|
|
11931
11937
|
return ExtendedKeyUsageExtension;
|
|
11932
11938
|
}
|
|
11933
11939
|
});
|
|
11940
|
+
Object.defineProperty(exports, "Extension", {
|
|
11941
|
+
enumerable: true,
|
|
11942
|
+
get: function() {
|
|
11943
|
+
return Extension;
|
|
11944
|
+
}
|
|
11945
|
+
});
|
|
11946
|
+
Object.defineProperty(exports, "GeneralName", {
|
|
11947
|
+
enumerable: true,
|
|
11948
|
+
get: function() {
|
|
11949
|
+
return GeneralName$1;
|
|
11950
|
+
}
|
|
11951
|
+
});
|
|
11952
|
+
Object.defineProperty(exports, "GeneralSubtree", {
|
|
11953
|
+
enumerable: true,
|
|
11954
|
+
get: function() {
|
|
11955
|
+
return GeneralSubtree;
|
|
11956
|
+
}
|
|
11957
|
+
});
|
|
11958
|
+
Object.defineProperty(exports, "GeneralSubtrees", {
|
|
11959
|
+
enumerable: true,
|
|
11960
|
+
get: function() {
|
|
11961
|
+
return GeneralSubtrees;
|
|
11962
|
+
}
|
|
11963
|
+
});
|
|
11934
11964
|
Object.defineProperty(exports, "KeyUsageFlags", {
|
|
11935
11965
|
enumerable: true,
|
|
11936
11966
|
get: function() {
|
|
@@ -11943,6 +11973,12 @@ Object.defineProperty(exports, "KeyUsagesExtension", {
|
|
|
11943
11973
|
return KeyUsagesExtension;
|
|
11944
11974
|
}
|
|
11945
11975
|
});
|
|
11976
|
+
Object.defineProperty(exports, "NameConstraints", {
|
|
11977
|
+
enumerable: true,
|
|
11978
|
+
get: function() {
|
|
11979
|
+
return NameConstraints;
|
|
11980
|
+
}
|
|
11981
|
+
});
|
|
11946
11982
|
Object.defineProperty(exports, "PemConverter", {
|
|
11947
11983
|
enumerable: true,
|
|
11948
11984
|
get: function() {
|
|
@@ -11913,4 +11913,4 @@ AsnEcSignatureFormatter.namedCurveSize.set("K-256", 32);
|
|
|
11913
11913
|
AsnEcSignatureFormatter.namedCurveSize.set("P-384", 48);
|
|
11914
11914
|
AsnEcSignatureFormatter.namedCurveSize.set("P-521", 66);
|
|
11915
11915
|
//#endregion
|
|
11916
|
-
export {
|
|
11916
|
+
export { backdatedNotBefore as S, NameConstraints as _, KeyUsageFlags as a, tslib_es6_exports as b, Pkcs10CertificateRequest as c, SubjectKeyIdentifierExtension as d, X509Certificate as f, GeneralSubtrees as g, GeneralSubtree as h, Extension as i, Pkcs10CertificateRequestGenerator as l, cryptoProvider as m, BasicConstraintsExtension as n, KeyUsagesExtension as o, X509CertificateGenerator as p, ExtendedKeyUsageExtension as r, PemConverter as s, AuthorityKeyIdentifierExtension as t, SubjectAlternativeNameExtension as u, GeneralName$1 as v, AsnConvert as x, init_tslib_es6 as y };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@camstack/system",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.439",
|
|
4
4
|
"description": "Core addon for CamStack — builtins, pipeline, process management, auth, logging, events",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"camstack",
|
|
@@ -491,6 +491,8 @@
|
|
|
491
491
|
"@camstack/types": "*",
|
|
492
492
|
"@homebridge/ciao": "^1.3.9",
|
|
493
493
|
"@msgpack/msgpack": "^3.1.3",
|
|
494
|
+
"@peculiar/asn1-schema": "^2.6.0",
|
|
495
|
+
"@peculiar/asn1-x509": "^2.6.1",
|
|
494
496
|
"@peculiar/x509": "^1.14.3",
|
|
495
497
|
"@trpc/client": "^11.16.0",
|
|
496
498
|
"@trpc/server": "^11.16.0",
|