@camstack/server 1.2.594 → 1.2.596
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-root-inventory.js +50 -11
- package/dist/agent/addon-scan.js +44 -6
- package/dist/agent/agent-addon-runtime.js +8 -3
- package/dist/agent/agent-addon-updates.js +52 -12
- package/dist/agent/agent-cap-dispatch-service.js +5 -3
- package/dist/agent/agent-config.js +42 -7
- package/dist/agent/agent-deploy-swap.js +41 -5
- package/dist/agent/agent-group-runner.js +47 -8
- package/dist/agent/agent-http-auth.js +22 -10
- package/dist/agent/agent-http.js +113 -64
- package/dist/agent/agent-hub-addon-update.js +16 -10
- package/dist/agent/agent-hub-registration.js +7 -4
- package/dist/agent/agent-infra-capabilities.js +9 -5
- package/dist/agent/agent-json-file.js +42 -5
- package/dist/agent/agent-mesh-gate.js +8 -5
- package/dist/agent/agent-node-certificates.js +28 -25
- package/dist/agent/agent-pairing-local.js +47 -10
- package/dist/agent/agent-pairing-routes.js +20 -16
- package/dist/agent/agent-pairing-store.js +58 -18
- package/dist/agent/agent-reconnect.js +4 -1
- package/dist/agent/agent-service.js +71 -35
- package/dist/agent/agent-sniffing-listener.js +48 -11
- package/dist/agent/agent-undeploy.js +41 -5
- package/dist/agent/agent-update-routes.js +19 -14
- package/dist/agent/agent-update-service.js +80 -38
- package/dist/agent/apply-model-distribution.js +4 -1
- package/dist/agent/apply-stage-dev-uploads.js +9 -6
- package/dist/agent/derive-hub-url.js +8 -3
- package/dist/agent/fetch-bundle-from-hub.js +9 -6
- package/dist/agent/hubs-found.js +43 -6
- package/dist/agent/infra-boot-guard.js +4 -1
- package/dist/agent/infra-boot-plan.js +6 -2
- package/dist/agent/main.js +183 -148
- package/dist/agent/register-agent-cap-dispatch.js +6 -3
- package/dist/agent/serial-queue.js +7 -2
- package/dist/agent-status-page.js +4 -1
- package/dist/api/addon-upload.js +61 -22
- package/dist/api/agent-addon-delivery.js +11 -6
- package/dist/api/auth-whoami.js +4 -1
- package/dist/api/backup-download-pump.js +9 -5
- package/dist/api/backup-download.js +10 -7
- package/dist/api/core/addon-settings.router.js +19 -16
- package/dist/api/core/agent-pairing.router.js +79 -76
- package/dist/api/core/agents.router.js +24 -21
- package/dist/api/core/auth-admin-tokens.procedures.js +52 -48
- package/dist/api/core/auth-device-cert.procedures.js +67 -62
- package/dist/api/core/auth-limits.js +25 -16
- package/dist/api/core/auth-reauth.procedures.js +37 -32
- package/dist/api/core/auth-revoke-credentials.procedures.js +26 -22
- package/dist/api/core/auth-sessions.procedures.js +56 -52
- package/dist/api/core/auth.router.js +304 -300
- package/dist/api/core/cap-providers.js +121 -74
- package/dist/api/core/capabilities.router.js +37 -34
- package/dist/api/core/capability-preference-writes.js +17 -10
- package/dist/api/core/certificates.router.js +109 -106
- package/dist/api/core/cluster-nodes.router.js +18 -15
- package/dist/api/core/collection-preference.js +6 -2
- package/dist/api/core/event-bus-proxy.router.js +37 -34
- package/dist/api/core/failure-contributions.js +8 -4
- package/dist/api/core/hwaccel.router.js +20 -17
- package/dist/api/core/integration-secrets.js +12 -8
- package/dist/api/core/lifecycle-job-runner.js +49 -13
- package/dist/api/core/live-events.router.js +32 -29
- package/dist/api/core/load-contributions.js +8 -4
- package/dist/api/core/logging-settings.js +43 -30
- package/dist/api/core/logs.router.js +43 -40
- package/dist/api/core/notifications.router.js +18 -15
- package/dist/api/core/public-event-filter.js +8 -4
- package/dist/api/core/repl.router.js +21 -18
- package/dist/api/core/request-census-settings.js +16 -11
- package/dist/api/core/server-management.provider.js +4 -1
- package/dist/api/core/server-name.js +17 -9
- package/dist/api/core/site-location.js +24 -16
- package/dist/api/core/stream-probe.router.js +24 -21
- package/dist/api/core/system-events.router.js +26 -23
- package/dist/api/cors/cors-policy.js +29 -20
- package/dist/api/cors/register-cors-policy.js +14 -9
- package/dist/api/deploy-stage-registry.js +10 -6
- package/dist/api/dev-uploads-bundle.js +50 -12
- package/dist/api/health/adaptive-probe.routes.js +13 -9
- package/dist/api/health/health.routes.js +13 -8
- package/dist/api/hub-cluster-url.js +9 -3
- package/dist/api/model-distributor.js +50 -12
- package/dist/api/oauth2/consent-page.js +13 -10
- package/dist/api/oauth2/oauth2-routes.js +25 -17
- package/dist/api/oauth2/private-host.js +4 -1
- package/dist/api/server-upload-propagate.js +51 -15
- package/dist/api/server-upload.js +50 -13
- package/dist/api/sse-no-compression.js +4 -1
- package/dist/api/static/frame-policy.js +9 -4
- package/dist/api/static/precompressed-asset.js +57 -15
- package/dist/api/static/spa-mount.js +47 -8
- package/dist/api/static/spa-static.js +12 -5
- package/dist/api/tarball-manifest.js +44 -7
- package/dist/api/trpc/cap-mount-helpers.js +12 -7
- package/dist/api/trpc/cap-route-error-formatter.js +13 -10
- package/dist/api/trpc/cap-router-runtime.js +51 -40
- package/dist/api/trpc/client-ip.js +20 -9
- package/dist/api/trpc/core-cap-bridge.js +42 -32
- package/dist/api/trpc/device-collection-dispatch.js +27 -23
- package/dist/api/trpc/device-config-secret-redaction.js +40 -24
- package/dist/api/trpc/generated-cap-mounts.js +225 -219
- package/dist/api/trpc/generated-cap-routers.js +5167 -4852
- package/dist/api/trpc/http-request-census-hook.js +11 -8
- package/dist/api/trpc/http-request-census.js +41 -34
- package/dist/api/trpc/http-request-census.singleton.js +8 -4
- package/dist/api/trpc/localized-schema-paths.js +4 -1
- package/dist/api/trpc/principal-visibility.js +22 -14
- package/dist/api/trpc/remote-addon-update-grant.js +4 -1
- package/dist/api/trpc/scope-access.js +15 -10
- package/dist/api/trpc/server-provided-caps.js +7 -3
- package/dist/api/trpc/share-view-access.js +14 -6
- package/dist/api/trpc/trpc-error-device-tags.js +6 -3
- package/dist/api/trpc/trpc-error-principal.js +6 -2
- package/dist/api/trpc/trpc.context.js +25 -20
- package/dist/api/trpc/trpc.middleware.js +46 -38
- package/dist/api/trpc/trpc.router.js +99 -58
- package/dist/api/trpc/user-error.js +8 -5
- package/dist/api/trpc/ws-request-census.js +24 -17
- package/dist/api/trpc/ws-slow-consumer-guard.js +16 -11
- package/dist/api/upload-auth.js +9 -5
- package/dist/auth/addon-route-jwt-gate.js +7 -4
- package/dist/auth/addon-route-share-gate.js +12 -7
- package/dist/auth/app-confirm-page.js +22 -17
- package/dist/auth/app-confirm-routes.js +31 -26
- package/dist/auth/app-confirmations.js +44 -7
- package/dist/auth/app-page-shell.js +30 -17
- package/dist/auth/app-page-strings.js +17 -11
- package/dist/auth/app-passkey-page.js +21 -16
- package/dist/auth/app-passkey-routes.js +41 -37
- package/dist/auth/app-refused-route.js +18 -13
- package/dist/auth/auth-network-policy.js +15 -11
- package/dist/auth/auth-provider-gate.js +9 -4
- package/dist/auth/auth-rate-limit.js +7 -3
- package/dist/auth/client-address.js +9 -6
- package/dist/auth/device-enroll-proofs.js +43 -6
- package/dist/auth/external-link-intents.js +7 -3
- package/dist/auth/hub-sessions.js +12 -6
- package/dist/auth/native-link-completions.js +11 -7
- package/dist/auth/native-return.js +13 -9
- package/dist/auth/passkey-provider.js +32 -26
- package/dist/auth/second-factors.js +10 -6
- package/dist/auth/session-connections.js +12 -6
- package/dist/auth/session-cookie.js +23 -12
- package/dist/auth/session-lifetimes.js +12 -8
- package/dist/auth/session-mint.js +11 -4
- package/dist/auth/sso-finish-app.js +16 -13
- package/dist/auth/sso-finish-deps.js +27 -21
- package/dist/auth/sso-finish.js +38 -28
- package/dist/auth/sso-routes.js +25 -22
- package/dist/auth/used-bridge-ids.js +5 -1
- package/dist/boot/boot-config.js +55 -16
- package/dist/boot/init-sequence.js +4 -1
- package/dist/boot/integration-id-backfill.js +8 -3
- package/dist/boot/platform-keychain-key.js +42 -5
- package/dist/boot/post-boot.service.js +18 -14
- package/dist/boot/reconcile-lifecycle-jobs.js +6 -3
- package/dist/boot/retired-public-url-env.js +8 -4
- package/dist/bootstrap-packages.js +4 -1
- package/dist/closure-node-modules.js +38 -2
- package/dist/core/addon/addon-call-gateway.js +5 -1
- package/dist/core/addon/addon-package.service.js +123 -83
- package/dist/core/addon/addon-process-view.js +6 -2
- package/dist/core/addon/addon-realign-plan.js +4 -1
- package/dist/core/addon/addon-registry.service.js +187 -146
- package/dist/core/addon/addon-row-manifest.js +4 -1
- package/dist/core/addon/addon-search.service.js +7 -3
- package/dist/core/addon/addon-settings-provider.js +3 -1
- package/dist/core/addon/addon-uninstall.js +11 -4
- package/dist/core/addon/addon.tokens.js +5 -2
- package/dist/core/addon/device-meta-mirror.js +13 -8
- package/dist/core/addon/forked-custom-actions.js +11 -6
- package/dist/core/addon/integration-visibility.js +6 -3
- package/dist/core/addon/materialize-route-path.js +4 -1
- package/dist/core/addon/package-dir-utils.js +45 -8
- package/dist/core/addon/prune-misplaced-addons.js +43 -5
- package/dist/core/addon/runner-convergence.js +4 -1
- package/dist/core/addon/runner-serialization.js +4 -1
- package/dist/core/addon/runner-spawn-fanout.js +8 -3
- package/dist/core/addon/settings-door-wiring.js +8 -5
- package/dist/core/addon/single-flight-refresh.js +4 -1
- package/dist/core/addon-bridge/addon-bridge.service.js +44 -7
- package/dist/core/addon-pages/addon-pages.service.js +40 -3
- package/dist/core/addon-widgets/addon-widgets.service.js +42 -4
- package/dist/core/agent/agent-addon-backfill.js +17 -9
- package/dist/core/agent/agent-delivery-ledger.js +7 -3
- package/dist/core/agent/agent-liveness-event.js +6 -2
- package/dist/core/agent/agent-pairing-http.js +45 -41
- package/dist/core/agent/agent-registry.service.js +89 -50
- package/dist/core/agent/cluster-node-history-mirror.js +7 -3
- package/dist/core/agent/cluster-node-history-store.js +35 -31
- package/dist/core/agent/hub-agent-pairing.js +5 -1
- package/dist/core/agent/node-certificates-client.js +6 -3
- package/dist/core/agent/node-directory.js +4 -1
- package/dist/core/app-links/well-known-app-links.js +6 -2
- package/dist/core/auth/auth.service.js +8 -3
- package/dist/core/auth/handoff-code.service.js +49 -11
- package/dist/core/auth/record-kinds.js +19 -16
- package/dist/core/auth/share-token.service.js +79 -42
- package/dist/core/capability/capability.service.js +5 -1
- package/dist/core/config/config.schema.js +6 -1
- package/dist/core/config/config.service.js +6 -2
- package/dist/core/events/event-bus.service.js +7 -3
- package/dist/core/feature/feature.service.js +6 -2
- package/dist/core/lifecycle/lifecycle-runner.singleton.js +10 -5
- package/dist/core/lifecycle/lifecycle-state-machine.js +5 -1
- package/dist/core/logging/log-ring-buffer.js +5 -1
- package/dist/core/logging/logging.service.js +9 -5
- package/dist/core/logging/scoped-logger.js +5 -1
- package/dist/core/moleculer/agent-readiness-pull.js +4 -1
- package/dist/core/moleculer/agent-registration-request.js +7 -3
- package/dist/core/moleculer/cap-call-fn.js +7 -4
- package/dist/core/moleculer/cap-route-authority.js +8 -3
- package/dist/core/moleculer/hub-mesh-guard.js +9 -5
- package/dist/core/moleculer/moleculer.service.js +86 -79
- package/dist/core/network/network-quality.service.js +6 -2
- package/dist/core/notification/notification-wrapper.service.js +7 -3
- package/dist/core/notification/toast-wrapper.service.js +7 -3
- package/dist/core/provider/provider.tokens.js +4 -1
- package/dist/core/repl/repl-engine.service.js +8 -4
- package/dist/core/runner-health/runner-boot-check.js +15 -7
- package/dist/core/runner-health/update-preflight.js +14 -9
- package/dist/core/server-update/server-update.service.js +49 -12
- package/dist/core/server-update/system-apply-closure-patches.js +42 -6
- package/dist/core/server-update/system-ensure-prebuilds.js +6 -3
- package/dist/core/server-update/system-exec-npm.js +5 -2
- package/dist/core/storage/fs-storage-backend.js +5 -1
- package/dist/core/storage/storage-location-manager.js +5 -1
- package/dist/core/storage/storage.service.js +6 -2
- package/dist/core/streaming/ffmpeg-stream-info.js +8 -3
- package/dist/core/streaming/stream-probe.service.js +16 -12
- package/dist/core/streaming/ttl-cache.js +5 -1
- package/dist/core/topology/topology-emitter.service.js +23 -19
- package/dist/core/update-availability-emitter.js +7 -3
- package/dist/core/update-availability-store.js +45 -8
- package/dist/core/updates/agent-installed-packages.js +9 -5
- package/dist/core/updates/restart-marker.js +8 -3
- package/dist/core/updates/update-check-scheduler.js +18 -13
- package/dist/core/updates/wrapper-update-checker.js +7 -3
- package/dist/first-boot-addon-plan.js +6 -2
- package/dist/framework-nodepath.js +38 -2
- package/dist/i18n/request-lang.js +11 -7
- package/dist/launcher.js +65 -30
- package/dist/lifecycle-journal-path.js +38 -2
- package/dist/main.js +324 -286
- package/dist/manual-boot.js +156 -117
- package/dist/node-role.js +4 -1
- package/dist/package-inventory.js +48 -7
- package/dist/pending-restore.js +43 -7
- package/dist/single-copy-cleanup-runner.js +45 -9
- package/dist/single-copy-cleanup.js +15 -7
- package/dist/sqlite-restore.js +48 -9
- package/dist/starter.js +39 -4
- package/dist/ui-serving/lazy-ui-serving.js +39 -3
- package/package.json +7 -7
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.finishSsoApp = finishSsoApp;
|
|
1
4
|
/**
|
|
2
5
|
* `/api/auth/sso/finish-app` - the native-app leg of an OIDC sign-in (D858).
|
|
3
6
|
*
|
|
@@ -27,41 +30,41 @@
|
|
|
27
30
|
*
|
|
28
31
|
* Pure: the Fastify route in `sso-routes.ts` wires the deps and maps the outcome.
|
|
29
32
|
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const types_1 = require("@camstack/types");
|
|
34
|
+
const auth_provider_gate_js_1 = require("./auth-provider-gate.js");
|
|
35
|
+
const session_mint_js_1 = require("./session-mint.js");
|
|
36
|
+
const sso_finish_js_1 = require("./sso-finish.js");
|
|
34
37
|
function refused(error, deps, redirect, state) {
|
|
35
38
|
deps.logRefusal?.(error);
|
|
36
|
-
return { kind: 'app', location: appFlowLocation(redirect, { error }, state) };
|
|
39
|
+
return { kind: 'app', location: (0, types_1.appFlowLocation)(redirect, { error }, state) };
|
|
37
40
|
}
|
|
38
41
|
/** Exchange a verified app login bridge for a handoff code at the app's callback. */
|
|
39
|
-
|
|
40
|
-
const fallback = APP_FLOW_DEFAULT_REDIRECT;
|
|
42
|
+
async function finishSsoApp(bridge, deps) {
|
|
43
|
+
const fallback = types_1.APP_FLOW_DEFAULT_REDIRECT;
|
|
41
44
|
if (!bridge)
|
|
42
45
|
return refused('invalid-bridge', deps, fallback, undefined);
|
|
43
46
|
const claims = deps.verifyBridge(bridge);
|
|
44
47
|
if (claims === null)
|
|
45
48
|
return refused('invalid-bridge', deps, fallback, undefined);
|
|
46
49
|
const app = claims.app;
|
|
47
|
-
if (app === undefined || !isLoginBridge(claims)) {
|
|
50
|
+
if (app === undefined || !(0, sso_finish_js_1.isLoginBridge)(claims)) {
|
|
48
51
|
return refused('not-app-flow', deps, fallback, undefined);
|
|
49
52
|
}
|
|
50
53
|
// The signed redirect is checked against the allow-list again: the finish
|
|
51
54
|
// never trusts a stored URL to be one it would accept.
|
|
52
|
-
const redirect = parseAppAuthCallback(app.redirect);
|
|
55
|
+
const redirect = (0, types_1.parseAppAuthCallback)(app.redirect);
|
|
53
56
|
if (redirect === null)
|
|
54
57
|
return refused('not-app-flow', deps, fallback, undefined);
|
|
55
58
|
const deny = (error) => refused(error, deps, redirect, app.state);
|
|
56
59
|
if (claims.linkIntent !== undefined)
|
|
57
60
|
return deny('link-not-supported');
|
|
58
|
-
if (deps.isProviderDisabled(bridgeProviderAddonId(claims.provider))) {
|
|
61
|
+
if (deps.isProviderDisabled((0, auth_provider_gate_js_1.bridgeProviderAddonId)(claims.provider))) {
|
|
59
62
|
return deny('provider-disabled');
|
|
60
63
|
}
|
|
61
|
-
if (!bridgeIsFirstUseHere(claims, deps))
|
|
64
|
+
if (!(0, sso_finish_js_1.bridgeIsFirstUseHere)(claims, deps))
|
|
62
65
|
return deny('sso-state');
|
|
63
66
|
try {
|
|
64
|
-
const identity = oidcIdentityOf(claims);
|
|
67
|
+
const identity = (0, sso_finish_js_1.oidcIdentityOf)(claims);
|
|
65
68
|
if (identity === null)
|
|
66
69
|
return deny('invalid-bridge');
|
|
67
70
|
const link = await deps.identities.findUser(identity.provider, identity.subject);
|
|
@@ -91,7 +94,7 @@ export async function finishSsoApp(bridge, deps) {
|
|
|
91
94
|
return { kind: 'confirm', ...parked };
|
|
92
95
|
}
|
|
93
96
|
catch (error) {
|
|
94
|
-
if (error instanceof SessionUserGoneError)
|
|
97
|
+
if (error instanceof session_mint_js_1.SessionUserGoneError)
|
|
95
98
|
return deny('user-gone');
|
|
96
99
|
deps.logFailure?.(error);
|
|
97
100
|
return deny('failed');
|
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.sessionUserIdFromCookie = sessionUserIdFromCookie;
|
|
4
|
+
exports.readCookie = readCookie;
|
|
5
|
+
exports.ssoBrowserBinding = ssoBrowserBinding;
|
|
6
|
+
exports.createSsoFinishDeps = createSsoFinishDeps;
|
|
7
|
+
const types_1 = require("@camstack/types");
|
|
2
8
|
/**
|
|
3
9
|
* The live wiring of `finishSsoLogin`'s deps (D777, D782) — kept out of
|
|
4
10
|
* `main.ts` so the route there stays a three-line mapping.
|
|
5
11
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
const node_crypto_1 = require("node:crypto");
|
|
13
|
+
const system_1 = require("@camstack/system");
|
|
14
|
+
const types_2 = require("@camstack/types");
|
|
15
|
+
const auth_provider_gate_js_1 = require("./auth-provider-gate.js");
|
|
16
|
+
const passkey_provider_js_1 = require("./passkey-provider.js");
|
|
17
|
+
const second_factors_js_1 = require("./second-factors.js");
|
|
18
|
+
const session_cookie_js_1 = require("./session-cookie.js");
|
|
13
19
|
/**
|
|
14
20
|
* The user a REAL session cookie names, or `null`. Same rule as
|
|
15
21
|
* `auth.exchangeSession`: a bridge or challenge token verifies under the same
|
|
16
22
|
* secret but carries a `kind`, and a session always has a boolean `isAdmin`
|
|
17
23
|
* and a string `userId`.
|
|
18
24
|
*/
|
|
19
|
-
|
|
20
|
-
const token = readSessionCookieFromHeader(cookieHeader);
|
|
25
|
+
function sessionUserIdFromCookie(auth, cookieHeader) {
|
|
26
|
+
const token = (0, session_cookie_js_1.readSessionCookieFromHeader)(cookieHeader);
|
|
21
27
|
if (token === null)
|
|
22
28
|
return null;
|
|
23
29
|
try {
|
|
@@ -33,7 +39,7 @@ export function sessionUserIdFromCookie(auth, cookieHeader) {
|
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
/** The value of one cookie in a raw `Cookie` header, or `null`. */
|
|
36
|
-
|
|
42
|
+
function readCookie(header, name) {
|
|
37
43
|
if (header === undefined)
|
|
38
44
|
return null;
|
|
39
45
|
for (const pair of header.split(';')) {
|
|
@@ -48,22 +54,22 @@ export function readCookie(header, name) {
|
|
|
48
54
|
return null;
|
|
49
55
|
}
|
|
50
56
|
/** SHA-256 (hex) of the request's SSO state cookie, or `null` without one. */
|
|
51
|
-
|
|
52
|
-
const value = readCookie(cookieHeader, SSO_STATE_COOKIE);
|
|
53
|
-
return value === null ? null : createHash('sha256').update(value).digest('hex');
|
|
57
|
+
function ssoBrowserBinding(cookieHeader) {
|
|
58
|
+
const value = readCookie(cookieHeader, types_2.SSO_STATE_COOKIE);
|
|
59
|
+
return value === null ? null : (0, node_crypto_1.createHash)('sha256').update(value).digest('hex');
|
|
54
60
|
}
|
|
55
|
-
|
|
61
|
+
function createSsoFinishDeps(wiring, cookieHeader) {
|
|
56
62
|
const { auth, registry, moleculer } = wiring;
|
|
57
63
|
const userManagement = () => {
|
|
58
64
|
const um = registry.getSingleton('user-management');
|
|
59
65
|
if (!um)
|
|
60
|
-
throw userError('server.login-unavailable', undefined, 'Login unavailable — `user-management` capability not registered');
|
|
66
|
+
throw (0, types_1.userError)('server.login-unavailable', undefined, 'Login unavailable — `user-management` capability not registered');
|
|
61
67
|
return um;
|
|
62
68
|
};
|
|
63
69
|
return {
|
|
64
70
|
verifyBridge: (token) => auth.verifySsoBridgeToken(token),
|
|
65
71
|
minter: wiring.minter,
|
|
66
|
-
isProviderDisabled: (addonId) => isAuthAddonDisabled(registry, addonId),
|
|
72
|
+
isProviderDisabled: (addonId) => (0, auth_provider_gate_js_1.isAuthAddonDisabled)(registry, addonId),
|
|
67
73
|
identities: {
|
|
68
74
|
findUser: async (provider, subject) => userManagement().findUserByExternalIdentity({ provider, subject }),
|
|
69
75
|
link: async (input) => {
|
|
@@ -76,7 +82,7 @@ export function createSsoFinishDeps(wiring, cookieHeader) {
|
|
|
76
82
|
return 'conflict';
|
|
77
83
|
// Hub-internal: creating a link is on no wire (not tRPC, not the
|
|
78
84
|
// mesh, not ctx.api) — only this in-process caller reaches it.
|
|
79
|
-
const internal = getUserManagementInternal(um);
|
|
85
|
+
const internal = (0, system_1.getUserManagementInternal)(um);
|
|
80
86
|
if (internal === null)
|
|
81
87
|
throw new Error('External sign-in linking not available');
|
|
82
88
|
await internal.linkExternalIdentity(input);
|
|
@@ -92,7 +98,7 @@ export function createSsoFinishDeps(wiring, cookieHeader) {
|
|
|
92
98
|
? {
|
|
93
99
|
trustedNetworkLogin: wiring.trustedNetworkLogin,
|
|
94
100
|
auditSkip: async (userId, factors) => {
|
|
95
|
-
const internal = getUserManagementInternal(registry.getSingleton('user-management'));
|
|
101
|
+
const internal = (0, system_1.getUserManagementInternal)(registry.getSingleton('user-management'));
|
|
96
102
|
if (internal === null)
|
|
97
103
|
throw new Error('auth audit unavailable');
|
|
98
104
|
const ip = wiring.sessionIssue?.().ip;
|
|
@@ -108,11 +114,11 @@ export function createSsoFinishDeps(wiring, cookieHeader) {
|
|
|
108
114
|
sessionUserId: () => sessionUserIdFromCookie(auth, cookieHeader),
|
|
109
115
|
secondFactors: (userId) => {
|
|
110
116
|
const um = registry.getSingleton('user-management');
|
|
111
|
-
return collectSecondFactors({
|
|
117
|
+
return (0, second_factors_js_1.collectSecondFactors)({
|
|
112
118
|
...(um && typeof um.getTotpStatus === 'function'
|
|
113
119
|
? { getTotpStatus: (input) => um.getTotpStatus(input) }
|
|
114
120
|
: {}),
|
|
115
|
-
passkeyProvider: () => resolvePasskeyProvider(registry, moleculer),
|
|
121
|
+
passkeyProvider: () => (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer),
|
|
116
122
|
}, userId, 'sso');
|
|
117
123
|
},
|
|
118
124
|
signChallenge: (user) => auth.signTotpChallengeToken(user),
|
package/dist/auth/sso-finish.js
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SSO_POPUP_COMPLETE_PATH = exports.SSO_LOGIN_PATH = exports.SSO_PROFILE_PATH = exports.OIDC_IDENTITY_PREFIX = exports.OIDC_BRIDGE_PROVIDER_PREFIX = void 0;
|
|
4
|
+
exports.popupCompletionLocation = popupCompletionLocation;
|
|
5
|
+
exports.oidcIdentityOf = oidcIdentityOf;
|
|
6
|
+
exports.isLoginBridge = isLoginBridge;
|
|
7
|
+
exports.appCallbackLocation = appCallbackLocation;
|
|
8
|
+
exports.sessionFragmentParams = sessionFragmentParams;
|
|
9
|
+
exports.finishSsoLogin = finishSsoLogin;
|
|
10
|
+
exports.bridgeIsFirstUseHere = bridgeIsFirstUseHere;
|
|
1
11
|
/**
|
|
2
12
|
* `/api/auth/sso/finish` — swaps a verified login bridge for a session (D712),
|
|
3
13
|
* or completes an explicit OIDC link (D782).
|
|
@@ -35,10 +45,10 @@
|
|
|
35
45
|
*
|
|
36
46
|
* Pure: the Fastify route in `main.ts` wires the deps and maps the outcome.
|
|
37
47
|
*/
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
48
|
+
const node_crypto_1 = require("node:crypto");
|
|
49
|
+
const types_1 = require("@camstack/types");
|
|
50
|
+
const auth_provider_gate_js_1 = require("./auth-provider-gate.js");
|
|
51
|
+
const session_mint_js_1 = require("./session-mint.js");
|
|
42
52
|
/**
|
|
43
53
|
* `auth-oidc` signs `auth-oidc/<instance>`.
|
|
44
54
|
*
|
|
@@ -50,25 +60,25 @@ import { SessionUserGoneError, } from './session-mint.js';
|
|
|
50
60
|
* non-OIDC provider fails closed until it has its own bridge format. (The
|
|
51
61
|
* magic-link bridge that named a user record directly is gone with its addon.)
|
|
52
62
|
*/
|
|
53
|
-
|
|
63
|
+
exports.OIDC_BRIDGE_PROVIDER_PREFIX = 'auth-oidc/';
|
|
54
64
|
/** `auth-oidc` names an identity `oidc:<instance>:<sub>`. */
|
|
55
|
-
|
|
65
|
+
exports.OIDC_IDENTITY_PREFIX = 'oidc:';
|
|
56
66
|
/**
|
|
57
67
|
* Where a completed (or refused) link lands — the signed-in user's profile —
|
|
58
68
|
* and where a login returns. Admin-ui routes, relative to its mount: the
|
|
59
69
|
* route in `main.ts` prepends the hub's mount prefix. (These read `/admin/…`
|
|
60
70
|
* once, a path admin-ui has no route for, so both returns drew a blank page.)
|
|
61
71
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const PROFILE_PATH = SSO_PROFILE_PATH;
|
|
65
|
-
const LOGIN_PATH = SSO_LOGIN_PATH;
|
|
72
|
+
exports.SSO_PROFILE_PATH = '/system/my-access';
|
|
73
|
+
exports.SSO_LOGIN_PATH = '/login';
|
|
74
|
+
const PROFILE_PATH = exports.SSO_PROFILE_PATH;
|
|
75
|
+
const LOGIN_PATH = exports.SSO_LOGIN_PATH;
|
|
66
76
|
/**
|
|
67
77
|
* The admin-ui page a POPUP sign-in lands on (D791): it hands the outcome to
|
|
68
78
|
* the window that opened it and closes, or — opener gone — continues to the
|
|
69
79
|
* page the outcome names, like a full-page return.
|
|
70
80
|
*/
|
|
71
|
-
|
|
81
|
+
exports.SSO_POPUP_COMPLETE_PATH = '/sso-complete';
|
|
72
82
|
/**
|
|
73
83
|
* The popup form of a return `location`: the completion page, with what the
|
|
74
84
|
* page return carried — the login FRAGMENT (session / challenge / error) or
|
|
@@ -77,39 +87,39 @@ export const SSO_POPUP_COMPLETE_PATH = '/sso-complete';
|
|
|
77
87
|
* never reaches a server log, and the completion page never posts it to
|
|
78
88
|
* another origin.
|
|
79
89
|
*/
|
|
80
|
-
|
|
90
|
+
function popupCompletionLocation(location) {
|
|
81
91
|
const hashAt = location.indexOf('#');
|
|
82
92
|
const pathAndQuery = hashAt === -1 ? location : location.slice(0, hashAt);
|
|
83
93
|
const fragment = hashAt === -1 ? '' : location.slice(hashAt + 1);
|
|
84
94
|
const queryAt = pathAndQuery.indexOf('?');
|
|
85
95
|
const path = queryAt === -1 ? pathAndQuery : pathAndQuery.slice(0, queryAt);
|
|
86
96
|
const query = queryAt === -1 ? '' : pathAndQuery.slice(queryAt + 1);
|
|
87
|
-
const target = path === SSO_PROFILE_PATH ? 'profile' : 'login';
|
|
97
|
+
const target = path === exports.SSO_PROFILE_PATH ? 'profile' : 'login';
|
|
88
98
|
const carried = [query, fragment].filter((part) => part.length > 0).join('&');
|
|
89
|
-
return `${SSO_POPUP_COMPLETE_PATH}#return=${target}${carried.length > 0 ? `&${carried}` : ''}`;
|
|
99
|
+
return `${exports.SSO_POPUP_COMPLETE_PATH}#return=${target}${carried.length > 0 ? `&${carried}` : ''}`;
|
|
90
100
|
}
|
|
91
101
|
/**
|
|
92
102
|
* `(provider, subject, issuer)` of an OIDC bridge, or `null` when it is not a
|
|
93
103
|
* well-formed one. A subject is unique only per issuer, so a bridge without
|
|
94
104
|
* the verified `iss` names no identity.
|
|
95
105
|
*/
|
|
96
|
-
|
|
97
|
-
if (!claims.provider.startsWith(OIDC_BRIDGE_PROVIDER_PREFIX))
|
|
106
|
+
function oidcIdentityOf(claims) {
|
|
107
|
+
if (!claims.provider.startsWith(exports.OIDC_BRIDGE_PROVIDER_PREFIX))
|
|
98
108
|
return null;
|
|
99
109
|
if (claims.issuer === undefined || claims.issuer.length === 0)
|
|
100
110
|
return null;
|
|
101
|
-
const instance = claims.provider.slice(OIDC_BRIDGE_PROVIDER_PREFIX.length);
|
|
111
|
+
const instance = claims.provider.slice(exports.OIDC_BRIDGE_PROVIDER_PREFIX.length);
|
|
102
112
|
if (instance.length === 0)
|
|
103
113
|
return null;
|
|
104
|
-
const prefix = `${OIDC_IDENTITY_PREFIX}${instance}:`;
|
|
114
|
+
const prefix = `${exports.OIDC_IDENTITY_PREFIX}${instance}:`;
|
|
105
115
|
if (!claims.userId.startsWith(prefix))
|
|
106
116
|
return null;
|
|
107
117
|
const subject = claims.userId.slice(prefix.length);
|
|
108
118
|
return subject.length === 0 ? null : { provider: claims.provider, subject, issuer: claims.issuer };
|
|
109
119
|
}
|
|
110
120
|
/** Whether `claims` is a LOGIN bridge — the only kind this endpoint swaps. */
|
|
111
|
-
|
|
112
|
-
return claims.provider.startsWith(OIDC_BRIDGE_PROVIDER_PREFIX);
|
|
121
|
+
function isLoginBridge(claims) {
|
|
122
|
+
return claims.provider.startsWith(exports.OIDC_BRIDGE_PROVIDER_PREFIX);
|
|
113
123
|
}
|
|
114
124
|
function unauthorized(error) {
|
|
115
125
|
return { kind: 'error', status: 401, body: { error } };
|
|
@@ -121,11 +131,11 @@ function linkRefused(reason) {
|
|
|
121
131
|
return redirect(`${PROFILE_PATH}?linkError=${reason}`);
|
|
122
132
|
}
|
|
123
133
|
/** The app's callback with one query parameter — `link=<code>` or `linkError=<reason>`. */
|
|
124
|
-
|
|
134
|
+
function appCallbackLocation(returnTo, key, value) {
|
|
125
135
|
return `${returnTo}?${key}=${encodeURIComponent(value)}`;
|
|
126
136
|
}
|
|
127
137
|
function failed(error, deps) {
|
|
128
|
-
if (error instanceof SessionUserGoneError)
|
|
138
|
+
if (error instanceof session_mint_js_1.SessionUserGoneError)
|
|
129
139
|
return unauthorized('User no longer exists');
|
|
130
140
|
// The detail stays in the server log: a store error can name user ids.
|
|
131
141
|
deps.logFailure?.(error);
|
|
@@ -136,7 +146,7 @@ function failed(error, deps) {
|
|
|
136
146
|
* admin-ui is a refreshing client — the refresh token and both expiries. A
|
|
137
147
|
* fragment never reaches a server log or a Referer.
|
|
138
148
|
*/
|
|
139
|
-
|
|
149
|
+
function sessionFragmentParams(session) {
|
|
140
150
|
return {
|
|
141
151
|
token: session.token,
|
|
142
152
|
...(session.refreshToken !== undefined ? { refreshToken: session.refreshToken } : {}),
|
|
@@ -242,12 +252,12 @@ async function completeLogin(claims, deps) {
|
|
|
242
252
|
}
|
|
243
253
|
return signIn(await deps.minter.findUser(link.userId), claims.provider, deps);
|
|
244
254
|
}
|
|
245
|
-
|
|
255
|
+
async function finishSsoLogin(bridge, deps, options = {}) {
|
|
246
256
|
const outcome = await finishSsoReturn(bridge, deps);
|
|
247
257
|
if (options.popup !== true || outcome.kind !== 'redirect')
|
|
248
258
|
return outcome;
|
|
249
259
|
// A native return goes to the app's scheme, never to a popup page.
|
|
250
|
-
if (hasUrlScheme(outcome.location))
|
|
260
|
+
if ((0, types_1.hasUrlScheme)(outcome.location))
|
|
251
261
|
return outcome;
|
|
252
262
|
return redirect(popupCompletionLocation(outcome.location));
|
|
253
263
|
}
|
|
@@ -255,7 +265,7 @@ export async function finishSsoLogin(bridge, deps, options = {}) {
|
|
|
255
265
|
function sameDigest(a, b) {
|
|
256
266
|
const left = Buffer.from(a, 'utf8');
|
|
257
267
|
const right = Buffer.from(b, 'utf8');
|
|
258
|
-
return left.length === right.length && timingSafeEqual(left, right);
|
|
268
|
+
return left.length === right.length && (0, node_crypto_1.timingSafeEqual)(left, right);
|
|
259
269
|
}
|
|
260
270
|
/**
|
|
261
271
|
* Is this the FIRST presentation of the bridge, in the browser that started
|
|
@@ -263,7 +273,7 @@ function sameDigest(a, b) {
|
|
|
263
273
|
* presented from a browser without the cookie is refused without being burned
|
|
264
274
|
* — the real browser can still finish.
|
|
265
275
|
*/
|
|
266
|
-
|
|
276
|
+
function bridgeIsFirstUseHere(claims, deps) {
|
|
267
277
|
if (claims.jti === undefined || claims.browserBinding === undefined)
|
|
268
278
|
return false;
|
|
269
279
|
const presented = deps.browserBinding();
|
|
@@ -283,7 +293,7 @@ async function finishSsoReturn(bridge, deps) {
|
|
|
283
293
|
// which hands the app a code; it must never become a web session here.
|
|
284
294
|
if (claims.app !== undefined)
|
|
285
295
|
return unauthorized('Not a web login bridge token');
|
|
286
|
-
if (deps.isProviderDisabled(bridgeProviderAddonId(claims.provider))) {
|
|
296
|
+
if (deps.isProviderDisabled((0, auth_provider_gate_js_1.bridgeProviderAddonId)(claims.provider))) {
|
|
287
297
|
return unauthorized('Login provider is disabled');
|
|
288
298
|
}
|
|
289
299
|
if (!bridgeIsFirstUseHere(claims, deps)) {
|
package/dist/auth/sso-routes.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerSsoRoutes = registerSsoRoutes;
|
|
1
4
|
/**
|
|
2
5
|
* The two browser-facing SSO routes, kept out of `main.ts`:
|
|
3
6
|
*
|
|
@@ -11,14 +14,14 @@
|
|
|
11
14
|
* - `GET /api/auth/browser-handoff?code=…` — a one-time code from
|
|
12
15
|
* `auth.createBrowserHandoff` opens the account page signed in (D801).
|
|
13
16
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
const types_1 = require("@camstack/types");
|
|
18
|
+
const spa_mount_js_1 = require("../api/static/spa-mount.js");
|
|
19
|
+
const auth_rate_limit_js_1 = require("./auth-rate-limit.js");
|
|
20
|
+
const native_return_js_1 = require("./native-return.js");
|
|
21
|
+
const sso_finish_js_1 = require("./sso-finish.js");
|
|
22
|
+
const app_confirm_routes_js_1 = require("./app-confirm-routes.js");
|
|
23
|
+
const sso_finish_app_js_1 = require("./sso-finish-app.js");
|
|
24
|
+
const sso_finish_deps_js_1 = require("./sso-finish-deps.js");
|
|
22
25
|
/** A User-Agent as a session's client label. */
|
|
23
26
|
function clientOf(ua) {
|
|
24
27
|
const value = Array.isArray(ua) ? ua[0] : ua;
|
|
@@ -26,11 +29,11 @@ function clientOf(ua) {
|
|
|
26
29
|
}
|
|
27
30
|
/** Expire the state cookie (both Secure variants are cleared by name + path). */
|
|
28
31
|
function clearSsoStateCookie() {
|
|
29
|
-
return `${SSO_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
|
|
32
|
+
return `${types_1.SSO_STATE_COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`;
|
|
30
33
|
}
|
|
31
|
-
|
|
34
|
+
function registerSsoRoutes(fastify, deps) {
|
|
32
35
|
fastify.get('/api/auth/sso/finish', async (request, reply) => {
|
|
33
|
-
const client = clientKeyFromRequest(request, deps.network);
|
|
36
|
+
const client = (0, auth_rate_limit_js_1.clientKeyFromRequest)(request, deps.network);
|
|
34
37
|
if (client !== null) {
|
|
35
38
|
const verdict = deps.limiter.check(`sso-finish:${client}`);
|
|
36
39
|
if (!verdict.allowed) {
|
|
@@ -38,7 +41,7 @@ export function registerSsoRoutes(fastify, deps) {
|
|
|
38
41
|
return reply.status(429).send({ error: 'Too many attempts' });
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
|
-
const outcome = await finishSsoLogin(request.query.bridge, createSsoFinishDeps({
|
|
44
|
+
const outcome = await (0, sso_finish_js_1.finishSsoLogin)(request.query.bridge, (0, sso_finish_deps_js_1.createSsoFinishDeps)({
|
|
42
45
|
...deps.wiring,
|
|
43
46
|
sessionIssue: () => {
|
|
44
47
|
const ip = deps.network.clientAddress(request).ip;
|
|
@@ -59,8 +62,8 @@ export function registerSsoRoutes(fastify, deps) {
|
|
|
59
62
|
reply.code(302);
|
|
60
63
|
// Admin-ui paths are relative to the hub's mount (HA ingress etc.); a
|
|
61
64
|
// native app return (`camstack://…`, D801) is not a hub path at all.
|
|
62
|
-
const mount = parseForwardedPrefix(request.headers['x-forwarded-prefix']) ?? '';
|
|
63
|
-
reply.header('Location', ssoReturnLocation(mount, outcome.location));
|
|
65
|
+
const mount = (0, spa_mount_js_1.parseForwardedPrefix)(request.headers['x-forwarded-prefix']) ?? '';
|
|
66
|
+
reply.header('Location', (0, native_return_js_1.ssoReturnLocation)(mount, outcome.location));
|
|
64
67
|
return reply.send('');
|
|
65
68
|
});
|
|
66
69
|
// The native-app leg (D858): same bridge rules, a handoff code instead of a
|
|
@@ -70,7 +73,7 @@ export function registerSsoRoutes(fastify, deps) {
|
|
|
70
73
|
reply.header('Cache-Control', 'no-store');
|
|
71
74
|
const clearState = clearSsoStateCookie();
|
|
72
75
|
reply.header('Set-Cookie', clearState);
|
|
73
|
-
const client = clientKeyFromRequest(request, deps.network);
|
|
76
|
+
const client = (0, auth_rate_limit_js_1.clientKeyFromRequest)(request, deps.network);
|
|
74
77
|
if (client !== null) {
|
|
75
78
|
const verdict = deps.limiter.check(`sso-finish:${client}`);
|
|
76
79
|
if (!verdict.allowed) {
|
|
@@ -78,8 +81,8 @@ export function registerSsoRoutes(fastify, deps) {
|
|
|
78
81
|
return reply.status(429).send({ error: 'Too many attempts' });
|
|
79
82
|
}
|
|
80
83
|
}
|
|
81
|
-
const outcome = await finishSsoApp(request.query.bridge, {
|
|
82
|
-
...createSsoFinishDeps({
|
|
84
|
+
const outcome = await (0, sso_finish_app_js_1.finishSsoApp)(request.query.bridge, {
|
|
85
|
+
...(0, sso_finish_deps_js_1.createSsoFinishDeps)({
|
|
83
86
|
...deps.wiring,
|
|
84
87
|
logFailure: (error) => deps.logger.error('SSO app finish failed', {
|
|
85
88
|
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
@@ -96,19 +99,19 @@ export function registerSsoRoutes(fastify, deps) {
|
|
|
96
99
|
}
|
|
97
100
|
// The confirmation page, on this hub (mount-aware); its cookie binds the
|
|
98
101
|
// token to this browser. The SSO state cookie is spent either way.
|
|
99
|
-
const mount = parseForwardedPrefix(request.headers['x-forwarded-prefix']) ?? '';
|
|
102
|
+
const mount = (0, spa_mount_js_1.parseForwardedPrefix)(request.headers['x-forwarded-prefix']) ?? '';
|
|
100
103
|
reply.header('Set-Cookie', [
|
|
101
104
|
clearState,
|
|
102
|
-
appConfirmCookie(outcome.cookie, request.protocol === 'https'),
|
|
105
|
+
(0, app_confirm_routes_js_1.appConfirmCookie)(outcome.cookie, request.protocol === 'https'),
|
|
103
106
|
]);
|
|
104
|
-
reply.header('Location', `${mount}${APP_CONFIRM_PATH}?${APP_CONFIRM_PARAM}=${encodeURIComponent(outcome.token)}`);
|
|
107
|
+
reply.header('Location', `${mount}${app_confirm_routes_js_1.APP_CONFIRM_PATH}?${app_confirm_routes_js_1.APP_CONFIRM_PARAM}=${encodeURIComponent(outcome.token)}`);
|
|
105
108
|
return reply.send('');
|
|
106
109
|
});
|
|
107
110
|
// A one-time code minted by `auth.createBrowserHandoff` opens the account
|
|
108
111
|
// page signed in (D801): the session rides the URL FRAGMENT (never a server
|
|
109
112
|
// log), and the only destination is the account page.
|
|
110
113
|
fastify.get('/api/auth/browser-handoff', async (request, reply) => {
|
|
111
|
-
const mount = parseForwardedPrefix(request.headers['x-forwarded-prefix']) ?? '';
|
|
114
|
+
const mount = (0, spa_mount_js_1.parseForwardedPrefix)(request.headers['x-forwarded-prefix']) ?? '';
|
|
112
115
|
const grant = typeof request.query.code === 'string'
|
|
113
116
|
? deps.browserHandoffCodes.redeem(request.query.code)
|
|
114
117
|
: null;
|
|
@@ -133,7 +136,7 @@ export function registerSsoRoutes(fastify, deps) {
|
|
|
133
136
|
}
|
|
134
137
|
reply.code(302);
|
|
135
138
|
reply.header('Referrer-Policy', 'no-referrer');
|
|
136
|
-
reply.header('Location', browserHandoffLocation(mount, session));
|
|
139
|
+
reply.header('Location', (0, native_return_js_1.browserHandoffLocation)(mount, session));
|
|
137
140
|
return reply.send('');
|
|
138
141
|
});
|
|
139
142
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UsedBridgeIds = void 0;
|
|
1
4
|
/**
|
|
2
5
|
* The `jti`s of login bridges already swapped for a session or a link.
|
|
3
6
|
*
|
|
@@ -12,7 +15,7 @@
|
|
|
12
15
|
*/
|
|
13
16
|
const RETENTION_MS = 10 * 60_000;
|
|
14
17
|
const DEFAULT_MAX_ENTRIES = 10_000;
|
|
15
|
-
|
|
18
|
+
class UsedBridgeIds {
|
|
16
19
|
used = new Map();
|
|
17
20
|
now;
|
|
18
21
|
maxEntries;
|
|
@@ -46,3 +49,4 @@ export class UsedBridgeIds {
|
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
}
|
|
52
|
+
exports.UsedBridgeIds = UsedBridgeIds;
|
package/dist/boot/boot-config.js
CHANGED
|
@@ -1,14 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Phase 1: Bootstrap config loading and infrastructure setup.
|
|
3
4
|
*
|
|
4
5
|
* Extracted from main.ts — pure extraction, no behavior change.
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
19
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
20
|
+
}) : function(o, v) {
|
|
21
|
+
o["default"] = v;
|
|
22
|
+
});
|
|
23
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
24
|
+
var ownKeys = function(o) {
|
|
25
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
26
|
+
var ar = [];
|
|
27
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
28
|
+
return ar;
|
|
29
|
+
};
|
|
30
|
+
return ownKeys(o);
|
|
31
|
+
};
|
|
32
|
+
return function (mod) {
|
|
33
|
+
if (mod && mod.__esModule) return mod;
|
|
34
|
+
var result = {};
|
|
35
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
36
|
+
__setModuleDefault(result, mod);
|
|
37
|
+
return result;
|
|
38
|
+
};
|
|
39
|
+
})();
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.ignoredTlsCertSources = ignoredTlsCertSources;
|
|
42
|
+
exports.retiredSecretSources = retiredSecretSources;
|
|
43
|
+
exports.loadBootstrapConfig = loadBootstrapConfig;
|
|
44
|
+
exports.setupInfra = setupInfra;
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const types_1 = require("@camstack/types");
|
|
48
|
+
const yaml = __importStar(require("js-yaml"));
|
|
49
|
+
const config_schema_1 = require("../core/config/config.schema");
|
|
50
|
+
const storage_location_manager_1 = require("../core/storage/storage-location-manager");
|
|
12
51
|
// ---------------------------------------------------------------------------
|
|
13
52
|
// Constants
|
|
14
53
|
// ---------------------------------------------------------------------------
|
|
@@ -61,7 +100,7 @@ function setNested(obj, p, value) {
|
|
|
61
100
|
return obj;
|
|
62
101
|
if (rest.length === 0)
|
|
63
102
|
return { ...obj, [head]: value };
|
|
64
|
-
const child = asJsonObject(obj[head]) ?? {};
|
|
103
|
+
const child = (0, types_1.asJsonObject)(obj[head]) ?? {};
|
|
65
104
|
return { ...obj, [head]: setNested(child, rest.join('.'), value) };
|
|
66
105
|
}
|
|
67
106
|
/**
|
|
@@ -69,12 +108,12 @@ function setNested(obj, p, value) {
|
|
|
69
108
|
* certificate and is now ignored (D726). Blank env values count as unset,
|
|
70
109
|
* exactly as the override loop treats them.
|
|
71
110
|
*/
|
|
72
|
-
|
|
111
|
+
function ignoredTlsCertSources(env, raw) {
|
|
73
112
|
const fromEnv = IGNORED_TLS_CERT_ENV.filter((name) => {
|
|
74
113
|
const value = env[name];
|
|
75
114
|
return value !== undefined && value !== '';
|
|
76
115
|
});
|
|
77
|
-
const tls = asJsonObject(raw['tls']) ?? {};
|
|
116
|
+
const tls = (0, types_1.asJsonObject)(raw['tls']) ?? {};
|
|
78
117
|
const fromYaml = IGNORED_TLS_CERT_KEYS.filter((key) => tls[key] !== undefined).map((key) => `tls.${key}`);
|
|
79
118
|
return [...fromEnv, ...fromYaml];
|
|
80
119
|
}
|
|
@@ -82,12 +121,12 @@ export function ignoredTlsCertSources(env, raw) {
|
|
|
82
121
|
* Every retired secret source still present: env variables set (non-blank) and
|
|
83
122
|
* `config.yaml` `auth.*` keys. Names only — a value is never read into a log.
|
|
84
123
|
*/
|
|
85
|
-
|
|
124
|
+
function retiredSecretSources(env, raw) {
|
|
86
125
|
const fromEnv = RETIRED_SECRET_ENV.filter((name) => {
|
|
87
126
|
const value = env[name];
|
|
88
127
|
return value !== undefined && value !== '';
|
|
89
128
|
});
|
|
90
|
-
const auth = asJsonObject(raw['auth']) ?? {};
|
|
129
|
+
const auth = (0, types_1.asJsonObject)(raw['auth']) ?? {};
|
|
91
130
|
const fromYaml = RETIRED_AUTH_KEYS.filter((key) => auth[key] !== undefined && auth[key] !== null).map((key) => `auth.${key}`);
|
|
92
131
|
return [...fromEnv, ...fromYaml];
|
|
93
132
|
}
|
|
@@ -98,13 +137,13 @@ export function retiredSecretSources(env, raw) {
|
|
|
98
137
|
* Load bootstrap config from a YAML file, apply env-var overrides, and
|
|
99
138
|
* validate via the bootstrap Zod schema.
|
|
100
139
|
*/
|
|
101
|
-
|
|
140
|
+
function loadBootstrapConfig(configPath) {
|
|
102
141
|
// Only bootstrap sections live in config.yaml.
|
|
103
142
|
// All runtime settings are stored in the SQL system_settings table.
|
|
104
143
|
let raw;
|
|
105
144
|
if (fs.existsSync(configPath)) {
|
|
106
145
|
const content = fs.readFileSync(configPath, 'utf-8');
|
|
107
|
-
raw = asJsonObject(yaml.load(content)) ?? {};
|
|
146
|
+
raw = (0, types_1.asJsonObject)(yaml.load(content)) ?? {};
|
|
108
147
|
// Merge in any missing bootstrap sections (server, auth only)
|
|
109
148
|
let updated = false;
|
|
110
149
|
for (const [key, defaults] of Object.entries(CONFIG_DEFAULTS)) {
|
|
@@ -166,7 +205,7 @@ export function loadBootstrapConfig(configPath) {
|
|
|
166
205
|
console.warn(`[Phase1] WARN ${ignored.join(', ')} ignored — the certificate is set only in the admin UI. ` +
|
|
167
206
|
'Upload the certificate in Network → Local access (D726).');
|
|
168
207
|
}
|
|
169
|
-
return bootstrapSchema.parse(raw);
|
|
208
|
+
return config_schema_1.bootstrapSchema.parse(raw);
|
|
170
209
|
}
|
|
171
210
|
// ---------------------------------------------------------------------------
|
|
172
211
|
// setupInfra
|
|
@@ -175,7 +214,7 @@ export function loadBootstrapConfig(configPath) {
|
|
|
175
214
|
* Phase 2: Create StorageLocationManager, ensure directories, configure TLS.
|
|
176
215
|
* Returns the full InfraContext needed by subsequent boot phases.
|
|
177
216
|
*/
|
|
178
|
-
|
|
217
|
+
async function setupInfra(_configPath, bootstrapConfig) {
|
|
179
218
|
// No secret is generated here: the session signing key is the keychain's
|
|
180
219
|
// (local-auth loads or creates it once the keychain is up — D797).
|
|
181
220
|
const config = bootstrapConfig;
|
|
@@ -185,7 +224,7 @@ export async function setupInfra(_configPath, bootstrapConfig) {
|
|
|
185
224
|
console.log(`[Phase1] Bootstrap: port=${port}, host=${host}, dataPath=${dataPath}`);
|
|
186
225
|
// --- Phase 2: Init StorageLocationManager → ensure all dirs exist ---
|
|
187
226
|
console.log('[Phase2] Initializing storage locations…');
|
|
188
|
-
const locationManager = new StorageLocationManager(dataPath);
|
|
227
|
+
const locationManager = new storage_location_manager_1.StorageLocationManager(dataPath);
|
|
189
228
|
await locationManager.initializeDefaults();
|
|
190
229
|
const locationStatus = locationManager.getStatus();
|
|
191
230
|
for (const { name, available, path: locPath } of locationStatus) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* The hub's `onModuleInit` order, as one named, testable sequence.
|
|
3
4
|
*
|
|
@@ -14,8 +15,10 @@
|
|
|
14
15
|
* 4. AddonRegistry — boots EVERY addon. Minutes of work on a real hub.
|
|
15
16
|
* 5. …post-boot reconciles.
|
|
16
17
|
*/
|
|
18
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
+
exports.runBootInitSequence = runBootInitSequence;
|
|
17
20
|
/** Run the boot init steps in dependency order. */
|
|
18
|
-
|
|
21
|
+
async function runBootInitSequence(sequence) {
|
|
19
22
|
await sequence.moleculer();
|
|
20
23
|
await sequence.addonBridge();
|
|
21
24
|
await sequence.agentRegistry();
|