@camstack/system 1.2.380 → 1.2.382
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 +4 -2
- package/dist/addon-runner.mjs +4 -2
- package/dist/addon-utils.js +1 -1
- package/dist/addon-utils.mjs +1 -1
- package/dist/auth/admin-token-manager.d.ts +75 -0
- package/dist/auth/api-key-manager.d.ts +1 -14
- package/dist/auth/auth-audit-log.d.ts +59 -0
- package/dist/auth/auth-manager.d.ts +28 -16
- package/dist/auth/cidr.d.ts +22 -0
- package/dist/auth/login-session-manager.d.ts +158 -0
- package/dist/auth/user-management-internal.d.ts +69 -0
- 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.d.ts +14 -0
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +291 -3631
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +284 -3617
- package/dist/builtins/backup-orchestrator/encryption-key-store.d.ts +36 -0
- package/dist/builtins/backup-orchestrator/manifest-store.d.ts +19 -1
- package/dist/builtins/backup-orchestrator/restore-archive.d.ts +24 -0
- 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-aggregation.d.ts +12 -0
- package/dist/builtins/device-manager/device-form-secrets.d.ts +25 -0
- package/dist/builtins/device-manager/device-manager.addon.d.ts +2 -0
- package/dist/builtins/device-manager/device-manager.addon.js +165 -26
- package/dist/builtins/device-manager/device-manager.addon.mjs +165 -26
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/keychain/index.js +1108 -733
- package/dist/builtins/keychain/index.mjs +1108 -733
- package/dist/builtins/keychain/keychain-reset-trigger.d.ts +25 -0
- package/dist/builtins/keychain/keychain-service.d.ts +36 -3
- package/dist/builtins/keychain/keychain-store.d.ts +24 -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.d.ts +16 -0
- package/dist/builtins/local-auth/local-auth.addon.js +1021 -118
- package/dist/builtins/local-auth/local-auth.addon.mjs +1034 -141
- package/dist/builtins/local-network/local-network.addon.js +3 -3
- package/dist/builtins/local-network/local-network.addon.mjs +3 -3
- package/dist/builtins/loki-logging/index.js +97 -29
- package/dist/builtins/loki-logging/index.mjs +97 -29
- package/dist/builtins/loki-logging/loki-logging.addon.d.ts +7 -23
- package/dist/builtins/loki-logging/retire-enabled-flag.d.ts +23 -0
- 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/sqlite-settings.addon.js +0 -0
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +0 -0
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +2 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +2 -2
- package/dist/builtins/system-backup/backup-encryption.d.ts +57 -0
- package/dist/builtins/system-backup/system-backup.service.d.ts +16 -1
- package/dist/builtins/system-config/cluster-secret-keeper.d.ts +7 -0
- package/dist/builtins/system-config/system-config.addon.d.ts +13 -3
- package/dist/builtins/system-config/system-config.addon.js +324 -38
- package/dist/builtins/system-config/system-config.addon.mjs +312 -39
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{child-cap-dispatch-CZeRUgYF.js → child-cap-dispatch-BrMdKHfp.js} +6 -3
- package/dist/{child-cap-dispatch-CpjohToR.mjs → child-cap-dispatch-WsYPNvnK.mjs} +10 -7
- package/dist/{cluster-secret-Dg0OOOSr.js → cluster-secret-BEPLh3LL.js} +1 -1
- package/dist/{cluster-secret-BDue-uJj.mjs → cluster-secret-DhPdZ0VA.mjs} +1 -1
- package/dist/{composition-sources-CHvLMrFI.js → composition-sources-C6ZynCZ2.js} +1 -1
- package/dist/{composition-sources-DT_uJwI3.mjs → composition-sources-XqRX51db.mjs} +1 -1
- package/dist/{dist-B9oFw2jh.mjs → dist-CP5TTjwd.mjs} +1713 -157
- package/dist/{dist-Cc6KOdY-.js → dist-tnAO12ak.js} +1754 -156
- package/dist/{event-loop-stall-monitor-mk6WGxir.js → event-loop-stall-monitor-9kR0sAPS.js} +15 -15
- package/dist/{event-loop-stall-monitor-anUH2IE1.mjs → event-loop-stall-monitor-WkssIXjq.mjs} +15 -15
- package/dist/{hub-cap-forward-CH6_VWVO.mjs → hub-cap-forward-CDiN1p98.mjs} +18 -2
- package/dist/{hub-cap-forward-COCmYaup.js → hub-cap-forward-W8oEm4ME.js} +23 -1
- package/dist/index.d.ts +16 -1
- package/dist/index.js +3341 -79
- package/dist/index.mjs +3567 -354
- package/dist/{jwt-signing-key-Qhde8r82.mjs → jwt-signing-key-CAbozwvF.mjs} +1 -1
- package/dist/{jwt-signing-key-C2rE3wH6.js → jwt-signing-key-Dgf8sIXY.js} +1 -1
- package/dist/kernel/index.d.ts +12 -0
- package/dist/kernel/moleculer/broker-factory.d.ts +8 -1
- package/dist/kernel/moleculer/child-addon-call-dispatch.d.ts +1 -0
- package/dist/kernel/moleculer/hub-service.d.ts +9 -0
- package/dist/kernel/moleculer/mesh-access-middleware.d.ts +28 -0
- package/dist/kernel/moleculer/mesh-auth-mode.d.ts +64 -0
- package/dist/kernel/moleculer/mesh-authenticator.d.ts +71 -0
- package/dist/kernel/moleculer/mesh-auto-enforce.d.ts +26 -0
- package/dist/kernel/moleculer/mesh-join-client.d.ts +51 -0
- package/dist/kernel/moleculer/mesh-join-proof.d.ts +39 -0
- package/dist/kernel/system-settings-policy.d.ts +4 -3
- package/dist/kernel/transport/hub-cap-forward.d.ts +14 -3
- package/dist/kernel/transport/index.d.ts +1 -1
- package/dist/restore-archive-BV39nY46.mjs +4045 -0
- package/dist/restore-archive-CbvrfPuB.js +4139 -0
- package/dist/{retired-settings-keys-YOOKLA3v.js → retired-settings-keys-4bHpL-0m.js} +1 -1
- package/dist/{retired-settings-keys-DlZ3VV6x.mjs → retired-settings-keys-CzpIkwS-.mjs} +1 -1
- package/dist/{tls-CJHogwTl.mjs → tls-4cRH24Id.mjs} +3 -3
- package/package.json +1 -1
- package/dist/{tls-CCMX7MjX.js → tls-CljF057D.js} +1 -1
package/dist/kernel/index.d.ts
CHANGED
|
@@ -54,6 +54,18 @@ export { callRegisterNodeWithRetry, buildNodeManifest } from './moleculer/regist
|
|
|
54
54
|
export type { RegisterNodeBroker, CallRegisterNodeOptions, } from './moleculer/register-node-client.js';
|
|
55
55
|
export { hashClusterSecret, clusterSecretMatches, isClusterSecretMismatchError, CLUSTER_SECRET_MISMATCH_TYPE, CLUSTER_SECRET_REJECTED_EXIT_CODE, CLUSTER_SECRET_REF, CLUSTER_SECRET_SETTINGS_KEY, CLUSTER_SECRET_UNAVAILABLE_TYPE, checkClusterSecret, getProcessClusterSecretGate, setProcessClusterSecretGate, } from './moleculer/cluster-secret.js';
|
|
56
56
|
export type { ClusterSecretGate, ClusterSecretVerdict } from './moleculer/cluster-secret.js';
|
|
57
|
+
export { MeshAuthenticator, isRemoteForbiddenAction, MESH_JOIN_CHALLENGE_TTL_MS, } from './moleculer/mesh-authenticator.js';
|
|
58
|
+
export type { MeshAuthenticatorDeps, MeshCallVerdict, } from './moleculer/mesh-authenticator.js';
|
|
59
|
+
export { createMeshAccessMiddleware, stripForgedIdentity, } from './moleculer/mesh-access-middleware.js';
|
|
60
|
+
export type { MeshAccessMiddlewareOptions } from './moleculer/mesh-access-middleware.js';
|
|
61
|
+
export { MeshJoinClient } from './moleculer/mesh-join-client.js';
|
|
62
|
+
export type { MeshJoinCall, MeshJoinClientOptions, MeshJoinState, } from './moleculer/mesh-join-client.js';
|
|
63
|
+
export { computeHubJoinProof, computeNodeJoinProof, meshErrorType, MESH_ACTION_FORBIDDEN_TYPE, MESH_JOIN_AUTHENTICATE_ACTION, MESH_JOIN_CHALLENGE_ACTION, MESH_JOIN_CHALLENGE_INVALID_TYPE, MESH_JOIN_PROTOCOL, MESH_NODE_UNAUTHENTICATED_TYPE, } from './moleculer/mesh-join-proof.js';
|
|
64
|
+
export type { MeshJoinAuthenticateParams, MeshJoinAuthenticateResult, MeshJoinChallenge, } from './moleculer/mesh-join-proof.js';
|
|
65
|
+
export { getProcessMeshAuthMode, getProcessMeshAuthStatus, isMeshAuthMode, MESH_AUTH_MODE_FIELD, parseMeshAuthMode, requestProcessMeshEnforcement, setProcessMeshAuthMode, setProcessMeshAuthStatusSource, setProcessMeshEnforcer, } from './moleculer/mesh-auth-mode.js';
|
|
66
|
+
export { decideMeshAutoEnforce, MESH_AUTO_ENFORCE_GRACE_MS, } from './moleculer/mesh-auto-enforce.js';
|
|
67
|
+
export type { MeshAutoEnforceDecision, MeshAutoEnforceInput, } from './moleculer/mesh-auto-enforce.js';
|
|
68
|
+
export type { MeshAuthMode, MeshAuthStatus, MeshEnforcer, MeshNodeAuthEntry, MeshNodeAuthState, } from './moleculer/mesh-auth-mode.js';
|
|
57
69
|
export { serializeTypedArrays } from './moleculer/typed-array-serde.js';
|
|
58
70
|
export { createReadinessService, createReadinessServiceForRegistry, AGENT_READINESS_SERVICE_NAME, } from './moleculer/readiness-service.js';
|
|
59
71
|
export type { ReadinessServiceDeps } from './moleculer/readiness-service.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ServiceBroker } from 'moleculer';
|
|
1
|
+
import { ServiceBroker, Middleware } from 'moleculer';
|
|
2
2
|
interface BrokerConfig {
|
|
3
3
|
readonly nodeID: string;
|
|
4
4
|
readonly mode: 'hub' | 'agent' | 'test';
|
|
@@ -20,6 +20,13 @@ interface BrokerConfig {
|
|
|
20
20
|
* on one host.
|
|
21
21
|
*/
|
|
22
22
|
readonly agentListenPort?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Broker middlewares (D802): the hub passes its mesh gate
|
|
25
|
+
* (`createMeshAccessMiddleware`), an agent its join gate
|
|
26
|
+
* (`MeshJoinClient.middleware`). They must be given at construction —
|
|
27
|
+
* Moleculer wraps action handlers when services register.
|
|
28
|
+
*/
|
|
29
|
+
readonly middlewares?: readonly Middleware[];
|
|
23
30
|
}
|
|
24
31
|
/**
|
|
25
32
|
* Derive a STABLE Moleculer reader port for an agent from its nodeID.
|
|
@@ -2,6 +2,7 @@ import { ServiceSchema } from 'moleculer';
|
|
|
2
2
|
import { LogTags } from '@camstack/types';
|
|
3
3
|
import { RegisterNodeParams } from './node-registry.js';
|
|
4
4
|
import { ClusterSecretGate } from './cluster-secret.js';
|
|
5
|
+
import { MeshAuthenticator } from './mesh-authenticator.js';
|
|
5
6
|
interface HubServiceDeps {
|
|
6
7
|
readonly getAddonConfig: (addonId: string) => unknown;
|
|
7
8
|
readonly getSettings: (scope: string, key?: string) => unknown;
|
|
@@ -32,6 +33,14 @@ interface HubServiceDeps {
|
|
|
32
33
|
* Absent → `off` (test brokers); the hub always passes the keychain's gate.
|
|
33
34
|
*/
|
|
34
35
|
readonly clusterSecretGate?: () => ClusterSecretGate;
|
|
36
|
+
/**
|
|
37
|
+
* The hub's per-node mesh identity (D802). When present, `joinChallenge` /
|
|
38
|
+
* `authenticateNode` run the challenge–response and `registerNode` asks it
|
|
39
|
+
* whether the SENDER may register (`MeshAuthenticator.admitRegistration`);
|
|
40
|
+
* `clusterSecretGate` is then read through it. Absent → the D797 hash gate
|
|
41
|
+
* alone (test brokers).
|
|
42
|
+
*/
|
|
43
|
+
readonly meshAuth?: MeshAuthenticator;
|
|
35
44
|
}
|
|
36
45
|
declare function createHubService(deps: HubServiceDeps): ServiceSchema;
|
|
37
46
|
export { createHubService };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Middleware } from 'moleculer';
|
|
2
|
+
import { MeshAuthenticator } from './mesh-authenticator.js';
|
|
3
|
+
/**
|
|
4
|
+
* The params of a request from another node, with every identity it claimed
|
|
5
|
+
* removed:
|
|
6
|
+
* - a cap action's input loses `caller` (the user identity the hub's tRPC
|
|
7
|
+
* router injects for `caller: 'required'` methods — `keychainAdmin.reveal`
|
|
8
|
+
* reads it) and `callerAddonId` (the transport's addon stamp the keychain
|
|
9
|
+
* owner-checks);
|
|
10
|
+
* - `$hub-cap-fwd.forward` keeps its envelope `callerAddonId` — the forward
|
|
11
|
+
* service checks it against the sender's registered manifest — but the
|
|
12
|
+
* forwarded `args` lose both.
|
|
13
|
+
*/
|
|
14
|
+
export declare function stripForgedIdentity(action: string, params: unknown): unknown;
|
|
15
|
+
interface GateLogger {
|
|
16
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
17
|
+
}
|
|
18
|
+
export interface MeshAccessMiddlewareOptions {
|
|
19
|
+
readonly ownNodeId: string;
|
|
20
|
+
readonly authenticator: MeshAuthenticator;
|
|
21
|
+
readonly logger?: GateLogger;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build the middleware. Pass it in `ServiceBroker({ middlewares: [...] })`
|
|
25
|
+
* so it wraps every service, including the ones Moleculer creates itself.
|
|
26
|
+
*/
|
|
27
|
+
export declare function createMeshAccessMiddleware(options: MeshAccessMiddlewareOptions): Middleware;
|
|
28
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How strictly the hub holds other nodes to the mesh join (D802).
|
|
3
|
+
*
|
|
4
|
+
* - `transition`: a node that has not authenticated is TOLERATED — its calls
|
|
5
|
+
* run, a warning names it, and System → Cluster lists it as "not
|
|
6
|
+
* authenticated". This is how an existing cluster upgrades without
|
|
7
|
+
* splitting: the hub generates its secret, the operator copies it into each
|
|
8
|
+
* agent, and nothing is refused meanwhile.
|
|
9
|
+
* - `enforced`: a node that has not authenticated is refused on every action
|
|
10
|
+
* and its events are dropped. The D797 hash in `registerNode` is no longer
|
|
11
|
+
* accepted either — only the challenge–response.
|
|
12
|
+
*
|
|
13
|
+
* `transition` ends by itself once EVERY node the hub has ever seen (the
|
|
14
|
+
* cluster-node history) has authenticated with the challenge–response
|
|
15
|
+
* (`MeshAuthenticator.onAuthenticated` → `requestProcessMeshEnforcement`).
|
|
16
|
+
* The operator can also switch it in System → Cluster, in both directions.
|
|
17
|
+
*
|
|
18
|
+
* The mode lives in the `cluster` section of `system-settings`
|
|
19
|
+
* (`cluster.meshAuth`), owned by `system-config`, published here as a process
|
|
20
|
+
* slot the hub's broker reads on every call — the same pattern as the cluster
|
|
21
|
+
* secret gate (`cluster-secret.ts`).
|
|
22
|
+
*/
|
|
23
|
+
export type MeshAuthMode = 'transition' | 'enforced';
|
|
24
|
+
/** The field key inside the `cluster` section. */
|
|
25
|
+
export declare const MESH_AUTH_MODE_FIELD = "meshAuth";
|
|
26
|
+
export declare function isMeshAuthMode(value: unknown): value is MeshAuthMode;
|
|
27
|
+
/** A stored value that is not a mode reads as `transition`: never refuse on a typo. */
|
|
28
|
+
export declare function parseMeshAuthMode(value: unknown): MeshAuthMode;
|
|
29
|
+
/** How a node stands with the hub right now. */
|
|
30
|
+
export type MeshNodeAuthState =
|
|
31
|
+
/** Answered the challenge–response on its current connection. */
|
|
32
|
+
'authenticated'
|
|
33
|
+
/** Registered with the D797 hash (replayable) — accepted in `transition` only. */
|
|
34
|
+
| 'legacy'
|
|
35
|
+
/** Presented nothing: tolerated in `transition`, refused in `enforced`. */
|
|
36
|
+
| 'unauthenticated';
|
|
37
|
+
export interface MeshNodeAuthEntry {
|
|
38
|
+
readonly nodeId: string;
|
|
39
|
+
readonly state: MeshNodeAuthState;
|
|
40
|
+
/** Epoch ms of the last change. */
|
|
41
|
+
readonly since: number;
|
|
42
|
+
}
|
|
43
|
+
/** What System → Cluster shows. */
|
|
44
|
+
export interface MeshAuthStatus {
|
|
45
|
+
readonly mode: MeshAuthMode;
|
|
46
|
+
readonly nodes: readonly MeshNodeAuthEntry[];
|
|
47
|
+
}
|
|
48
|
+
/** Published by `system-config` whenever the stored mode is (re)read. */
|
|
49
|
+
export declare function setProcessMeshAuthMode(mode: MeshAuthMode): void;
|
|
50
|
+
/**
|
|
51
|
+
* The hub's mode. Until `system-config` has read it: `transition` — the safe
|
|
52
|
+
* side for an upgrading cluster (nothing that worked before is refused), and
|
|
53
|
+
* exactly what an unread setting means.
|
|
54
|
+
*/
|
|
55
|
+
export declare function getProcessMeshAuthMode(): MeshAuthMode;
|
|
56
|
+
export declare function clearProcessMeshAuthMode(): void;
|
|
57
|
+
/** Persists `enforced`; installed by `system-config`, which owns the setting. */
|
|
58
|
+
export type MeshEnforcer = (reason: string) => Promise<void>;
|
|
59
|
+
export declare function setProcessMeshEnforcer(enforcer: MeshEnforcer | null): void;
|
|
60
|
+
/** Ask the owner of the setting to switch to `enforced`. `false` when nobody can. */
|
|
61
|
+
export declare function requestProcessMeshEnforcement(reason: string): Promise<boolean>;
|
|
62
|
+
/** Published by the hub's broker; read by System → Cluster. */
|
|
63
|
+
export declare function setProcessMeshAuthStatusSource(source: (() => MeshAuthStatus) | null): void;
|
|
64
|
+
export declare function getProcessMeshAuthStatus(): MeshAuthStatus | null;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ClusterSecretGate } from './cluster-secret.js';
|
|
2
|
+
import { MeshAuthMode, MeshAuthStatus, MeshNodeAuthState } from './mesh-auth-mode.js';
|
|
3
|
+
import { MeshJoinAuthenticateParams, MeshJoinAuthenticateResult, MeshJoinChallenge } from './mesh-join-proof.js';
|
|
4
|
+
/** A challenge is answered within this window or not at all. */
|
|
5
|
+
export declare const MESH_JOIN_CHALLENGE_TTL_MS = 60000;
|
|
6
|
+
export declare function isRemoteForbiddenAction(action: string): boolean;
|
|
7
|
+
export type MeshCallVerdict = {
|
|
8
|
+
readonly verdict: 'allow';
|
|
9
|
+
readonly errorType?: undefined;
|
|
10
|
+
} | {
|
|
11
|
+
readonly verdict: 'tolerate';
|
|
12
|
+
readonly errorType?: undefined;
|
|
13
|
+
} | {
|
|
14
|
+
readonly verdict: 'deny';
|
|
15
|
+
readonly errorType: string;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
};
|
|
18
|
+
export interface MeshAuthenticatorDeps {
|
|
19
|
+
/** The hub's own node id — its local calls never pass through here. */
|
|
20
|
+
readonly ownNodeId: string;
|
|
21
|
+
/** The cluster secret as the keychain answers it now (D797). */
|
|
22
|
+
readonly gate: () => ClusterSecretGate;
|
|
23
|
+
readonly mode: () => MeshAuthMode;
|
|
24
|
+
readonly now?: () => number;
|
|
25
|
+
/** A node completed the challenge–response. */
|
|
26
|
+
readonly onAuthenticated?: (nodeId: string) => void;
|
|
27
|
+
/** First time a node is tolerated without proof on this connection. */
|
|
28
|
+
readonly onTolerated?: (nodeId: string, action: string) => void;
|
|
29
|
+
}
|
|
30
|
+
interface RegistrationLike {
|
|
31
|
+
readonly nodeId: string;
|
|
32
|
+
readonly clusterSecretHash?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare class MeshAuthenticator {
|
|
35
|
+
private readonly deps;
|
|
36
|
+
private readonly challenges;
|
|
37
|
+
private readonly nodes;
|
|
38
|
+
/** Completed the challenge–response at least once since the hub started. */
|
|
39
|
+
private readonly everAuthenticated;
|
|
40
|
+
/** Let in WITHOUT the challenge–response at least once since the hub started. */
|
|
41
|
+
private readonly everTolerated;
|
|
42
|
+
private readonly now;
|
|
43
|
+
constructor(deps: MeshAuthenticatorDeps);
|
|
44
|
+
issueChallenge(sender: string): MeshJoinChallenge;
|
|
45
|
+
authenticate(sender: string, params: MeshJoinAuthenticateParams): MeshJoinAuthenticateResult;
|
|
46
|
+
/** The node's connection dropped: it authenticates again when it returns. */
|
|
47
|
+
forget(nodeId: string): void;
|
|
48
|
+
admitCall(sender: string, action: string): MeshCallVerdict;
|
|
49
|
+
/** Same rule as a call, for an inbound event. */
|
|
50
|
+
admitEvent(sender: string, eventName: string): MeshCallVerdict;
|
|
51
|
+
private admitSender;
|
|
52
|
+
/** Throws when `sender` may not register `params`; returns when it may. */
|
|
53
|
+
admitRegistration(sender: string, params: RegistrationLike): void;
|
|
54
|
+
private noteTolerated;
|
|
55
|
+
stateOf(nodeId: string): MeshNodeAuthState;
|
|
56
|
+
/** Node ids that completed the challenge–response on their current connection. */
|
|
57
|
+
authenticatedNodeIds(): readonly string[];
|
|
58
|
+
/** Node ids that ever completed the challenge–response since the hub started. */
|
|
59
|
+
everAuthenticatedNodeIds(): ReadonlySet<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Node ids let in without the challenge–response since the hub started.
|
|
62
|
+
* Bounded: past {@link MAX_TRACKED_NODES} a flood of fake ids stops adding,
|
|
63
|
+
* and the ones already here keep the transition open (the operator can still
|
|
64
|
+
* switch to `enforced` by hand).
|
|
65
|
+
*/
|
|
66
|
+
everToleratedNodeIds(): readonly string[];
|
|
67
|
+
snapshot(): MeshAuthStatus;
|
|
68
|
+
private record;
|
|
69
|
+
private secretHashOrThrow;
|
|
70
|
+
}
|
|
71
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ClusterSecretGate } from './cluster-secret.js';
|
|
2
|
+
import { MeshAuthMode } from './mesh-auth-mode.js';
|
|
3
|
+
/** Boot grace before an empty or partial roster can end the transition. */
|
|
4
|
+
export declare const MESH_AUTO_ENFORCE_GRACE_MS: number;
|
|
5
|
+
export interface MeshAutoEnforceInput {
|
|
6
|
+
readonly mode: MeshAuthMode;
|
|
7
|
+
readonly gate: ClusterSecretGate['kind'];
|
|
8
|
+
readonly uptimeMs: number;
|
|
9
|
+
readonly graceMs?: number;
|
|
10
|
+
/** Agent node ids from the cluster-node history; `null` = the store did not answer. */
|
|
11
|
+
readonly knownAgents: readonly string[] | null;
|
|
12
|
+
readonly connected: readonly string[];
|
|
13
|
+
readonly toleratedEver: readonly string[];
|
|
14
|
+
readonly authenticatedEver: ReadonlySet<string>;
|
|
15
|
+
/** The hub's own id and its local children (`hub/<runner>`) are not agents. */
|
|
16
|
+
readonly ownNodeId: string;
|
|
17
|
+
}
|
|
18
|
+
export type MeshAutoEnforceDecision = {
|
|
19
|
+
readonly enforce: true;
|
|
20
|
+
readonly reason: string;
|
|
21
|
+
} | {
|
|
22
|
+
readonly enforce: false;
|
|
23
|
+
readonly waitingFor: readonly string[];
|
|
24
|
+
readonly why: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function decideMeshAutoEnforce(input: MeshAutoEnforceInput): MeshAutoEnforceDecision;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Middleware } from 'moleculer';
|
|
2
|
+
export type MeshJoinState = 'pending' | 'authenticated' | 'no-secret' | 'unsupported' | 'unavailable' | 'secret-mismatch' | 'hub-unverified';
|
|
3
|
+
export type MeshJoinCall = (action: string, params: unknown, opts?: {
|
|
4
|
+
nodeID?: string;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
}) => Promise<unknown>;
|
|
7
|
+
export interface MeshJoinClientOptions {
|
|
8
|
+
readonly nodeId: string;
|
|
9
|
+
/** The agent's cluster secret, read at each join (the operator may enter it at runtime). */
|
|
10
|
+
readonly secret: () => string | null;
|
|
11
|
+
readonly call: MeshJoinCall;
|
|
12
|
+
readonly hubNodeId?: string;
|
|
13
|
+
readonly maxAttempts?: number;
|
|
14
|
+
readonly retryDelayMs?: number;
|
|
15
|
+
readonly callTimeoutMs?: number;
|
|
16
|
+
/** How long a call waits for a pending join before it fails (default 30 s). */
|
|
17
|
+
readonly pendingWaitMs?: number;
|
|
18
|
+
readonly log?: (message: string) => void;
|
|
19
|
+
/** Told about every settled state. */
|
|
20
|
+
readonly onSettled?: (state: MeshJoinState) => void;
|
|
21
|
+
}
|
|
22
|
+
export declare class MeshJoinClient {
|
|
23
|
+
private readonly opts;
|
|
24
|
+
private current;
|
|
25
|
+
private settledWaiters;
|
|
26
|
+
private inFlight;
|
|
27
|
+
private readonly hubNodeId;
|
|
28
|
+
constructor(opts: MeshJoinClientOptions);
|
|
29
|
+
get state(): MeshJoinState;
|
|
30
|
+
/** Did this agent prove itself on the current connection? */
|
|
31
|
+
get authenticated(): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Run the join. Concurrent callers share one attempt. Resolves with the
|
|
34
|
+
* settled state; never rejects.
|
|
35
|
+
*/
|
|
36
|
+
join(): Promise<MeshJoinState>;
|
|
37
|
+
/** The hub connection dropped: the next connection authenticates again. */
|
|
38
|
+
reset(): void;
|
|
39
|
+
/** Resolves when a call to the hub may go out; rejects when it must not. */
|
|
40
|
+
whenCallable(): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Moleculer middleware for the AGENT broker: every call to the hub node waits
|
|
43
|
+
* for the join; a hub answer "not authenticated" (the hub restarted and lost
|
|
44
|
+
* us) triggers a new join.
|
|
45
|
+
*/
|
|
46
|
+
middleware(onUnauthenticated?: () => void): Middleware;
|
|
47
|
+
private secretPresent;
|
|
48
|
+
private settle;
|
|
49
|
+
private runJoin;
|
|
50
|
+
private attempt;
|
|
51
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Protocol version carried by the challenge; the agent refuses one it does not speak. */
|
|
2
|
+
export declare const MESH_JOIN_PROTOCOL = 1;
|
|
3
|
+
/** The hub's action that hands out a single-use nonce. */
|
|
4
|
+
export declare const MESH_JOIN_CHALLENGE_ACTION = "$hub.joinChallenge";
|
|
5
|
+
/** The hub's action that verifies a node's proof and answers with its own. */
|
|
6
|
+
export declare const MESH_JOIN_AUTHENTICATE_ACTION = "$hub.authenticateNode";
|
|
7
|
+
/** Moleculer error `type`: the sender has not authenticated and the hub enforces it. */
|
|
8
|
+
export declare const MESH_NODE_UNAUTHENTICATED_TYPE = "MESH_NODE_UNAUTHENTICATED";
|
|
9
|
+
/** Moleculer error `type`: the action is never callable from another node. */
|
|
10
|
+
export declare const MESH_ACTION_FORBIDDEN_TYPE = "MESH_ACTION_FORBIDDEN";
|
|
11
|
+
/** Moleculer error `type`: the challenge is unknown, used or expired — ask for a new one. */
|
|
12
|
+
export declare const MESH_JOIN_CHALLENGE_INVALID_TYPE = "MESH_JOIN_CHALLENGE_INVALID";
|
|
13
|
+
/** Answer of `$hub.joinChallenge`. */
|
|
14
|
+
export interface MeshJoinChallenge {
|
|
15
|
+
readonly protocol: number;
|
|
16
|
+
readonly nonce: string;
|
|
17
|
+
}
|
|
18
|
+
/** Params of `$hub.authenticateNode`. */
|
|
19
|
+
export interface MeshJoinAuthenticateParams {
|
|
20
|
+
readonly nodeId: string;
|
|
21
|
+
readonly nonce: string;
|
|
22
|
+
readonly clientNonce: string;
|
|
23
|
+
readonly proof: string;
|
|
24
|
+
}
|
|
25
|
+
/** Answer of `$hub.authenticateNode`. */
|
|
26
|
+
export interface MeshJoinAuthenticateResult {
|
|
27
|
+
readonly ok: true;
|
|
28
|
+
readonly hubProof: string;
|
|
29
|
+
}
|
|
30
|
+
/** A fresh 32-byte nonce, hex. */
|
|
31
|
+
export declare function createMeshNonce(): string;
|
|
32
|
+
/** The node's answer to the hub's nonce. `secretHash` is `hashClusterSecret(secret)`. */
|
|
33
|
+
export declare function computeNodeJoinProof(secretHash: string, nodeId: string, nonce: string): string;
|
|
34
|
+
/** The hub's answer to the node's nonce — proves the hub holds the same secret. */
|
|
35
|
+
export declare function computeHubJoinProof(secretHash: string, nodeId: string, nonce: string, clientNonce: string): string;
|
|
36
|
+
/** Constant-time comparison of two hex proofs; any shape mismatch is `false`. */
|
|
37
|
+
export declare function proofsEqual(expected: string, presented: unknown): boolean;
|
|
38
|
+
/** Reads a Moleculer error's `type`, including after an RPC round-trip. */
|
|
39
|
+
export declare function meshErrorType(err: unknown): string | null;
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* So a bootstrap-owned section is answered from env + config.yaml ONLY, and
|
|
15
15
|
* the store may add exactly the keys in {@link STORE_READABLE_BOOTSTRAP_KEYS}:
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* the values the operator edits on System → Authentication (`auth.tokenExpiry`,
|
|
17
|
+
* `auth.accessTokenExpiry`, `auth.trustedProxies`). Widening this list is a security decision, not a
|
|
18
18
|
* convenience.
|
|
19
19
|
*/
|
|
20
20
|
/** The only keys under a bootstrap-owned section the store may answer. */
|
|
@@ -32,7 +32,8 @@ export declare function storeMayAnswer(key: string): boolean;
|
|
|
32
32
|
export declare const PRELOADED_SYSTEM_PREFIXES: readonly string[];
|
|
33
33
|
/**
|
|
34
34
|
* Single keys loaded the same way. `auth.tokenExpiry` is read synchronously on
|
|
35
|
-
* every mint by the hub's `AuthService` (`AuthManager.signToken`)
|
|
35
|
+
* every mint by the hub's `AuthService` (`AuthManager.signToken`), and
|
|
36
|
+
* `auth.trustedProxies` on every public auth request (`auth-network-policy.ts`).
|
|
36
37
|
*/
|
|
37
38
|
export declare const PRELOADED_SYSTEM_KEYS: readonly string[];
|
|
38
39
|
/** Is `key` served from the boot-time mirror when the engine is isolated? */
|
|
@@ -27,9 +27,10 @@ export interface HubCapForwardParams {
|
|
|
27
27
|
/**
|
|
28
28
|
* The ORIGINATING addon, stamped by the AGENT's `LocalChildRegistry` off the
|
|
29
29
|
* child connection the call arrived on (D787) — the agent-side equivalent of
|
|
30
|
-
* what the hub's own registry stamps for a hub-local child. The hub
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* what the hub's own registry stamps for a hub-local child. The hub believes
|
|
31
|
+
* it only from a node that joined the mesh (D802: challenge–response; in
|
|
32
|
+
* `transition` an unauthenticated node is tolerated) and only when that
|
|
33
|
+
* node's registered manifest hosts the runner ({@link HubCapForwardOptions}).
|
|
33
34
|
* Absent → the call is anonymous, and an owner-checked cap refuses it.
|
|
34
35
|
*/
|
|
35
36
|
readonly callerAddonId?: string;
|
|
@@ -46,6 +47,16 @@ export interface HubCapForwardOptions {
|
|
|
46
47
|
/** Told about a dropped stamp — a misrouted or lying runner deserves a line. */
|
|
47
48
|
readonly onRejectedCaller?: (nodeId: string, callerAddonId: string) => void;
|
|
48
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Drop a `caller` the forwarded args carry. `caller` is the USER identity the
|
|
52
|
+
* hub's tRPC router injects for `caller: 'required'` methods
|
|
53
|
+
* (`cap-router-builder.ts`), and providers trust it — `keychainAdmin.reveal`
|
|
54
|
+
* reads `input.caller.userId`. A call that arrives over the mesh has no user
|
|
55
|
+
* session behind it, so whatever `caller` it carries is forged (D802). The
|
|
56
|
+
* args' `callerAddonId` is overwritten or stripped further down by
|
|
57
|
+
* `stampCallerAddonId`; `caller` had no such guard.
|
|
58
|
+
*/
|
|
59
|
+
export declare function stripForwardedCaller(args: unknown): unknown;
|
|
49
60
|
/**
|
|
50
61
|
* Handler that routes an agent-originated cap call through the hub's own
|
|
51
62
|
* unowned-call routing. Structurally the hub's `onUnownedCall`.
|
|
@@ -32,5 +32,5 @@ export { createParentUnownedCallHandler } from './parent-unowned-call.js';
|
|
|
32
32
|
export { answerClaimedGetStatus, deviceOfGetStatus, GET_STATUS_METHOD, } from './claimed-get-status.js';
|
|
33
33
|
export type { ClaimedGetStatusAnswer, ClaimedGetStatusCall } from './claimed-get-status.js';
|
|
34
34
|
export type { ParentUnownedCallDeps, ParentUnownedCallLogger } from './parent-unowned-call.js';
|
|
35
|
-
export { createHubCapForwardService, HUB_CAP_FWD_SERVICE, HUB_CAP_FWD_ACTION, } from './hub-cap-forward.js';
|
|
35
|
+
export { createHubCapForwardService, HUB_CAP_FWD_SERVICE, HUB_CAP_FWD_ACTION, stripForwardedCaller, } from './hub-cap-forward.js';
|
|
36
36
|
export type { HubCapForwardOptions, HubCapForwardParams, HubUnownedCallHandler, } from './hub-cap-forward.js';
|