@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
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mesh leaf renewal and revocation, driven by the hub (D856).
|
|
3
|
+
*
|
|
4
|
+
* The rule that shapes the order: a node must never be left without a leaf that
|
|
5
|
+
* works. So renewal is a handover, not a replacement:
|
|
6
|
+
*
|
|
7
|
+
* 1. the node makes a NEW key pair and a CSR (the key never leaves it);
|
|
8
|
+
* 2. the hub signs it (CN = the node id) and RECORDS the new leaf;
|
|
9
|
+
* 3. the node persists it beside the old one and reconnects with it;
|
|
10
|
+
* 4. the hub waits until it SEES that node connected presenting the NEW leaf;
|
|
11
|
+
* 5. only then does the hub tell the node to keep it, and put the OLD serial on
|
|
12
|
+
* the CRL.
|
|
13
|
+
*
|
|
14
|
+
* Failure at any step before 5 leaves the old leaf valid and not revoked, asks the
|
|
15
|
+
* node to go back to it (the node also goes back by itself when no confirmation
|
|
16
|
+
* arrives in time), and returns the reason. The new serial is never revoked on
|
|
17
|
+
* failure: the node may still hold it, and cutting it off would be the very
|
|
18
|
+
* outage this order exists to prevent.
|
|
19
|
+
*
|
|
20
|
+
* Every step is logged with the node id.
|
|
21
|
+
*/
|
|
22
|
+
import type { MeshCaSigner } from "./mesh-ca.js";
|
|
23
|
+
import { type MeshCertificateRegistry } from "./mesh-certificate-registry.js";
|
|
24
|
+
import type { MeshCrl } from "./mesh-crl.js";
|
|
25
|
+
import type { MeshPeerLeaf } from "./mesh-peer-transport.js";
|
|
26
|
+
/** The node side, as the hub calls it (the `node-certificates` capability, pinned to the node). */
|
|
27
|
+
export interface NodeMeshClient {
|
|
28
|
+
prepareMeshRenewal(): Promise<{
|
|
29
|
+
readonly csrPem: string;
|
|
30
|
+
}>;
|
|
31
|
+
installMeshLeaf(input: {
|
|
32
|
+
readonly certPem: string;
|
|
33
|
+
readonly caCertPem: string;
|
|
34
|
+
readonly confirmWithinMs: number;
|
|
35
|
+
}): Promise<{
|
|
36
|
+
readonly fingerprintSha256: string;
|
|
37
|
+
readonly serial: string;
|
|
38
|
+
}>;
|
|
39
|
+
confirmMeshLeaf(input: {
|
|
40
|
+
readonly fingerprintSha256: string;
|
|
41
|
+
}): Promise<{
|
|
42
|
+
readonly confirmed: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
rollbackMeshLeaf(): Promise<{
|
|
45
|
+
readonly rolledBack: boolean;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
export interface MeshPeers {
|
|
49
|
+
/** The leaf `nodeId` presented at its last handshake, while connected. */
|
|
50
|
+
peerLeaf(nodeId: string): MeshPeerLeaf | undefined;
|
|
51
|
+
/** Close the node's mutual-TLS sockets. */
|
|
52
|
+
dropPeer(nodeId: string): number;
|
|
53
|
+
}
|
|
54
|
+
/** "Node X finished registering" - the hub's registration completion (D3), not a poll. */
|
|
55
|
+
export interface MeshRegistrations {
|
|
56
|
+
subscribe(listener: (nodeId: string) => void): () => void;
|
|
57
|
+
}
|
|
58
|
+
export interface MeshLog {
|
|
59
|
+
info(message: string, extras?: {
|
|
60
|
+
tags?: Record<string, string>;
|
|
61
|
+
meta?: Record<string, unknown>;
|
|
62
|
+
}): void;
|
|
63
|
+
warn(message: string, extras?: {
|
|
64
|
+
tags?: Record<string, string>;
|
|
65
|
+
meta?: Record<string, unknown>;
|
|
66
|
+
}): void;
|
|
67
|
+
error(message: string, extras?: {
|
|
68
|
+
tags?: Record<string, string>;
|
|
69
|
+
meta?: Record<string, unknown>;
|
|
70
|
+
}): void;
|
|
71
|
+
}
|
|
72
|
+
export interface RenewMeshDeps {
|
|
73
|
+
readonly nodeId: string;
|
|
74
|
+
readonly client: NodeMeshClient;
|
|
75
|
+
readonly ca: MeshCaSigner;
|
|
76
|
+
readonly registry: MeshCertificateRegistry;
|
|
77
|
+
readonly crl: MeshCrl;
|
|
78
|
+
readonly peers: MeshPeers;
|
|
79
|
+
/** Registration completions: the node is usable once its manifest has landed. */
|
|
80
|
+
readonly registrations: MeshRegistrations;
|
|
81
|
+
readonly log: MeshLog;
|
|
82
|
+
/** How long to wait for the node to be back AND registered with the new leaf. */
|
|
83
|
+
readonly reconnectTimeoutMs?: number;
|
|
84
|
+
/** Gap between attempts to confirm while the node's capability is not there yet. */
|
|
85
|
+
readonly confirmRetryMs?: number;
|
|
86
|
+
readonly sleep?: (ms: number) => Promise<void>;
|
|
87
|
+
/** Single deadline timer (not a scan); a seam for specs. */
|
|
88
|
+
readonly setTimer?: (fn: () => void, ms: number) => {
|
|
89
|
+
cancel(): void;
|
|
90
|
+
};
|
|
91
|
+
readonly now?: () => number;
|
|
92
|
+
}
|
|
93
|
+
export type RenewMeshResult = {
|
|
94
|
+
readonly ok: true;
|
|
95
|
+
readonly oldSerial: string | null;
|
|
96
|
+
readonly newSerial: string;
|
|
97
|
+
readonly newNotAfter: number;
|
|
98
|
+
} | {
|
|
99
|
+
readonly ok: false;
|
|
100
|
+
readonly stage: "prepare" | "issue" | "install" | "reconnect" | "confirm";
|
|
101
|
+
readonly reason: string;
|
|
102
|
+
/** The node is back on its previous leaf (or never left it). */
|
|
103
|
+
readonly keptPreviousLeaf: boolean;
|
|
104
|
+
};
|
|
105
|
+
export declare function renewMeshCertificate(deps: RenewMeshDeps): Promise<RenewMeshResult>;
|
|
106
|
+
export interface RevokeMeshResult {
|
|
107
|
+
readonly nodeId: string;
|
|
108
|
+
/** Serials now on the revocation list for this node. */
|
|
109
|
+
readonly revokedSerials: readonly string[];
|
|
110
|
+
/** Live sockets that were closed. */
|
|
111
|
+
readonly disconnected: number;
|
|
112
|
+
/** What the operator does next - revoking never forgets the node. */
|
|
113
|
+
readonly next: string;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Revoke every live mesh leaf of `nodeId` and cut its connection. The node cannot
|
|
117
|
+
* reconnect: it must re-join with a new join token. The node is NOT forgotten
|
|
118
|
+
* (that stays `clusterNodes.forgetNode`).
|
|
119
|
+
*/
|
|
120
|
+
export declare function revokeMeshCertificate(deps: {
|
|
121
|
+
readonly nodeId: string;
|
|
122
|
+
readonly registry: MeshCertificateRegistry;
|
|
123
|
+
readonly crl: MeshCrl;
|
|
124
|
+
readonly peers: MeshPeers;
|
|
125
|
+
readonly log: MeshLog;
|
|
126
|
+
}): Promise<RevokeMeshResult>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The mesh TLS listener must not accept agents before the revocation registry has
|
|
3
|
+
* loaded (D856): until `mesh_node_certificates` is read, the CRL is empty, so a
|
|
4
|
+
* revoked leaf would be accepted - a fail-open on the one list whose job is to refuse.
|
|
5
|
+
*
|
|
6
|
+
* `openMeshTlsWhenRevocationsLoaded` therefore keeps the listener CLOSED while the
|
|
7
|
+
* registry cannot be loaded, and retries; it opens the listener exactly once, after
|
|
8
|
+
* the registry's revocations were replayed into the CRL. The hub itself talks to no
|
|
9
|
+
* one over this listener, so closed means "agents wait", not "the hub is down".
|
|
10
|
+
*/
|
|
11
|
+
/** What the admin UI shows about the hub's mesh listener (Identity -> Certificates). */
|
|
12
|
+
export type MeshTlsListenerState = {
|
|
13
|
+
readonly state: "open";
|
|
14
|
+
} | {
|
|
15
|
+
readonly state: "closed";
|
|
16
|
+
readonly reason: string;
|
|
17
|
+
readonly since: number;
|
|
18
|
+
};
|
|
19
|
+
export declare function setProcessMeshTlsListenerState(state: MeshTlsListenerState | null): void;
|
|
20
|
+
/** `null` before the gate has run at all (no mesh CA yet). */
|
|
21
|
+
export declare function getProcessMeshTlsListenerState(): MeshTlsListenerState | null;
|
|
22
|
+
export interface MeshTlsGateDeps<R> {
|
|
23
|
+
/** Load the registry and replay its revocations into the CRL. `null` when it cannot yet. */
|
|
24
|
+
readonly loadRegistry: () => Promise<R | null>;
|
|
25
|
+
/** Open the listener. Called until it succeeds (a failed open is retried), then never again. */
|
|
26
|
+
readonly open: (registry: R) => Promise<void>;
|
|
27
|
+
/** Run `fn` again after `ms` (an unref'd timer in production). */
|
|
28
|
+
readonly retry: (fn: () => void, ms: number) => void;
|
|
29
|
+
readonly retryMs?: number;
|
|
30
|
+
readonly onWaiting?: (attempt: number) => void;
|
|
31
|
+
readonly onError?: (error: unknown) => void;
|
|
32
|
+
/** Every change of the listener's state, for the status the admin UI reads. */
|
|
33
|
+
readonly onState?: (state: MeshTlsListenerState) => void;
|
|
34
|
+
readonly now?: () => number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Nothing in `run` can reject: a load or an open that throws is reported and retried, so a
|
|
38
|
+
* failure can never become an unhandled rejection that leaves the listener closed in silence.
|
|
39
|
+
*/
|
|
40
|
+
export declare function openMeshTlsWhenRevocationsLoaded<R>(deps: MeshTlsGateDeps<R>): Promise<boolean>;
|
|
@@ -113,6 +113,14 @@ export interface FilteredGossip {
|
|
|
113
113
|
* remove the payload is returned unchanged.
|
|
114
114
|
*/
|
|
115
115
|
export declare function keepOnlyGossipNodes(payload: unknown, keep: ReadonlySet<string>): FilteredGossip;
|
|
116
|
+
/** What a peer's leaf looks like, recorded at handshake. */
|
|
117
|
+
interface PeerLeaf {
|
|
118
|
+
readonly serial: string;
|
|
119
|
+
readonly fingerprint: string;
|
|
120
|
+
readonly notBefore: number;
|
|
121
|
+
readonly notAfter: number;
|
|
122
|
+
readonly remoteAddress?: string;
|
|
123
|
+
}
|
|
116
124
|
export declare class TlsTcpTransporter extends TcpTransporterBase {
|
|
117
125
|
private tlsServer;
|
|
118
126
|
private meshTls;
|
|
@@ -120,6 +128,8 @@ export declare class TlsTcpTransporter extends TcpTransporterBase {
|
|
|
120
128
|
private readonly tlsSockets;
|
|
121
129
|
/** Node id (certificate CN) → serial of every peer that completed a mutual-TLS handshake. */
|
|
122
130
|
private readonly tlsPeers;
|
|
131
|
+
/** Node id → the leaf it presented at its last handshake (hub inventory, D856). */
|
|
132
|
+
private readonly peerLeaves;
|
|
123
133
|
private clearDisabled;
|
|
124
134
|
private readonly hubTlsOnly;
|
|
125
135
|
private readonly hubOnlyPeers;
|
|
@@ -172,6 +182,11 @@ export declare class TlsTcpTransporter extends TcpTransporterBase {
|
|
|
172
182
|
* restarted node is back), in which case its live TLS socket keeps it `tls`.
|
|
173
183
|
*/
|
|
174
184
|
forgetPeer(nodeId: string): void;
|
|
185
|
+
private rememberPeerLeaf;
|
|
186
|
+
/** The leaf `nodeId` presented at its last mutual-TLS handshake. */
|
|
187
|
+
peerLeaf(nodeId: string): PeerLeaf | undefined;
|
|
188
|
+
/** Close every live mutual-TLS socket of `nodeId` (revocation, renewal). Returns how many. */
|
|
189
|
+
dropPeer(nodeId: string): number;
|
|
175
190
|
/** True once the mutual-TLS listener is bound. */
|
|
176
191
|
isTlsListening(): boolean;
|
|
177
192
|
isClearTransportEnabled(): boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as DATABASE_SNAPSHOT_SUFFIX } from "./dist-
|
|
1
|
+
import { g as DATABASE_SNAPSHOT_SUFFIX } from "./dist-CSSfTM18.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-Bgy_AmwX.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");
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which names the hub has certified to which agent (D856): the memory behind "a name
|
|
3
|
+
* already certified to another node is never signed again". Hub only.
|
|
4
|
+
*/
|
|
5
|
+
import type { CollectionColumn, SettingsStoreClient } from "@camstack/types";
|
|
6
|
+
/**
|
|
7
|
+
* @durable class=config owner=system-config
|
|
8
|
+
* write="the hub records the names it signed into an agent's HTTPS leaf, replacing that
|
|
9
|
+
* node's previous row"
|
|
10
|
+
* retention="one row per node, replaced on every issue; a forgotten node's row stays until
|
|
11
|
+
* the node is issued again or an operator clears it (it only blocks reuse of its names)"
|
|
12
|
+
*/
|
|
13
|
+
export declare const AGENT_HTTPS_NAMES_COLLECTION = "agent_https_names";
|
|
14
|
+
export declare const AGENT_HTTPS_NAMES_COLUMNS: readonly CollectionColumn[];
|
|
15
|
+
export declare class AgentHttpsNames {
|
|
16
|
+
private readonly store;
|
|
17
|
+
private readonly byNode;
|
|
18
|
+
constructor(store: SettingsStoreClient);
|
|
19
|
+
load(): Promise<void>;
|
|
20
|
+
/** Every name certified to a node other than `nodeId`. */
|
|
21
|
+
takenByOthers(nodeId: string): ReadonlySet<string>;
|
|
22
|
+
/** Free every name certified to a node that was forgotten. */
|
|
23
|
+
release(nodeId: string): Promise<boolean>;
|
|
24
|
+
record(nodeId: string, names: readonly string[]): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function setProcessAgentHttpsNames(names: AgentHttpsNames | null): void;
|
|
27
|
+
export declare function getProcessAgentHttpsNames(): AgentHttpsNames | null;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { HttpsLeafInfo } from "@camstack/types";
|
|
2
|
+
import { type CertIdentity, type HostFacts } from "./cert-identity.js";
|
|
3
|
+
export interface AgentHttpsPaths {
|
|
4
|
+
readonly dir: string;
|
|
5
|
+
/** The one atomic file: key + leaf + pinned CA. */
|
|
6
|
+
readonly bundlePath: string;
|
|
7
|
+
/** Informational copy of the leaf (public), written after the bundle. */
|
|
8
|
+
readonly certPath: string;
|
|
9
|
+
readonly pendingKeyPath: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function agentHttpsPaths(dataDir: string): AgentHttpsPaths;
|
|
12
|
+
export interface AgentHttpsMaterial {
|
|
13
|
+
readonly keyPem: string;
|
|
14
|
+
readonly certPem: string;
|
|
15
|
+
readonly caCertPem: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The material on disk, or `null` while no hub-issued leaf is installed. A bundle that
|
|
19
|
+
* cannot be parsed is reported through `onCorrupt` and treated as absent: a bad file must
|
|
20
|
+
* never take the agent API down.
|
|
21
|
+
*/
|
|
22
|
+
export declare function loadAgentHttps(dataDir: string, onCorrupt?: (reason: string) => void): AgentHttpsMaterial | null;
|
|
23
|
+
/** What an agent reports about itself for its certificate. */
|
|
24
|
+
export interface AgentNames {
|
|
25
|
+
readonly hostnames: readonly string[];
|
|
26
|
+
readonly addresses: readonly string[];
|
|
27
|
+
}
|
|
28
|
+
export declare function collectAgentNames(nodeId: string, hostFacts: HostFacts): AgentNames;
|
|
29
|
+
export interface AgentHttpsRequest extends AgentNames {
|
|
30
|
+
readonly csrPem: string;
|
|
31
|
+
}
|
|
32
|
+
/** SHA-256 of the hub local CA this agent pinned, or `null` while none is. */
|
|
33
|
+
export declare function pinnedHttpsCaFingerprint(dataDir: string): string | null;
|
|
34
|
+
/**
|
|
35
|
+
* A fresh key pair (EC P-256, kept in `agent.key.pending`, 0600) and its CSR. The
|
|
36
|
+
* key becomes `agent.key` only when the matching certificate is installed, so a
|
|
37
|
+
* request that is never answered changes nothing that is being served.
|
|
38
|
+
*/
|
|
39
|
+
export declare function createAgentHttpsRequest(dataDir: string, nodeId: string, names: AgentNames): Promise<AgentHttpsRequest>;
|
|
40
|
+
export declare class AgentHttpsInstallError extends Error {
|
|
41
|
+
constructor(message: string);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Install the hub-signed leaf for the pending key. Refused when it is not for that key, when
|
|
45
|
+
* it is not signed by the CA it came with, or - once a CA is pinned - when that CA is not the
|
|
46
|
+
* one this agent already pinned (the CA that arrives with a later leaf is never trusted on its
|
|
47
|
+
* own say: the first one came over the authenticated mesh, every later leaf must chain to it).
|
|
48
|
+
* Key, leaf and CA are written as ONE file, atomically.
|
|
49
|
+
*/
|
|
50
|
+
export declare function installAgentHttps(dataDir: string, input: {
|
|
51
|
+
readonly certPem: string;
|
|
52
|
+
readonly caCertPem: string;
|
|
53
|
+
/**
|
|
54
|
+
* The hub says its local CA was rotated and this leaf chains to the new one. Honoured only
|
|
55
|
+
* because the install call itself arrived over the authenticated mesh from the hub; without
|
|
56
|
+
* it a different CA is refused.
|
|
57
|
+
*/
|
|
58
|
+
readonly caRotation?: boolean;
|
|
59
|
+
}): AgentHttpsMaterial;
|
|
60
|
+
/** Fingerprint, issuer, SANs and validity of a served leaf. */
|
|
61
|
+
export declare function describeHttpsLeaf(certPem: string): HttpsLeafInfo;
|
|
62
|
+
/** Private-network IPv4/IPv6: RFC 1918, CGNAT (Tailscale), link-local, ULA. */
|
|
63
|
+
export declare function isPrivateAddress(address: string): boolean;
|
|
64
|
+
/** The default docker bridge network (172.17.0.0/16): identical on every host, so it names nothing. */
|
|
65
|
+
export declare function isContainerBridgeAddress(address: string): boolean;
|
|
66
|
+
/** A name that cannot collide with public DNS. */
|
|
67
|
+
export declare function isLocalOnlyHostname(name: string): boolean;
|
|
68
|
+
export interface AcceptedSans {
|
|
69
|
+
readonly identity: CertIdentity;
|
|
70
|
+
readonly accepted: readonly string[];
|
|
71
|
+
readonly rejected: readonly string[];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The names the hub will sign for `nodeId`: its node id and the address of its live mesh
|
|
75
|
+
* socket - nothing the agent says about itself. `excluded` holds every name already taken
|
|
76
|
+
* (the hub's own certificate, other nodes' leaves); `reported` is what the agent claimed,
|
|
77
|
+
* listed only so it can be logged as dropped.
|
|
78
|
+
*/
|
|
79
|
+
export declare function acceptAgentSans(input: {
|
|
80
|
+
readonly nodeId: string;
|
|
81
|
+
/** The remote address of the agent's live mesh socket, as the HUB sees it. */
|
|
82
|
+
readonly observedAddress?: string | undefined;
|
|
83
|
+
readonly excluded?: ReadonlySet<string>;
|
|
84
|
+
readonly reported?: readonly string[];
|
|
85
|
+
}): AcceptedSans;
|
|
86
|
+
/** The SAN values (lower-cased) of a certificate PEM: DNS names and IP addresses. */
|
|
87
|
+
export declare function certificateNames(certPem: string): ReadonlySet<string>;
|
|
88
|
+
export interface IssuedAgentHttps {
|
|
89
|
+
readonly certPem: string;
|
|
90
|
+
readonly caCertPem: string;
|
|
91
|
+
readonly accepted: readonly string[];
|
|
92
|
+
readonly rejected: readonly string[];
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Hub side: sign an agent's CSR under the local CA in `<hubDataDir>/tls`. Throws when
|
|
96
|
+
* there is no local CA to sign with or no name survives the policy.
|
|
97
|
+
*/
|
|
98
|
+
export declare function issueAgentHttpsLeaf(input: {
|
|
99
|
+
readonly hubDataDir: string;
|
|
100
|
+
readonly nodeId: string;
|
|
101
|
+
readonly csrPem: string;
|
|
102
|
+
/** What the agent reported. Never certified; only logged as dropped. */
|
|
103
|
+
readonly reportedNames?: readonly string[];
|
|
104
|
+
/** The remote address of the agent's live mesh socket, from the hub's own view. */
|
|
105
|
+
readonly observedAddress?: string | undefined;
|
|
106
|
+
/** Names already certified to OTHER nodes. */
|
|
107
|
+
readonly takenByOthers?: ReadonlySet<string>;
|
|
108
|
+
readonly now?: Date;
|
|
109
|
+
}): Promise<IssuedAgentHttps>;
|
|
110
|
+
/** SHA-256 of a PEM (for logs that must not print a certificate). */
|
|
111
|
+
export declare function pemDigest(pem: string): string;
|
package/dist/tls/cert-issue.d.ts
CHANGED
|
@@ -49,3 +49,10 @@ export declare function loadCa(certPem: string, keyPem: string): Promise<CaSigne
|
|
|
49
49
|
* Apple's `testAppTrustRoot_AnyEKU_AfterJul2019` asserts must fail.
|
|
50
50
|
*/
|
|
51
51
|
export declare function issueLeaf(ca: CaSigner, identity: CertIdentity, commonName: string, validDays: number, now: Date): Promise<CertMaterial>;
|
|
52
|
+
/**
|
|
53
|
+
* A server leaf for a key pair the CALLER holds (D856): an agent sends a CSR, the
|
|
54
|
+
* hub signs its public key under the local root. Same extensions as
|
|
55
|
+
* {@link issueLeaf} - `CA:FALSE`, serverAuth only - so a device that trusts the
|
|
56
|
+
* hub root trusts the agent. The private key never exists on the hub.
|
|
57
|
+
*/
|
|
58
|
+
export declare function issueLeafFromCsr(ca: CaSigner, csrPem: string, identity: CertIdentity, commonName: string, validDays: number, now: Date): Promise<string>;
|
package/dist/tls/index.d.ts
CHANGED
|
@@ -6,3 +6,6 @@ export { applyCertificateToListener, regenerateCertificate, revertToGeneratedCer
|
|
|
6
6
|
export { CA_COMMON_NAME } from "./cert-issue.js";
|
|
7
7
|
export { validateUploadedTls, type UploadedTlsValidation } from "./uploaded-cert.js";
|
|
8
8
|
export { type TlsAccessStatus, readTlsAccessStatus, splitPemCertificates, UPLOADED_CA_FILE, writeTlsMode, readTlsMode, readExtraSans, writeExtraSans } from "./tls-status.js";
|
|
9
|
+
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
|
+
export { AGENT_HTTPS_NAMES_COLLECTION, AGENT_HTTPS_NAMES_COLUMNS, AgentHttpsNames, getProcessAgentHttpsNames, setProcessAgentHttpsNames } from "./agent-https-names.js";
|
|
11
|
+
export { systemHostFacts } from "./cert-identity.js";
|