@camstack/system 1.2.427 → 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.
Files changed (100) hide show
  1. package/dist/agent-https-names-CpUSuP4w.js +120 -0
  2. package/dist/agent-https-names-uetr4OQl.mjs +91 -0
  3. package/dist/auth/auth-audit-log.d.ts +1 -1
  4. package/dist/auth/device-ca-store.d.ts +57 -0
  5. package/dist/auth/device-ca.d.ts +75 -0
  6. package/dist/auth/device-credential-manager.d.ts +154 -0
  7. package/dist/auth/login-session-manager.d.ts +14 -2
  8. package/dist/auth/user-management-internal.d.ts +10 -1
  9. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
  10. package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
  11. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
  12. package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
  13. package/dist/builtins/alerts/alerts.addon.js +1 -1
  14. package/dist/builtins/alerts/alerts.addon.mjs +1 -1
  15. package/dist/builtins/autotrack/index.js +1 -1
  16. package/dist/builtins/autotrack/index.mjs +1 -1
  17. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +2 -2
  18. package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +2 -2
  19. package/dist/builtins/calendars/calendars.addon.js +1 -1
  20. package/dist/builtins/calendars/calendars.addon.mjs +1 -1
  21. package/dist/builtins/camera-grid/index.js +1 -1
  22. package/dist/builtins/camera-grid/index.mjs +1 -1
  23. package/dist/builtins/composer/composer.addon.js +2 -2
  24. package/dist/builtins/composer/composer.addon.mjs +2 -2
  25. package/dist/builtins/console-logging/index.js +1 -1
  26. package/dist/builtins/console-logging/index.mjs +1 -1
  27. package/dist/builtins/core-blocks/core-blocks.addon.js +2 -2
  28. package/dist/builtins/core-blocks/core-blocks.addon.mjs +2 -2
  29. package/dist/builtins/device-manager/device-manager.addon.js +2 -2
  30. package/dist/builtins/device-manager/device-manager.addon.mjs +2 -2
  31. package/dist/builtins/hub-forwarder/index.js +1 -1
  32. package/dist/builtins/hub-forwarder/index.mjs +1 -1
  33. package/dist/builtins/keychain/index.js +10 -6
  34. package/dist/builtins/keychain/index.mjs +8 -4
  35. package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
  36. package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
  37. package/dist/builtins/local-auth/local-auth.addon.d.ts +6 -0
  38. package/dist/builtins/local-auth/local-auth.addon.js +955 -47
  39. package/dist/builtins/local-auth/local-auth.addon.mjs +946 -41
  40. package/dist/builtins/local-network/local-network.addon.js +2 -2
  41. package/dist/builtins/local-network/local-network.addon.mjs +2 -2
  42. package/dist/builtins/loki-logging/index.js +1 -1
  43. package/dist/builtins/loki-logging/index.mjs +1 -1
  44. package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
  45. package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
  46. package/dist/builtins/platform-probe/index.js +1 -1
  47. package/dist/builtins/platform-probe/index.mjs +1 -1
  48. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
  49. package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
  50. package/dist/builtins/snapshot/index.js +1 -1
  51. package/dist/builtins/snapshot/index.mjs +1 -1
  52. package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
  53. package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
  54. package/dist/builtins/sqlite-storage/index.js +1 -1
  55. package/dist/builtins/sqlite-storage/index.mjs +1 -1
  56. package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +3 -3
  57. package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +3 -3
  58. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +1 -1
  59. package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +1 -1
  60. package/dist/builtins/system-config/system-config.addon.d.ts +18 -0
  61. package/dist/builtins/system-config/system-config.addon.js +834 -18
  62. package/dist/builtins/system-config/system-config.addon.mjs +819 -19
  63. package/dist/builtins/winston-logging/index.js +1 -1
  64. package/dist/builtins/winston-logging/index.mjs +1 -1
  65. package/dist/{composition-sources-DvCGZEUI.js → composition-sources-C2VNX6tF.js} +1 -1
  66. package/dist/{composition-sources-BQNxXQZG.mjs → composition-sources-SYtYuAgh.mjs} +1 -1
  67. package/dist/{constants-CR4If_lP.mjs → constants-CKuWoWvc.mjs} +1 -1
  68. package/dist/{constants-CCSJGnjs.js → constants-RI-hGP5S.js} +1 -1
  69. package/dist/device-ca-BWfdDB3k.js +462 -0
  70. package/dist/device-ca-R7DKKZL6.mjs +355 -0
  71. package/dist/{dist-BQG3QFg7.js → dist-Bgy_AmwX.js} +554 -0
  72. package/dist/{dist-DHSJV4Qc.mjs → dist-CSSfTM18.mjs} +507 -1
  73. package/dist/file-host-worker.js +1 -1
  74. package/dist/file-host-worker.mjs +1 -1
  75. package/dist/index.d.ts +4 -1
  76. package/dist/index.js +59 -12
  77. package/dist/index.mjs +10 -9
  78. package/dist/kernel/index.d.ts +2 -2
  79. package/dist/kernel/moleculer/mesh-mtls/index.d.ts +4 -1
  80. package/dist/kernel/moleculer/mesh-mtls/mesh-certificate-registry.d.ts +91 -0
  81. package/dist/kernel/moleculer/mesh-mtls/mesh-enroll.d.ts +4 -0
  82. package/dist/kernel/moleculer/mesh-mtls/mesh-peer-transport.d.ts +23 -0
  83. package/dist/kernel/moleculer/mesh-mtls/mesh-renewal.d.ts +126 -0
  84. package/dist/kernel/moleculer/mesh-mtls/mesh-tls-gate.d.ts +40 -0
  85. package/dist/kernel/moleculer/mesh-mtls/tls-tcp-transporter.d.ts +15 -0
  86. package/dist/{restore-archive-DH1Pxq_1.mjs → restore-archive-AIwMHO5_.mjs} +1 -1
  87. package/dist/{restore-archive-Dccm8lkA.js → restore-archive-BYUEMsog.js} +1 -1
  88. package/dist/{retired-settings-keys-BfGaSeQI.js → retired-settings-keys-BTPkRLTS.js} +1 -1
  89. package/dist/{retired-settings-keys-CPz7zpza.mjs → retired-settings-keys-H0rYXT27.mjs} +1 -1
  90. package/dist/tls/agent-https-names.d.ts +27 -0
  91. package/dist/tls/agent-https.d.ts +111 -0
  92. package/dist/tls/cert-issue.d.ts +7 -0
  93. package/dist/tls/index.d.ts +3 -0
  94. package/dist/{tls-BgImdxCO.js → tls-C5IYg3V5.js} +406 -0
  95. package/dist/{tls-CaOLZ09W.mjs → tls-CpcGkeJV.mjs} +314 -4
  96. package/dist/{wal-maintenance-DItkuOvu.js → wal-maintenance-BSGsxKW7.js} +0 -0
  97. package/dist/{wal-maintenance-Drqhcjit.mjs → wal-maintenance-DW0FfGV7.mjs} +0 -0
  98. package/package.json +4 -1
  99. package/dist/jwt-signing-key-BZm055IP.js +0 -174
  100. 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-DHSJV4Qc.mjs";
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-BQG3QFg7.js");
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");
@@ -1,4 +1,4 @@
1
- const require_dist = require("./dist-BQG3QFg7.js");
1
+ const require_dist = require("./dist-Bgy_AmwX.js");
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -1,4 +1,4 @@
1
- import { yr as asJsonObject } from "./dist-DHSJV4Qc.mjs";
1
+ import { Dr as asJsonObject } from "./dist-CSSfTM18.mjs";
2
2
  //#region src/builtins/sqlite-storage/retired-settings-keys.ts
3
3
  /**
4
4
  * Is THIS node the one whose settings store is the cluster's authority?
@@ -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;
@@ -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>;
@@ -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";