@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,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* Auth router — core API for login/logout/me.
|
|
3
4
|
*
|
|
@@ -13,40 +14,43 @@
|
|
|
13
14
|
* collection — the single, generic mechanism every auth addon contributes
|
|
14
15
|
* to (superseding the removed `auth.listProviders`).
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.EXCHANGE_SESSION_HEADER = exports.BROWSER_HANDOFF_PATH = void 0;
|
|
19
|
+
exports.createAuthRouter = createAuthRouter;
|
|
20
|
+
const types_1 = require("@camstack/types");
|
|
21
|
+
const server_1 = require("@trpc/server");
|
|
22
|
+
const zod_1 = require("zod");
|
|
23
|
+
const auth_network_policy_js_1 = require("../../auth/auth-network-policy.js");
|
|
24
|
+
const app_passkey_routes_js_1 = require("../../auth/app-passkey-routes.js");
|
|
25
|
+
const auth_rate_limit_js_1 = require("../../auth/auth-rate-limit.js");
|
|
26
|
+
const auth_provider_gate_js_1 = require("../../auth/auth-provider-gate.js");
|
|
27
|
+
const device_enroll_proofs_js_1 = require("../../auth/device-enroll-proofs.js");
|
|
28
|
+
const external_link_intents_js_1 = require("../../auth/external-link-intents.js");
|
|
29
|
+
const passkey_provider_js_1 = require("../../auth/passkey-provider.js");
|
|
30
|
+
const second_factors_js_1 = require("../../auth/second-factors.js");
|
|
31
|
+
const session_cookie_js_1 = require("../../auth/session-cookie.js");
|
|
32
|
+
const hub_sessions_js_1 = require("../../auth/hub-sessions.js");
|
|
33
|
+
const session_mint_js_1 = require("../../auth/session-mint.js");
|
|
34
|
+
const handoff_code_service_js_1 = require("../../core/auth/handoff-code.service.js");
|
|
35
|
+
const share_token_service_js_1 = require("../../core/auth/share-token.service.js");
|
|
36
|
+
const principal_visibility_js_1 = require("../trpc/principal-visibility.js");
|
|
37
|
+
const trpc_middleware_js_1 = require("../trpc/trpc.middleware.js");
|
|
38
|
+
const auth_limits_js_1 = require("./auth-limits.js");
|
|
39
|
+
const auth_admin_tokens_procedures_js_1 = require("./auth-admin-tokens.procedures.js");
|
|
40
|
+
const auth_revoke_credentials_procedures_js_1 = require("./auth-revoke-credentials.procedures.js");
|
|
41
|
+
const auth_reauth_procedures_js_1 = require("./auth-reauth.procedures.js");
|
|
42
|
+
const auth_device_cert_procedures_js_1 = require("./auth-device-cert.procedures.js");
|
|
43
|
+
const auth_sessions_procedures_js_1 = require("./auth-sessions.procedures.js");
|
|
44
|
+
const server_name_js_1 = require("./server-name.js");
|
|
45
|
+
const types_2 = require("@camstack/types");
|
|
46
|
+
const user_error_js_1 = require("../trpc/user-error.js");
|
|
43
47
|
/**
|
|
44
48
|
* A public procedure limited per (procedure, REAL client address) — see
|
|
45
49
|
* `auth-limits.ts` for the tiers and why the address is the forwarded client.
|
|
46
50
|
*/
|
|
47
51
|
function makeRateLimitedProcedure(limiter, network) {
|
|
48
|
-
return publicProcedure.use(({ ctx, path, next }) => {
|
|
49
|
-
limitByClient(limiter, path, ctx.req, network);
|
|
52
|
+
return trpc_middleware_js_1.publicProcedure.use(({ ctx, path, next }) => {
|
|
53
|
+
(0, auth_limits_js_1.limitByClient)(limiter, path, ctx.req, network);
|
|
50
54
|
return next({ ctx });
|
|
51
55
|
});
|
|
52
56
|
}
|
|
@@ -55,7 +59,7 @@ const STEP_UP_FRESH_MS = 120_000;
|
|
|
55
59
|
/** Login methods that count as an authentication (a handoff / exchange / certificate session does not). */
|
|
56
60
|
const STEP_UP_LOGIN_METHODS = ['password', 'passkey', 'sso'];
|
|
57
61
|
/** Asks for the refresh-token flow (short access token + rotating refresh token). */
|
|
58
|
-
const RefreshableInput = z.boolean().optional();
|
|
62
|
+
const RefreshableInput = zod_1.z.boolean().optional();
|
|
59
63
|
/** The request's User-Agent, trimmed, for the sessions list. */
|
|
60
64
|
function clientLabel(req) {
|
|
61
65
|
const ua = req?.headers['user-agent'];
|
|
@@ -67,11 +71,11 @@ function clientLabel(req) {
|
|
|
67
71
|
* link claim, browser handoff — D801): per user, not per ip, because the
|
|
68
72
|
* caller is known and a tunnel puts every client behind one address.
|
|
69
73
|
*/
|
|
70
|
-
const SELF_CODE_LIMITER = createRateLimiter({ windowMs: 60_000, max: 10 });
|
|
71
|
-
const selfCodeProcedure = protectedProcedure.use(({ ctx, path, next }) => {
|
|
74
|
+
const SELF_CODE_LIMITER = (0, auth_rate_limit_js_1.createRateLimiter)({ windowMs: 60_000, max: 10 });
|
|
75
|
+
const selfCodeProcedure = trpc_middleware_js_1.protectedProcedure.use(({ ctx, path, next }) => {
|
|
72
76
|
const verdict = SELF_CODE_LIMITER.check(`${path}:${ctx.user?.id ?? 'anonymous'}`);
|
|
73
77
|
if (!verdict.allowed) {
|
|
74
|
-
throw new TRPCError({
|
|
78
|
+
throw new server_1.TRPCError({
|
|
75
79
|
code: 'TOO_MANY_REQUESTS',
|
|
76
80
|
message: `Too many attempts — retry in ${verdict.retryAfterSeconds}s`,
|
|
77
81
|
});
|
|
@@ -79,7 +83,7 @@ const selfCodeProcedure = protectedProcedure.use(({ ctx, path, next }) => {
|
|
|
79
83
|
return next({ ctx });
|
|
80
84
|
});
|
|
81
85
|
/** The hub route a browser-handoff code is redeemed at (`main.ts`). */
|
|
82
|
-
|
|
86
|
+
exports.BROWSER_HANDOFF_PATH = '/api/auth/browser-handoff';
|
|
83
87
|
/**
|
|
84
88
|
* The available second-factor kinds a user may satisfy after the
|
|
85
89
|
* password leg. Capability-driven — `totp` maps to the
|
|
@@ -103,26 +107,26 @@ export const BROWSER_HANDOFF_PATH = '/api/auth/browser-handoff';
|
|
|
103
107
|
* `requiresTotp` is retained (`= secondFactors.includes('totp')`) for
|
|
104
108
|
* backward compatibility with older SDK builds that branch on it.
|
|
105
109
|
*/
|
|
106
|
-
const LoginResultSchema = z.object({
|
|
107
|
-
token: z.string(),
|
|
108
|
-
user: z.object({
|
|
109
|
-
id: z.string(),
|
|
110
|
-
username: z.string(),
|
|
111
|
-
isAdmin: z.boolean(),
|
|
110
|
+
const LoginResultSchema = zod_1.z.object({
|
|
111
|
+
token: zod_1.z.string(),
|
|
112
|
+
user: zod_1.z.object({
|
|
113
|
+
id: zod_1.z.string(),
|
|
114
|
+
username: zod_1.z.string(),
|
|
115
|
+
isAdmin: zod_1.z.boolean(),
|
|
112
116
|
}),
|
|
113
|
-
requiresTotp: z.boolean().optional(),
|
|
114
|
-
secondFactors: z.array(SecondFactorSchema).optional(),
|
|
117
|
+
requiresTotp: zod_1.z.boolean().optional(),
|
|
118
|
+
secondFactors: zod_1.z.array(second_factors_js_1.SecondFactorSchema).optional(),
|
|
115
119
|
/** When the access token expires (epoch ms). Absent on a challenge. */
|
|
116
|
-
expiresAt: z.number().optional(),
|
|
120
|
+
expiresAt: zod_1.z.number().optional(),
|
|
117
121
|
/** The server-side login session. */
|
|
118
|
-
sessionId: z.string().optional(),
|
|
122
|
+
sessionId: zod_1.z.string().optional(),
|
|
119
123
|
/** When the session expires unless refreshed (epoch ms). */
|
|
120
|
-
sessionExpiresAt: z.number().optional(),
|
|
124
|
+
sessionExpiresAt: zod_1.z.number().optional(),
|
|
121
125
|
/**
|
|
122
126
|
* Only when the client asked (`refreshable: true`): swap it at
|
|
123
127
|
* `auth.refreshSession` before `expiresAt`. Store it like a password.
|
|
124
128
|
*/
|
|
125
|
-
refreshToken: z.string().optional(),
|
|
129
|
+
refreshToken: zod_1.z.string().optional(),
|
|
126
130
|
});
|
|
127
131
|
// ── Login-method aggregation (login-method cap) ──────────────────────
|
|
128
132
|
//
|
|
@@ -136,8 +140,8 @@ const LoginResultSchema = z.object({
|
|
|
136
140
|
// bundle's relative sibling imports inherit it and a CDN busts the WHOLE
|
|
137
141
|
// bundle atomically on deploy (see the stamping site below). `redirect` and
|
|
138
142
|
// `passkey` arms pass through untouched — no server-side enrichment needed.
|
|
139
|
-
const PublicWidgetLoginMethodSchema = WidgetLoginMethodSchema.extend({
|
|
140
|
-
bundleUrl: z.string(),
|
|
143
|
+
const PublicWidgetLoginMethodSchema = types_1.WidgetLoginMethodSchema.extend({
|
|
144
|
+
bundleUrl: zod_1.z.string(),
|
|
141
145
|
});
|
|
142
146
|
/** Stable per hub PROCESS — busts the login widget bundle URL on each
|
|
143
147
|
* restart/deploy while caching cleanly within the process's uptime. */
|
|
@@ -146,24 +150,24 @@ const AUTH_BUNDLE_VERSION = String(Date.now());
|
|
|
146
150
|
// always sends `app` (`null` when there is no app path - the viewer hides the
|
|
147
151
|
// method). It stays optional in the TYPE so the admin-ui's hand-mirrored arms,
|
|
148
152
|
// which never read it, keep matching this union.
|
|
149
|
-
const PublicRedirectLoginMethodSchema = RedirectLoginMethodSchema;
|
|
150
|
-
const PublicPasskeyLoginMethodSchema = PasskeyLoginMethodSchema;
|
|
151
|
-
const PublicLoginMethodSchema = z.discriminatedUnion('kind', [
|
|
153
|
+
const PublicRedirectLoginMethodSchema = types_1.RedirectLoginMethodSchema;
|
|
154
|
+
const PublicPasskeyLoginMethodSchema = types_1.PasskeyLoginMethodSchema;
|
|
155
|
+
const PublicLoginMethodSchema = zod_1.z.discriminatedUnion('kind', [
|
|
152
156
|
PublicRedirectLoginMethodSchema,
|
|
153
157
|
PublicWidgetLoginMethodSchema,
|
|
154
158
|
PublicPasskeyLoginMethodSchema,
|
|
155
|
-
DeviceCertificateLoginMethodSchema,
|
|
159
|
+
types_1.DeviceCertificateLoginMethodSchema,
|
|
156
160
|
]);
|
|
157
161
|
/** One of the caller's linked sign-in identities, as the profile shows it (D782). */
|
|
158
|
-
const OwnExternalIdentitySchema = z.object({
|
|
159
|
-
provider: z.string(),
|
|
160
|
-
subject: z.string(),
|
|
161
|
-
label: z.string().optional(),
|
|
162
|
-
linkedAt: z.number(),
|
|
162
|
+
const OwnExternalIdentitySchema = zod_1.z.object({
|
|
163
|
+
provider: zod_1.z.string(),
|
|
164
|
+
subject: zod_1.z.string(),
|
|
165
|
+
label: zod_1.z.string().optional(),
|
|
166
|
+
linkedAt: zod_1.z.number(),
|
|
163
167
|
/** The provider instance's button label, or `null` when it is gone / disabled. */
|
|
164
|
-
providerLabel: z.string().nullable(),
|
|
168
|
+
providerLabel: zod_1.z.string().nullable(),
|
|
165
169
|
/** Whether the provider instance is configured and enabled right now. */
|
|
166
|
-
available: z.boolean(),
|
|
170
|
+
available: zod_1.z.boolean(),
|
|
167
171
|
});
|
|
168
172
|
// ── Share tokens (grid-view standalone share links) ──────────────────
|
|
169
173
|
//
|
|
@@ -175,26 +179,26 @@ const OwnExternalIdentitySchema = z.object({
|
|
|
175
179
|
// TTL: a bounded number of seconds, or the EXPLICIT literal `'never'`
|
|
176
180
|
// for a permanently-shared grid (revocation is the kill switch).
|
|
177
181
|
// Omitted → 7-day default; infinite is never a silent default.
|
|
178
|
-
const CreateShareTokenInputSchema = z.object({
|
|
179
|
-
scope: ShareTokenScopeSchema,
|
|
180
|
-
ttlSec: z
|
|
182
|
+
const CreateShareTokenInputSchema = zod_1.z.object({
|
|
183
|
+
scope: share_token_service_js_1.ShareTokenScopeSchema,
|
|
184
|
+
ttlSec: zod_1.z
|
|
181
185
|
.union([
|
|
182
|
-
z.number().int().min(SHARE_TOKEN_TTL_MIN_SEC).max(SHARE_TOKEN_TTL_MAX_SEC),
|
|
183
|
-
z.literal('never'),
|
|
186
|
+
zod_1.z.number().int().min(share_token_service_js_1.SHARE_TOKEN_TTL_MIN_SEC).max(share_token_service_js_1.SHARE_TOKEN_TTL_MAX_SEC),
|
|
187
|
+
zod_1.z.literal('never'),
|
|
184
188
|
])
|
|
185
189
|
.optional(),
|
|
186
190
|
});
|
|
187
|
-
const ShareTokenSummarySchema = z.object({
|
|
188
|
-
id: z.string(),
|
|
189
|
-
userId: z.string(),
|
|
190
|
-
tokenPrefix: z.string(),
|
|
191
|
-
scope: ShareTokenScopeSchema,
|
|
192
|
-
createdAt: z.number(),
|
|
191
|
+
const ShareTokenSummarySchema = zod_1.z.object({
|
|
192
|
+
id: zod_1.z.string(),
|
|
193
|
+
userId: zod_1.z.string(),
|
|
194
|
+
tokenPrefix: zod_1.z.string(),
|
|
195
|
+
scope: share_token_service_js_1.ShareTokenScopeSchema,
|
|
196
|
+
createdAt: zod_1.z.number(),
|
|
193
197
|
/** Epoch ms, or `null` for never-expiring tokens. */
|
|
194
|
-
expiresAt: z.number().nullable(),
|
|
198
|
+
expiresAt: zod_1.z.number().nullable(),
|
|
195
199
|
/** Derived convenience flag so listings surface infinite tokens clearly. */
|
|
196
|
-
neverExpires: z.boolean(),
|
|
197
|
-
lastUsedAt: z.number().optional(),
|
|
200
|
+
neverExpires: zod_1.z.boolean(),
|
|
201
|
+
lastUsedAt: zod_1.z.number().optional(),
|
|
198
202
|
});
|
|
199
203
|
function toShareTokenSummary(record) {
|
|
200
204
|
return {
|
|
@@ -218,7 +222,7 @@ function assertRealUserSession(user, what = 'Share-token management') {
|
|
|
218
222
|
// An admin token is a script's credential, never a person's session: it
|
|
219
223
|
// must not turn itself into a session (handoff codes) or mint links.
|
|
220
224
|
if (user.isScoped || user.shareView || user.adminTokenId !== undefined) {
|
|
221
|
-
throw new TRPCError({
|
|
225
|
+
throw new server_1.TRPCError({
|
|
222
226
|
code: 'FORBIDDEN',
|
|
223
227
|
message: `${what} requires a real user session`,
|
|
224
228
|
});
|
|
@@ -235,7 +239,7 @@ function assertRealUserSession(user, what = 'Share-token management') {
|
|
|
235
239
|
// answers with a freshly-minted session).
|
|
236
240
|
/** Custom header a cross-site form can never set — CSRF gate for the
|
|
237
241
|
* cookie-authenticated `exchangeSession` mutation. */
|
|
238
|
-
|
|
242
|
+
exports.EXCHANGE_SESSION_HEADER = 'x-camstack-exchange';
|
|
239
243
|
/** Read a single-valued request header off the tRPC context request. */
|
|
240
244
|
function readRequestHeader(req, name) {
|
|
241
245
|
const value = req?.headers[name];
|
|
@@ -246,14 +250,14 @@ function readRequestHeader(req, name) {
|
|
|
246
250
|
return null;
|
|
247
251
|
}
|
|
248
252
|
/** Per-access device reach summary (counts, never id lists). */
|
|
249
|
-
const DeviceReachSummarySchema = z.object({
|
|
250
|
-
all: z.boolean(),
|
|
251
|
-
deviceCount: z.number().int(),
|
|
253
|
+
const DeviceReachSummarySchema = zod_1.z.object({
|
|
254
|
+
all: zod_1.z.boolean(),
|
|
255
|
+
deviceCount: zod_1.z.number().int(),
|
|
252
256
|
});
|
|
253
257
|
/** One capability/addon grant flattened for the UI. */
|
|
254
|
-
const ScopeGrantSummarySchema = z.object({
|
|
255
|
-
name: z.string(),
|
|
256
|
-
access: z.array(MethodAccessSchema).readonly(),
|
|
258
|
+
const ScopeGrantSummarySchema = zod_1.z.object({
|
|
259
|
+
name: zod_1.z.string(),
|
|
260
|
+
access: zod_1.z.array(types_1.MethodAccessSchema).readonly(),
|
|
257
261
|
});
|
|
258
262
|
/**
|
|
259
263
|
* The caller's RESOLVED effective scope (scope model v3). Selectors are
|
|
@@ -261,31 +265,31 @@ const ScopeGrantSummarySchema = z.object({
|
|
|
261
265
|
* the viewer (F3/F4) can HIDE out-of-scope surfaces from a single probe. A
|
|
262
266
|
* non-admin with zero grants reports zero everything (born with no access).
|
|
263
267
|
*/
|
|
264
|
-
const EffectiveScopeSchema = z.object({
|
|
265
|
-
isAdmin: z.boolean(),
|
|
266
|
-
allDevicesViewable: z.boolean(),
|
|
267
|
-
viewableDeviceCount: z.number().int(),
|
|
268
|
-
device: z.object({
|
|
268
|
+
const EffectiveScopeSchema = zod_1.z.object({
|
|
269
|
+
isAdmin: zod_1.z.boolean(),
|
|
270
|
+
allDevicesViewable: zod_1.z.boolean(),
|
|
271
|
+
viewableDeviceCount: zod_1.z.number().int(),
|
|
272
|
+
device: zod_1.z.object({
|
|
269
273
|
view: DeviceReachSummarySchema,
|
|
270
274
|
create: DeviceReachSummarySchema,
|
|
271
275
|
delete: DeviceReachSummarySchema,
|
|
272
276
|
}),
|
|
273
|
-
system: z.array(MethodAccessSchema).readonly(),
|
|
274
|
-
capabilities: z.array(ScopeGrantSummarySchema).readonly(),
|
|
275
|
-
addons: z.array(ScopeGrantSummarySchema).readonly(),
|
|
277
|
+
system: zod_1.z.array(types_1.MethodAccessSchema).readonly(),
|
|
278
|
+
capabilities: zod_1.z.array(ScopeGrantSummarySchema).readonly(),
|
|
279
|
+
addons: zod_1.z.array(ScopeGrantSummarySchema).readonly(),
|
|
276
280
|
});
|
|
277
281
|
/** Wire shape of the authenticated user returned by `auth.me`. */
|
|
278
|
-
const MeSchema = z
|
|
282
|
+
const MeSchema = zod_1.z
|
|
279
283
|
.object({
|
|
280
|
-
id: z.string(),
|
|
281
|
-
username: z.string(),
|
|
282
|
-
isAdmin: z.boolean(),
|
|
283
|
-
permissions: z.object({
|
|
284
|
-
isAdmin: z.boolean(),
|
|
285
|
-
allowedProviders: z.union([z.literal('*'), z.array(z.string())]),
|
|
286
|
-
allowedDevices: z.record(z.string(), z.unknown()),
|
|
284
|
+
id: zod_1.z.string(),
|
|
285
|
+
username: zod_1.z.string(),
|
|
286
|
+
isAdmin: zod_1.z.boolean(),
|
|
287
|
+
permissions: zod_1.z.object({
|
|
288
|
+
isAdmin: zod_1.z.boolean(),
|
|
289
|
+
allowedProviders: zod_1.z.union([zod_1.z.literal('*'), zod_1.z.array(zod_1.z.string())]),
|
|
290
|
+
allowedDevices: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
287
291
|
}),
|
|
288
|
-
isApiKey: z.boolean(),
|
|
292
|
+
isApiKey: zod_1.z.boolean(),
|
|
289
293
|
/**
|
|
290
294
|
* The caller's resolved effective scope. Absent only on the (unreachable
|
|
291
295
|
* here — `me` is `protected`) null-principal branch.
|
|
@@ -293,9 +297,9 @@ const MeSchema = z
|
|
|
293
297
|
scope: EffectiveScopeSchema.optional(),
|
|
294
298
|
})
|
|
295
299
|
.nullable();
|
|
296
|
-
|
|
297
|
-
const network = options.network ?? DEFAULT_AUTH_NETWORK_POLICY;
|
|
298
|
-
const limiters = options.limiters ?? PROCESS_AUTH_LIMITERS;
|
|
300
|
+
function createAuthRouter(auth, registry, moleculer = null, shareTokens = null, handoffCodes = new handoff_code_service_js_1.HandoffCodeService(), linkIntents = new external_link_intents_js_1.ExternalLinkIntents(), nativeLink = null, options = {}) {
|
|
301
|
+
const network = options.network ?? auth_network_policy_js_1.DEFAULT_AUTH_NETWORK_POLICY;
|
|
302
|
+
const limiters = options.limiters ?? auth_limits_js_1.PROCESS_AUTH_LIMITERS;
|
|
299
303
|
/** Secret-verifying legs (password / TOTP / passkey assertion / codes). */
|
|
300
304
|
const credentialProcedure = makeRateLimitedProcedure(limiters.credential, network);
|
|
301
305
|
/** Challenge-minting begin-legs — looser, they verify nothing. */
|
|
@@ -313,13 +317,13 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
313
317
|
* admin change made mid-flow; signing from stale claims could mint a
|
|
314
318
|
* stale-scope session.
|
|
315
319
|
*/
|
|
316
|
-
const minter = createSessionMinter({
|
|
320
|
+
const minter = (0, session_mint_js_1.createSessionMinter)({
|
|
317
321
|
signer: auth,
|
|
318
322
|
directory: () => registry?.getSingleton('user-management'),
|
|
319
323
|
...(options.sessions !== undefined ? { sessions: options.sessions } : {}),
|
|
320
324
|
credentials: options.credentials ??
|
|
321
325
|
(() => {
|
|
322
|
-
const internal = registry === null ? null : userManagementInternal(registry);
|
|
326
|
+
const internal = registry === null ? null : (0, hub_sessions_js_1.userManagementInternal)(registry);
|
|
323
327
|
return internal === null ? null : internal.deviceCredentials;
|
|
324
328
|
}),
|
|
325
329
|
});
|
|
@@ -348,8 +352,8 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
348
352
|
return await mintSessionForUserId(userId, issue);
|
|
349
353
|
}
|
|
350
354
|
catch (error) {
|
|
351
|
-
if (error instanceof SessionUserGoneError) {
|
|
352
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.user-gone', undefined, 'User no longer exists');
|
|
355
|
+
if (error instanceof session_mint_js_1.SessionUserGoneError) {
|
|
356
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.user-gone', undefined, 'User no longer exists');
|
|
353
357
|
}
|
|
354
358
|
throw error;
|
|
355
359
|
}
|
|
@@ -357,11 +361,11 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
357
361
|
/** The second factors a primary login still owes (`auth/second-factors.ts`). */
|
|
358
362
|
const collectSecondFactorsFor = async (userId, primary) => {
|
|
359
363
|
const userMgmt = registry?.getSingleton('user-management');
|
|
360
|
-
return collectSecondFactors({
|
|
364
|
+
return (0, second_factors_js_1.collectSecondFactors)({
|
|
361
365
|
...(userMgmt && typeof userMgmt.getTotpStatus === 'function'
|
|
362
366
|
? { getTotpStatus: (input) => userMgmt.getTotpStatus(input) }
|
|
363
367
|
: {}),
|
|
364
|
-
passkeyProvider: () => resolvePasskeyProvider(registry, moleculer),
|
|
368
|
+
passkeyProvider: () => (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer),
|
|
365
369
|
}, userId, primary);
|
|
366
370
|
};
|
|
367
371
|
/**
|
|
@@ -377,7 +381,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
377
381
|
const address = network.clientAddress(req);
|
|
378
382
|
if (!network.isTrustedNetworkLogin(address))
|
|
379
383
|
return factors;
|
|
380
|
-
const internal = registry === null ? null : userManagementInternal(registry);
|
|
384
|
+
const internal = registry === null ? null : (0, hub_sessions_js_1.userManagementInternal)(registry);
|
|
381
385
|
if (internal === null)
|
|
382
386
|
return factors; // cannot audit it → do not skip it
|
|
383
387
|
await internal.audit.record({
|
|
@@ -409,18 +413,18 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
409
413
|
for (const [name, value] of Object.entries(req?.headers ?? {})) {
|
|
410
414
|
headers[name.toLowerCase()] = Array.isArray(value) ? value[0] : value;
|
|
411
415
|
}
|
|
412
|
-
const picked = pickRequestOrigin(headers, advertisedHubOrigins(book));
|
|
416
|
+
const picked = (0, types_1.pickRequestOrigin)(headers, (0, types_1.advertisedHubOrigins)(book));
|
|
413
417
|
return (picked ??
|
|
414
418
|
book.roles.publicEndpoint.resolved ??
|
|
415
419
|
book.roles.appConnections.resolved[0] ??
|
|
416
420
|
null);
|
|
417
421
|
});
|
|
418
|
-
const enrollProofs = options.enrollProofs ?? new DeviceEnrollProofs(Date.now, options.logger ?? null);
|
|
422
|
+
const enrollProofs = options.enrollProofs ?? new device_enroll_proofs_js_1.DeviceEnrollProofs(Date.now, options.logger ?? null);
|
|
419
423
|
/** The device credential behind a session, so a session minted FROM it inherits it (D855). */
|
|
420
424
|
const credentialOfSession = (sessionId) => {
|
|
421
425
|
if (sessionId === undefined || registry === null)
|
|
422
426
|
return undefined;
|
|
423
|
-
const check = userManagementInternal(registry)?.sessions.check(sessionId);
|
|
427
|
+
const check = (0, hub_sessions_js_1.userManagementInternal)(registry)?.sessions.check(sessionId);
|
|
424
428
|
return check?.state === 'active' ? (check.session.credentialId ?? undefined) : undefined;
|
|
425
429
|
};
|
|
426
430
|
/**
|
|
@@ -434,10 +438,10 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
434
438
|
const assertFreshAuthentication = (user, reauthToken) => {
|
|
435
439
|
const refuse = (message) => {
|
|
436
440
|
options.logger?.warn(`Step-up refused: ${message}`, { tags: { userId: user.id } });
|
|
437
|
-
throw new TRPCError({ code: 'FORBIDDEN', message: `Sign in again first: ${message}` });
|
|
441
|
+
throw new server_1.TRPCError({ code: 'FORBIDDEN', message: `Sign in again first: ${message}` });
|
|
438
442
|
};
|
|
439
443
|
if (reauthToken !== undefined) {
|
|
440
|
-
assertReauthenticated(auth, user, reauthToken);
|
|
444
|
+
(0, auth_reauth_procedures_js_1.assertReauthenticated)(auth, user, reauthToken);
|
|
441
445
|
if (!enrollProofs.consumeReauth(reauthToken))
|
|
442
446
|
refuse('that confirmation was already used');
|
|
443
447
|
return;
|
|
@@ -445,7 +449,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
445
449
|
const sid = user.sessionId;
|
|
446
450
|
const check = sid === undefined || registry === null
|
|
447
451
|
? null
|
|
448
|
-
: userManagementInternal(registry)?.sessions.check(sid);
|
|
452
|
+
: (0, hub_sessions_js_1.userManagementInternal)(registry)?.sessions.check(sid);
|
|
449
453
|
if (check?.state !== 'active')
|
|
450
454
|
return refuse('no live session');
|
|
451
455
|
if (!STEP_UP_LOGIN_METHODS.includes(check.session.method)) {
|
|
@@ -458,7 +462,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
458
462
|
return refuse('this sign-in already started a step-up');
|
|
459
463
|
}
|
|
460
464
|
};
|
|
461
|
-
const serverNameReader = serverNameReaderFor(registry);
|
|
465
|
+
const serverNameReader = (0, server_name_js_1.serverNameReaderFor)(registry);
|
|
462
466
|
const aggregateLoginMethods = async () => {
|
|
463
467
|
if (!registry)
|
|
464
468
|
return [];
|
|
@@ -471,7 +475,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
471
475
|
// The operator's Enable/Disable on Identity → Authentication is the
|
|
472
476
|
// addon's ONE enable (D777). It toggles `auth-provider` /
|
|
473
477
|
// `user-passkeys`, never `login-method` — so ask the governing caps.
|
|
474
|
-
if (isAuthAddonDisabled(registry, addonId))
|
|
478
|
+
if ((0, auth_provider_gate_js_1.isAuthAddonDisabled)(registry, addonId))
|
|
475
479
|
continue;
|
|
476
480
|
let contributions;
|
|
477
481
|
try {
|
|
@@ -501,7 +505,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
501
505
|
// system browser at it; a second-factor ceremony has no app path.
|
|
502
506
|
const parsed = PublicPasskeyLoginMethodSchema.safeParse({
|
|
503
507
|
...raw,
|
|
504
|
-
app: raw.stage === 'primary' ? { kind: 'browser', startPath: APP_PASSKEY_PATH } : null,
|
|
508
|
+
app: raw.stage === 'primary' ? { kind: 'browser', startPath: app_passkey_routes_js_1.APP_PASSKEY_PATH } : null,
|
|
505
509
|
});
|
|
506
510
|
if (parsed.success) {
|
|
507
511
|
out.push(parsed.data);
|
|
@@ -532,7 +536,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
532
536
|
// The hub's own method (D855): a device certificate. Not an addon
|
|
533
537
|
// contribution - the device CA lives in `local-auth` - so it is added here.
|
|
534
538
|
// Offered only where the hub can actually serve it (local-auth up).
|
|
535
|
-
if (userManagementInternal(registry) !== null)
|
|
539
|
+
if ((0, hub_sessions_js_1.userManagementInternal)(registry) !== null)
|
|
536
540
|
out.push({
|
|
537
541
|
kind: 'device-certificate',
|
|
538
542
|
id: 'device-certificate',
|
|
@@ -543,8 +547,8 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
543
547
|
renewPath: 'auth.renewDeviceCertificate',
|
|
544
548
|
revokePath: 'auth.revokeOwnDeviceCertificate',
|
|
545
549
|
enrollSelfPath: 'auth.enrollSelf',
|
|
546
|
-
signature: DEVICE_CERT_SIGNATURE,
|
|
547
|
-
messageVersion: DEVICE_SIGNATURE_MESSAGE_VERSION,
|
|
550
|
+
signature: types_1.DEVICE_CERT_SIGNATURE,
|
|
551
|
+
messageVersion: types_1.DEVICE_SIGNATURE_MESSAGE_VERSION,
|
|
548
552
|
clients: ['native'],
|
|
549
553
|
app: { kind: 'native' },
|
|
550
554
|
});
|
|
@@ -557,9 +561,9 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
557
561
|
const linkableProviders = async () => (await aggregateLoginMethods()).flatMap((m) => m.kind === 'redirect' && m.linkable === true
|
|
558
562
|
? [{ provider: m.id, label: m.label, startUrl: m.startUrl }]
|
|
559
563
|
: []);
|
|
560
|
-
return trpcRouter({
|
|
564
|
+
return (0, trpc_middleware_js_1.trpcRouter)({
|
|
561
565
|
login: credentialProcedure
|
|
562
|
-
.input(z.object({ username: z.string(), password: z.string(), refreshable: RefreshableInput }))
|
|
566
|
+
.input(zod_1.z.object({ username: zod_1.z.string(), password: zod_1.z.string(), refreshable: RefreshableInput }))
|
|
563
567
|
.output(LoginResultSchema)
|
|
564
568
|
.mutation(async ({ input, ctx }) => {
|
|
565
569
|
const userMgmt = registry?.getSingleton('user-management');
|
|
@@ -573,14 +577,14 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
573
577
|
'The `local-auth` addon failed to initialize; check server logs ' +
|
|
574
578
|
'for an error tagged `[hub/local-auth]`.');
|
|
575
579
|
}
|
|
576
|
-
assertAccountNotLocked(limiters, input.username);
|
|
580
|
+
(0, auth_limits_js_1.assertAccountNotLocked)(limiters, input.username);
|
|
577
581
|
const user = await userMgmt.validateCredentials({
|
|
578
582
|
username: input.username,
|
|
579
583
|
password: input.password,
|
|
580
584
|
});
|
|
581
585
|
if (!user) {
|
|
582
|
-
recordAccountFailure(limiters, input.username);
|
|
583
|
-
throw userError('auth.invalid-credentials', undefined, 'Invalid credentials');
|
|
586
|
+
(0, auth_limits_js_1.recordAccountFailure)(limiters, input.username);
|
|
587
|
+
throw (0, types_2.userError)('auth.invalid-credentials', undefined, 'Invalid credentials');
|
|
584
588
|
}
|
|
585
589
|
// ── Second-factor gate ───────────────────────────────────────
|
|
586
590
|
// After credentials validate, collect every ACTIVE second
|
|
@@ -625,7 +629,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
625
629
|
* deleted concurrently — rare).
|
|
626
630
|
*/
|
|
627
631
|
loginVerifyTotp: credentialProcedure
|
|
628
|
-
.input(z.object({ challengeToken: z.string(), code: z.string(), refreshable: RefreshableInput }))
|
|
632
|
+
.input(zod_1.z.object({ challengeToken: zod_1.z.string(), code: zod_1.z.string(), refreshable: RefreshableInput }))
|
|
629
633
|
.output(LoginResultSchema)
|
|
630
634
|
.mutation(async ({ input, ctx }) => {
|
|
631
635
|
const claims = auth.verifyTotpChallengeToken(input.challengeToken);
|
|
@@ -636,13 +640,13 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
636
640
|
if (!userMgmt) {
|
|
637
641
|
throw new Error('Login unavailable — `user-management` capability not registered');
|
|
638
642
|
}
|
|
639
|
-
assertAccountNotLocked(limiters, claims.username);
|
|
643
|
+
(0, auth_limits_js_1.assertAccountNotLocked)(limiters, claims.username);
|
|
640
644
|
const verify = typeof userMgmt.verifyTotp === 'function'
|
|
641
645
|
? await userMgmt.verifyTotp({ userId: claims.userId, code: input.code.trim() })
|
|
642
646
|
: { valid: false };
|
|
643
647
|
if (!verify.valid) {
|
|
644
|
-
recordAccountFailure(limiters, claims.username);
|
|
645
|
-
throw userError('auth.invalid-totp', undefined, 'Invalid TOTP code');
|
|
648
|
+
(0, auth_limits_js_1.recordAccountFailure)(limiters, claims.username);
|
|
649
|
+
throw (0, types_2.userError)('auth.invalid-totp', undefined, 'Invalid TOTP code');
|
|
646
650
|
}
|
|
647
651
|
return mintSessionForUserId(claims.userId, issueFor(ctx.req, claims.method ?? 'password', input.refreshable));
|
|
648
652
|
}),
|
|
@@ -654,14 +658,14 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
654
658
|
* the client is still pre-session at this point.
|
|
655
659
|
*/
|
|
656
660
|
loginBeginPasskey: ceremonyProcedure
|
|
657
|
-
.input(z.object({ challengeToken: z.string() }))
|
|
658
|
-
.output(OptionsJsonSchema)
|
|
661
|
+
.input(zod_1.z.object({ challengeToken: zod_1.z.string() }))
|
|
662
|
+
.output(passkey_provider_js_1.OptionsJsonSchema)
|
|
659
663
|
.mutation(async ({ input }) => {
|
|
660
664
|
const claims = auth.verifyTotpChallengeToken(input.challengeToken);
|
|
661
665
|
if (!claims) {
|
|
662
|
-
throw userError('auth.login-challenge-expired', undefined, 'Invalid or expired login challenge — please re-enter your password');
|
|
666
|
+
throw (0, types_2.userError)('auth.login-challenge-expired', undefined, 'Invalid or expired login challenge — please re-enter your password');
|
|
663
667
|
}
|
|
664
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
668
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
665
669
|
if (!provider)
|
|
666
670
|
throw new Error('Passkey authentication is not available');
|
|
667
671
|
return provider.beginAuthentication({ userId: claims.userId });
|
|
@@ -674,28 +678,28 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
674
678
|
* `loginVerifyTotp` uses (fresh user re-fetch for up-to-date scopes).
|
|
675
679
|
*/
|
|
676
680
|
loginVerifyPasskey: credentialProcedure
|
|
677
|
-
.input(z.object({
|
|
678
|
-
challengeToken: z.string(),
|
|
679
|
-
response: z.record(z.string(), z.unknown()),
|
|
681
|
+
.input(zod_1.z.object({
|
|
682
|
+
challengeToken: zod_1.z.string(),
|
|
683
|
+
response: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()),
|
|
680
684
|
refreshable: RefreshableInput,
|
|
681
685
|
}))
|
|
682
686
|
.output(LoginResultSchema)
|
|
683
687
|
.mutation(async ({ input, ctx }) => {
|
|
684
688
|
const claims = auth.verifyTotpChallengeToken(input.challengeToken);
|
|
685
689
|
if (!claims) {
|
|
686
|
-
throw userError('auth.login-challenge-expired', undefined, 'Invalid or expired login challenge — please re-enter your password');
|
|
690
|
+
throw (0, types_2.userError)('auth.login-challenge-expired', undefined, 'Invalid or expired login challenge — please re-enter your password');
|
|
687
691
|
}
|
|
688
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
692
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
689
693
|
if (!provider)
|
|
690
694
|
throw new Error('Passkey authentication is not available');
|
|
691
|
-
assertAccountNotLocked(limiters, claims.username);
|
|
695
|
+
(0, auth_limits_js_1.assertAccountNotLocked)(limiters, claims.username);
|
|
692
696
|
const result = await provider.finishAuthentication({
|
|
693
697
|
userId: claims.userId,
|
|
694
698
|
response: input.response,
|
|
695
699
|
});
|
|
696
700
|
if (!result.verified) {
|
|
697
|
-
recordAccountFailure(limiters, claims.username);
|
|
698
|
-
throw userError('auth.passkey-verification-failed', undefined, 'Passkey verification failed');
|
|
701
|
+
(0, auth_limits_js_1.recordAccountFailure)(limiters, claims.username);
|
|
702
|
+
throw (0, types_2.userError)('auth.passkey-verification-failed', undefined, 'Passkey verification failed');
|
|
699
703
|
}
|
|
700
704
|
return mintSessionForUserId(claims.userId, issueFor(ctx.req, claims.method ?? 'password', input.refreshable));
|
|
701
705
|
}),
|
|
@@ -711,10 +715,10 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
711
715
|
* challenge store is bounded by its 5-min TTL prune.
|
|
712
716
|
*/
|
|
713
717
|
passkeyLoginBegin: ceremonyProcedure
|
|
714
|
-
.input(z.void())
|
|
715
|
-
.output(OptionsJsonSchema)
|
|
718
|
+
.input(zod_1.z.void())
|
|
719
|
+
.output(passkey_provider_js_1.OptionsJsonSchema)
|
|
716
720
|
.mutation(async () => {
|
|
717
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
721
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
718
722
|
if (!provider)
|
|
719
723
|
throw new Error('Passkey authentication is not available');
|
|
720
724
|
return provider.beginDiscoverableAuthentication({});
|
|
@@ -735,17 +739,17 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
735
739
|
* re-proving it adds nothing.
|
|
736
740
|
*/
|
|
737
741
|
passkeyLoginFinish: credentialProcedure
|
|
738
|
-
.input(z.object({ response: z.record(z.string(), z.unknown()), refreshable: RefreshableInput }))
|
|
742
|
+
.input(zod_1.z.object({ response: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()), refreshable: RefreshableInput }))
|
|
739
743
|
.output(LoginResultSchema)
|
|
740
744
|
.mutation(async ({ input, ctx }) => {
|
|
741
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
745
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
742
746
|
if (!provider)
|
|
743
747
|
throw new Error('Passkey authentication is not available');
|
|
744
748
|
const result = await provider.finishDiscoverableAuthentication({
|
|
745
749
|
response: input.response,
|
|
746
750
|
});
|
|
747
751
|
if (!result.verified || !result.userId) {
|
|
748
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.passkey-verification-failed', undefined, 'Passkey verification failed');
|
|
752
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.passkey-verification-failed', undefined, 'Passkey verification failed');
|
|
749
753
|
}
|
|
750
754
|
const secondFactors = await factorsOwedHere(result.userId, 'passkey', ctx.req);
|
|
751
755
|
if (secondFactors.length > 0) {
|
|
@@ -790,25 +794,25 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
790
794
|
* scopes), equivalent to what `auth.login` hands out.
|
|
791
795
|
*/
|
|
792
796
|
exchangeSession: credentialProcedure
|
|
793
|
-
.input(z.object({ refreshable: RefreshableInput }).optional())
|
|
797
|
+
.input(zod_1.z.object({ refreshable: RefreshableInput }).optional())
|
|
794
798
|
.output(LoginResultSchema)
|
|
795
799
|
.mutation(async ({ ctx, input }) => {
|
|
796
|
-
if (readRequestHeader(ctx.req, EXCHANGE_SESSION_HEADER) !== '1') {
|
|
797
|
-
throw new TRPCError({
|
|
800
|
+
if (readRequestHeader(ctx.req, exports.EXCHANGE_SESSION_HEADER) !== '1') {
|
|
801
|
+
throw new server_1.TRPCError({
|
|
798
802
|
code: 'FORBIDDEN',
|
|
799
|
-
message: `Missing ${EXCHANGE_SESSION_HEADER} header`,
|
|
803
|
+
message: `Missing ${exports.EXCHANGE_SESSION_HEADER} header`,
|
|
800
804
|
});
|
|
801
805
|
}
|
|
802
|
-
const cookieToken = readSessionCookieFromHeader(readRequestHeader(ctx.req, 'cookie') ?? undefined);
|
|
806
|
+
const cookieToken = (0, session_cookie_js_1.readSessionCookieFromHeader)(readRequestHeader(ctx.req, 'cookie') ?? undefined);
|
|
803
807
|
if (!cookieToken) {
|
|
804
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.no-session-cookie', undefined, 'No session cookie');
|
|
808
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.no-session-cookie', undefined, 'No session cookie');
|
|
805
809
|
}
|
|
806
810
|
let payload;
|
|
807
811
|
try {
|
|
808
812
|
payload = auth.verifyToken(cookieToken);
|
|
809
813
|
}
|
|
810
814
|
catch {
|
|
811
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.invalid-session-cookie', undefined, 'Invalid session cookie');
|
|
815
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.invalid-session-cookie', undefined, 'Invalid session cookie');
|
|
812
816
|
}
|
|
813
817
|
// Reject non-session JWTs that verify under the same secret:
|
|
814
818
|
// challenge/bridge tokens carry a `kind` discriminator, and a
|
|
@@ -817,7 +821,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
817
821
|
if (kind !== undefined ||
|
|
818
822
|
typeof payload.isAdmin !== 'boolean' ||
|
|
819
823
|
typeof payload.userId !== 'string') {
|
|
820
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.invalid-session-cookie', undefined, 'Invalid session cookie');
|
|
824
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.invalid-session-cookie', undefined, 'Invalid session cookie');
|
|
821
825
|
}
|
|
822
826
|
// A session of its own for the client that asked (the hub-served
|
|
823
827
|
// viewer): signing out of one never signs the other out.
|
|
@@ -836,19 +840,19 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
836
840
|
/** Mint a one-time handoff code for the CALLING user. Real user
|
|
837
841
|
* sessions only — scoped (`cst_`) and share-view (`csv_`) callers
|
|
838
842
|
* must never convert themselves into a full session. */
|
|
839
|
-
createHandoffCode: protectedProcedure
|
|
840
|
-
.input(z
|
|
843
|
+
createHandoffCode: trpc_middleware_js_1.protectedProcedure
|
|
844
|
+
.input(zod_1.z
|
|
841
845
|
.object({
|
|
842
|
-
purpose: z.enum(['renew', 'new-session', 'step-up']).optional(),
|
|
846
|
+
purpose: zod_1.z.enum(['renew', 'new-session', 'step-up']).optional(),
|
|
843
847
|
/** PKCE S256 challenge of the app's verifier: redeem then requires the verifier. */
|
|
844
|
-
codeChallenge: z.string().min(43).max(128).optional(),
|
|
848
|
+
codeChallenge: zod_1.z.string().min(43).max(128).optional(),
|
|
845
849
|
/** The app's anti-CSRF state, required again at redeem. */
|
|
846
|
-
state: z.string().min(1).max(256).optional(),
|
|
850
|
+
state: zod_1.z.string().min(1).max(256).optional(),
|
|
847
851
|
/** `step-up`: a fresh single-use re-authentication, when the session itself is not a fresh sign-in. */
|
|
848
|
-
reauthToken: ReauthTokenInput.optional(),
|
|
852
|
+
reauthToken: auth_reauth_procedures_js_1.ReauthTokenInput.optional(),
|
|
849
853
|
})
|
|
850
854
|
.optional())
|
|
851
|
-
.output(z.object({ code: z.string(), expiresAt: z.number() }))
|
|
855
|
+
.output(zod_1.z.object({ code: zod_1.z.string(), expiresAt: zod_1.z.number() }))
|
|
852
856
|
.mutation(({ ctx, input }) => {
|
|
853
857
|
assertRealUserSession(ctx.user, 'Handoff-code minting');
|
|
854
858
|
const purpose = input?.purpose ?? 'renew';
|
|
@@ -861,7 +865,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
861
865
|
tags: { userId: ctx.user.id },
|
|
862
866
|
meta: { purpose },
|
|
863
867
|
});
|
|
864
|
-
throw new TRPCError({
|
|
868
|
+
throw new server_1.TRPCError({
|
|
865
869
|
code: 'BAD_REQUEST',
|
|
866
870
|
message: 'codeChallenge (S256) and state are required for this handoff',
|
|
867
871
|
});
|
|
@@ -883,12 +887,12 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
883
887
|
/** PUBLIC — redeem a one-time handoff code for a session bearer.
|
|
884
888
|
* Unknown / expired / already-used codes → UNAUTHORIZED. */
|
|
885
889
|
redeemHandoffCode: credentialProcedure
|
|
886
|
-
.input(z.object({
|
|
887
|
-
code: z.string().min(1),
|
|
890
|
+
.input(zod_1.z.object({
|
|
891
|
+
code: zod_1.z.string().min(1),
|
|
888
892
|
refreshable: RefreshableInput,
|
|
889
893
|
/** PKCE: required when the code was minted with a `codeChallenge`. */
|
|
890
|
-
codeVerifier: z.string().min(1).max(256).optional(),
|
|
891
|
-
state: z.string().min(1).max(256).optional(),
|
|
894
|
+
codeVerifier: zod_1.z.string().min(1).max(256).optional(),
|
|
895
|
+
state: zod_1.z.string().min(1).max(256).optional(),
|
|
892
896
|
}))
|
|
893
897
|
.output(LoginResultSchema)
|
|
894
898
|
.mutation(async ({ input, ctx }) => {
|
|
@@ -910,7 +914,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
910
914
|
});
|
|
911
915
|
}
|
|
912
916
|
if (!grant || grant.purpose === 'step-up') {
|
|
913
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.handoff-code-invalid', undefined, 'Invalid or expired handoff code');
|
|
917
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.handoff-code-invalid', undefined, 'Invalid or expired handoff code');
|
|
914
918
|
}
|
|
915
919
|
// A `renew` code continues THE SESSION IT WAS MINTED FROM. One without a session would
|
|
916
920
|
// open a brand-new session with no PKCE behind it: refused.
|
|
@@ -918,7 +922,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
918
922
|
options.logger?.warn('Handoff redeem refused: a renew code with no session behind it', {
|
|
919
923
|
tags: { userId: grant.userId },
|
|
920
924
|
});
|
|
921
|
-
throw trpcUserError('UNAUTHORIZED', 'auth.handoff-code-invalid', undefined, 'Invalid or expired handoff code');
|
|
925
|
+
throw (0, user_error_js_1.trpcUserError)('UNAUTHORIZED', 'auth.handoff-code-invalid', undefined, 'Invalid or expired handoff code');
|
|
922
926
|
}
|
|
923
927
|
if (grant.purpose === 'renew' && grant.sessionId !== undefined) {
|
|
924
928
|
// A legacy client renewing: the SAME session, its expiry slides. A
|
|
@@ -927,9 +931,9 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
927
931
|
return await minter.continueSession(grant.userId, grant.sessionId);
|
|
928
932
|
}
|
|
929
933
|
catch (error) {
|
|
930
|
-
if (error instanceof SessionRefreshRefusedError ||
|
|
931
|
-
error instanceof SessionUserGoneError) {
|
|
932
|
-
throw new TRPCError({
|
|
934
|
+
if (error instanceof session_mint_js_1.SessionRefreshRefusedError ||
|
|
935
|
+
error instanceof session_mint_js_1.SessionUserGoneError) {
|
|
936
|
+
throw new server_1.TRPCError({
|
|
933
937
|
code: 'UNAUTHORIZED',
|
|
934
938
|
message: 'Session expired — sign in again',
|
|
935
939
|
});
|
|
@@ -943,8 +947,8 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
943
947
|
...(grant.credentialId !== undefined ? { credentialId: grant.credentialId } : {}),
|
|
944
948
|
});
|
|
945
949
|
}),
|
|
946
|
-
me: protectedProcedure
|
|
947
|
-
.input(z.void())
|
|
950
|
+
me: trpc_middleware_js_1.protectedProcedure
|
|
951
|
+
.input(zod_1.z.void())
|
|
948
952
|
.output(MeSchema)
|
|
949
953
|
.query(({ ctx }) => {
|
|
950
954
|
if (!ctx.user)
|
|
@@ -953,7 +957,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
953
957
|
// hide surfaces from a single probe (F1 #5). Admins summarise to
|
|
954
958
|
// "everything"; a scoped principal's selectors expand to counts.
|
|
955
959
|
const fleet = ctx.deviceFleet?.() ?? [];
|
|
956
|
-
const scope = summarizeEffectiveScope(ctx.user.scopes ?? [], fleet, ctx.user.isAdmin);
|
|
960
|
+
const scope = (0, types_1.summarizeEffectiveScope)(ctx.user.scopes ?? [], fleet, ctx.user.isAdmin);
|
|
957
961
|
return { ...ctx.user, scope };
|
|
958
962
|
}),
|
|
959
963
|
/**
|
|
@@ -977,13 +981,13 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
977
981
|
* and the answer is "everything", which is what the panel must show
|
|
978
982
|
* when the operator ticks the Admin box.
|
|
979
983
|
*/
|
|
980
|
-
previewScope: adminProcedure
|
|
981
|
-
.input(z.object({
|
|
982
|
-
scopes: z.array(TokenScopeSchema),
|
|
983
|
-
isAdmin: z.boolean().default(false),
|
|
984
|
+
previewScope: trpc_middleware_js_1.adminProcedure
|
|
985
|
+
.input(zod_1.z.object({
|
|
986
|
+
scopes: zod_1.z.array(types_1.TokenScopeSchema),
|
|
987
|
+
isAdmin: zod_1.z.boolean().default(false),
|
|
984
988
|
}))
|
|
985
989
|
.output(EffectiveScopeSchema)
|
|
986
|
-
.query(({ ctx, input }) => summarizeEffectiveScope(input.scopes, ctx.deviceFleet?.() ?? [], input.isAdmin)),
|
|
990
|
+
.query(({ ctx, input }) => (0, types_1.summarizeEffectiveScope)(input.scopes, ctx.deviceFleet?.() ?? [], input.isAdmin)),
|
|
987
991
|
// ── Self-service profile operations ───────────────────────────────
|
|
988
992
|
//
|
|
989
993
|
// These route through the `user-management` capability provider but
|
|
@@ -996,18 +1000,18 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
996
1000
|
// them directly here is fine. The trpc admin-gate on the cap router
|
|
997
1001
|
// exists only to block third-party tampering — operators acting on
|
|
998
1002
|
// themselves bypass it intentionally.
|
|
999
|
-
changeOwnPassword: protectedProcedure
|
|
1000
|
-
.input(z.object({
|
|
1001
|
-
currentPassword: z.string().min(1),
|
|
1002
|
-
newPassword: z.string().min(8),
|
|
1003
|
+
changeOwnPassword: trpc_middleware_js_1.protectedProcedure
|
|
1004
|
+
.input(zod_1.z.object({
|
|
1005
|
+
currentPassword: zod_1.z.string().min(1),
|
|
1006
|
+
newPassword: zod_1.z.string().min(8),
|
|
1003
1007
|
}))
|
|
1004
|
-
.output(z.object({ success: z.literal(true) }))
|
|
1008
|
+
.output(zod_1.z.object({ success: zod_1.z.literal(true) }))
|
|
1005
1009
|
.mutation(async ({ input, ctx }) => {
|
|
1006
1010
|
const userMgmt = registry?.getSingleton('user-management');
|
|
1007
1011
|
if (!userMgmt)
|
|
1008
1012
|
throw new Error('user-management capability not available');
|
|
1009
1013
|
if (!ctx.user)
|
|
1010
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1014
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1011
1015
|
// Re-validate the current password against the live store to
|
|
1012
1016
|
// confirm session identity → password ownership match. Stops a
|
|
1013
1017
|
// stolen session-token from rotating credentials silently.
|
|
@@ -1019,7 +1023,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1019
1023
|
throw new Error('Current password is incorrect');
|
|
1020
1024
|
// Hub-internal: the password changes AND every other session of the
|
|
1021
1025
|
// user ends (this one stays signed in).
|
|
1022
|
-
const internal = registry === null ? null : userManagementInternal(registry);
|
|
1026
|
+
const internal = registry === null ? null : (0, hub_sessions_js_1.userManagementInternal)(registry);
|
|
1023
1027
|
if (internal === null)
|
|
1024
1028
|
throw new Error('user-management capability not available');
|
|
1025
1029
|
await internal.setPassword({
|
|
@@ -1029,44 +1033,44 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1029
1033
|
});
|
|
1030
1034
|
return { success: true };
|
|
1031
1035
|
}),
|
|
1032
|
-
setupOwnTotp: protectedProcedure
|
|
1033
|
-
.input(z.void())
|
|
1034
|
-
.output(z.object({ secret: z.string(), otpauthUrl: z.string() }))
|
|
1036
|
+
setupOwnTotp: trpc_middleware_js_1.protectedProcedure
|
|
1037
|
+
.input(zod_1.z.void())
|
|
1038
|
+
.output(zod_1.z.object({ secret: zod_1.z.string(), otpauthUrl: zod_1.z.string() }))
|
|
1035
1039
|
.mutation(async ({ ctx }) => {
|
|
1036
1040
|
const userMgmt = registry?.getSingleton('user-management');
|
|
1037
1041
|
if (!userMgmt)
|
|
1038
1042
|
throw new Error('user-management capability not available');
|
|
1039
1043
|
if (!ctx.user)
|
|
1040
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1044
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1041
1045
|
return userMgmt.setupTotp({ userId: ctx.user.id });
|
|
1042
1046
|
}),
|
|
1043
|
-
confirmOwnTotp: protectedProcedure
|
|
1044
|
-
.input(z.object({ code: z.string().min(1) }))
|
|
1045
|
-
.output(z.object({ success: z.literal(true) }))
|
|
1047
|
+
confirmOwnTotp: trpc_middleware_js_1.protectedProcedure
|
|
1048
|
+
.input(zod_1.z.object({ code: zod_1.z.string().min(1) }))
|
|
1049
|
+
.output(zod_1.z.object({ success: zod_1.z.literal(true) }))
|
|
1046
1050
|
.mutation(async ({ input, ctx }) => {
|
|
1047
1051
|
const userMgmt = registry?.getSingleton('user-management');
|
|
1048
1052
|
if (!userMgmt)
|
|
1049
1053
|
throw new Error('user-management capability not available');
|
|
1050
1054
|
if (!ctx.user)
|
|
1051
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1055
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1052
1056
|
return userMgmt.confirmTotp({ userId: ctx.user.id, code: input.code });
|
|
1053
1057
|
}),
|
|
1054
|
-
disableOwnTotp: protectedProcedure
|
|
1058
|
+
disableOwnTotp: trpc_middleware_js_1.protectedProcedure
|
|
1055
1059
|
// Re-authentication required: a session alone must not strip 2FA.
|
|
1056
|
-
.input(z.object({ reauthToken: ReauthTokenInput }).optional())
|
|
1057
|
-
.output(z.object({ success: z.literal(true) }))
|
|
1060
|
+
.input(zod_1.z.object({ reauthToken: auth_reauth_procedures_js_1.ReauthTokenInput }).optional())
|
|
1061
|
+
.output(zod_1.z.object({ success: zod_1.z.literal(true) }))
|
|
1058
1062
|
.mutation(async ({ ctx, input }) => {
|
|
1059
|
-
assertReauthenticated(auth, ctx.user, input?.reauthToken);
|
|
1063
|
+
(0, auth_reauth_procedures_js_1.assertReauthenticated)(auth, ctx.user, input?.reauthToken);
|
|
1060
1064
|
const userMgmt = registry?.getSingleton('user-management');
|
|
1061
1065
|
if (!userMgmt)
|
|
1062
1066
|
throw new Error('user-management capability not available');
|
|
1063
1067
|
if (!ctx.user)
|
|
1064
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1068
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1065
1069
|
return userMgmt.disableTotp({ userId: ctx.user.id });
|
|
1066
1070
|
}),
|
|
1067
|
-
getOwnTotpStatus: protectedProcedure
|
|
1068
|
-
.input(z.void())
|
|
1069
|
-
.output(z.object({ enabled: z.boolean(), confirmedAt: z.number().nullable() }))
|
|
1071
|
+
getOwnTotpStatus: trpc_middleware_js_1.protectedProcedure
|
|
1072
|
+
.input(zod_1.z.void())
|
|
1073
|
+
.output(zod_1.z.object({ enabled: zod_1.z.boolean(), confirmedAt: zod_1.z.number().nullable() }))
|
|
1070
1074
|
.query(async ({ ctx }) => {
|
|
1071
1075
|
const userMgmt = registry?.getSingleton('user-management');
|
|
1072
1076
|
if (!userMgmt || !ctx.user)
|
|
@@ -1081,24 +1085,24 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1081
1085
|
// THEIR OWN passkeys — the router is the trust boundary, exactly like
|
|
1082
1086
|
// the TOTP self-service block above. Cap-agnostic: resolved through
|
|
1083
1087
|
// the `user-passkeys` cap, never an addon id.
|
|
1084
|
-
beginOwnPasskeyRegistration: protectedProcedure
|
|
1085
|
-
.input(z.void())
|
|
1086
|
-
.output(OptionsJsonSchema)
|
|
1088
|
+
beginOwnPasskeyRegistration: trpc_middleware_js_1.protectedProcedure
|
|
1089
|
+
.input(zod_1.z.void())
|
|
1090
|
+
.output(passkey_provider_js_1.OptionsJsonSchema)
|
|
1087
1091
|
.mutation(async ({ ctx }) => {
|
|
1088
1092
|
if (!ctx.user)
|
|
1089
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1090
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
1093
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1094
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
1091
1095
|
if (!provider)
|
|
1092
1096
|
throw new Error('Passkey enrollment is not available');
|
|
1093
1097
|
return provider.beginRegistration({ userId: ctx.user.id, username: ctx.user.username });
|
|
1094
1098
|
}),
|
|
1095
|
-
finishOwnPasskeyRegistration: protectedProcedure
|
|
1096
|
-
.input(z.object({ response: z.record(z.string(), z.unknown()), label: z.string() }))
|
|
1097
|
-
.output(FinishRegistrationSchema)
|
|
1099
|
+
finishOwnPasskeyRegistration: trpc_middleware_js_1.protectedProcedure
|
|
1100
|
+
.input(zod_1.z.object({ response: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()), label: zod_1.z.string() }))
|
|
1101
|
+
.output(passkey_provider_js_1.FinishRegistrationSchema)
|
|
1098
1102
|
.mutation(async ({ input, ctx }) => {
|
|
1099
1103
|
if (!ctx.user)
|
|
1100
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1101
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
1104
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1105
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
1102
1106
|
if (!provider)
|
|
1103
1107
|
throw new Error('Passkey enrollment is not available');
|
|
1104
1108
|
return provider.finishRegistration({
|
|
@@ -1107,13 +1111,13 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1107
1111
|
label: input.label,
|
|
1108
1112
|
});
|
|
1109
1113
|
}),
|
|
1110
|
-
listOwnPasskeys: protectedProcedure
|
|
1111
|
-
.input(z.void())
|
|
1112
|
-
.output(z.array(PasskeySummarySchema))
|
|
1114
|
+
listOwnPasskeys: trpc_middleware_js_1.protectedProcedure
|
|
1115
|
+
.input(zod_1.z.void())
|
|
1116
|
+
.output(zod_1.z.array(types_1.PasskeySummarySchema))
|
|
1113
1117
|
.query(async ({ ctx }) => {
|
|
1114
1118
|
if (!ctx.user)
|
|
1115
1119
|
return [];
|
|
1116
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
1120
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
1117
1121
|
if (!provider)
|
|
1118
1122
|
return [];
|
|
1119
1123
|
try {
|
|
@@ -1123,15 +1127,15 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1123
1127
|
return [];
|
|
1124
1128
|
}
|
|
1125
1129
|
}),
|
|
1126
|
-
removeOwnPasskey: protectedProcedure
|
|
1130
|
+
removeOwnPasskey: trpc_middleware_js_1.protectedProcedure
|
|
1127
1131
|
// Re-authentication required: removing a passkey can strip a factor.
|
|
1128
|
-
.input(z.object({ credentialId: z.string(), reauthToken: ReauthTokenInput.optional() }))
|
|
1129
|
-
.output(z.object({ success: z.literal(true) }))
|
|
1132
|
+
.input(zod_1.z.object({ credentialId: zod_1.z.string(), reauthToken: auth_reauth_procedures_js_1.ReauthTokenInput.optional() }))
|
|
1133
|
+
.output(zod_1.z.object({ success: zod_1.z.literal(true) }))
|
|
1130
1134
|
.mutation(async ({ input, ctx }) => {
|
|
1131
1135
|
if (!ctx.user)
|
|
1132
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1133
|
-
assertReauthenticated(auth, ctx.user, input.reauthToken);
|
|
1134
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
1136
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1137
|
+
(0, auth_reauth_procedures_js_1.assertReauthenticated)(auth, ctx.user, input.reauthToken);
|
|
1138
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
1135
1139
|
if (!provider)
|
|
1136
1140
|
throw new Error('Passkey management is not available');
|
|
1137
1141
|
return provider.removePasskey({ userId: ctx.user.id, credentialId: input.credentialId });
|
|
@@ -1144,13 +1148,13 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1144
1148
|
* self-service block; reads degrade to `enabled: false` so the "My
|
|
1145
1149
|
* access" page renders even while the provider is booting.
|
|
1146
1150
|
*/
|
|
1147
|
-
getOwnPasskeySecondFactorPreference: protectedProcedure
|
|
1148
|
-
.input(z.void())
|
|
1149
|
-
.output(SecondFactorPreferenceSchema)
|
|
1151
|
+
getOwnPasskeySecondFactorPreference: trpc_middleware_js_1.protectedProcedure
|
|
1152
|
+
.input(zod_1.z.void())
|
|
1153
|
+
.output(passkey_provider_js_1.SecondFactorPreferenceSchema)
|
|
1150
1154
|
.query(async ({ ctx }) => {
|
|
1151
1155
|
if (!ctx.user)
|
|
1152
1156
|
return { enabled: false };
|
|
1153
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
1157
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
1154
1158
|
if (!provider)
|
|
1155
1159
|
return { enabled: false };
|
|
1156
1160
|
try {
|
|
@@ -1160,13 +1164,13 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1160
1164
|
return { enabled: false };
|
|
1161
1165
|
}
|
|
1162
1166
|
}),
|
|
1163
|
-
setOwnPasskeySecondFactorPreference: protectedProcedure
|
|
1164
|
-
.input(z.object({ enabled: z.boolean() }))
|
|
1165
|
-
.output(SetSecondFactorPreferenceSchema)
|
|
1167
|
+
setOwnPasskeySecondFactorPreference: trpc_middleware_js_1.protectedProcedure
|
|
1168
|
+
.input(zod_1.z.object({ enabled: zod_1.z.boolean() }))
|
|
1169
|
+
.output(passkey_provider_js_1.SetSecondFactorPreferenceSchema)
|
|
1166
1170
|
.mutation(async ({ input, ctx }) => {
|
|
1167
1171
|
if (!ctx.user)
|
|
1168
|
-
throw userError('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1169
|
-
const provider = resolvePasskeyProvider(registry, moleculer);
|
|
1172
|
+
throw (0, types_2.userError)('auth.not-authenticated', undefined, 'Not authenticated');
|
|
1173
|
+
const provider = (0, passkey_provider_js_1.resolvePasskeyProvider)(registry, moleculer);
|
|
1170
1174
|
if (!provider)
|
|
1171
1175
|
throw new Error('Passkey management is not available');
|
|
1172
1176
|
return provider.setSecondFactorPreference({
|
|
@@ -1179,9 +1183,9 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1179
1183
|
// or regular); the resulting `csv_*` token authenticates as a
|
|
1180
1184
|
// restricted `share-view` principal limited to the embed surface
|
|
1181
1185
|
// + its in-scope devices (see `share-view-access.ts`). ──────────
|
|
1182
|
-
createShareToken: protectedProcedure
|
|
1186
|
+
createShareToken: trpc_middleware_js_1.protectedProcedure
|
|
1183
1187
|
.input(CreateShareTokenInputSchema)
|
|
1184
|
-
.output(z.object({ id: z.string(), token: z.string(), expiresAt: z.number().nullable() }))
|
|
1188
|
+
.output(zod_1.z.object({ id: zod_1.z.string(), token: zod_1.z.string(), expiresAt: zod_1.z.number().nullable() }))
|
|
1185
1189
|
.mutation(async ({ input, ctx }) => {
|
|
1186
1190
|
assertRealUserSession(ctx.user);
|
|
1187
1191
|
const service = requireShareTokens();
|
|
@@ -1198,10 +1202,10 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1198
1202
|
? input.scope
|
|
1199
1203
|
: {
|
|
1200
1204
|
...input.scope,
|
|
1201
|
-
deviceIds: filterViewableDeviceIds(ctx.user.scopes ?? [], input.scope.deviceIds, ctx.deviceScopeLookup),
|
|
1205
|
+
deviceIds: (0, principal_visibility_js_1.filterViewableDeviceIds)(ctx.user.scopes ?? [], input.scope.deviceIds, ctx.deviceScopeLookup),
|
|
1202
1206
|
};
|
|
1203
1207
|
if (scope.deviceIds.length === 0) {
|
|
1204
|
-
throw new TRPCError({
|
|
1208
|
+
throw new server_1.TRPCError({
|
|
1205
1209
|
code: 'FORBIDDEN',
|
|
1206
1210
|
message: 'None of the requested devices are within your scope — you cannot mint a share token for devices you cannot see',
|
|
1207
1211
|
});
|
|
@@ -1218,12 +1222,12 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1218
1222
|
* Home Assistant embed cache so a long-lived dashboard does not mint a
|
|
1219
1223
|
* new row every hour. Expired / missing → NOT_FOUND (caller must create).
|
|
1220
1224
|
*/
|
|
1221
|
-
extendShareToken: protectedProcedure
|
|
1222
|
-
.input(z.object({
|
|
1223
|
-
id: z.string().min(1),
|
|
1224
|
-
ttlSec: z.number().int().min(SHARE_TOKEN_TTL_MIN_SEC).max(SHARE_TOKEN_TTL_MAX_SEC),
|
|
1225
|
+
extendShareToken: trpc_middleware_js_1.protectedProcedure
|
|
1226
|
+
.input(zod_1.z.object({
|
|
1227
|
+
id: zod_1.z.string().min(1),
|
|
1228
|
+
ttlSec: zod_1.z.number().int().min(share_token_service_js_1.SHARE_TOKEN_TTL_MIN_SEC).max(share_token_service_js_1.SHARE_TOKEN_TTL_MAX_SEC),
|
|
1225
1229
|
}))
|
|
1226
|
-
.output(z.object({ id: z.string(), expiresAt: z.number() }))
|
|
1230
|
+
.output(zod_1.z.object({ id: zod_1.z.string(), expiresAt: zod_1.z.number() }))
|
|
1227
1231
|
.mutation(async ({ input, ctx }) => {
|
|
1228
1232
|
assertRealUserSession(ctx.user);
|
|
1229
1233
|
const service = requireShareTokens();
|
|
@@ -1235,24 +1239,24 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1235
1239
|
callerIsAdmin: ctx.user.isAdmin,
|
|
1236
1240
|
});
|
|
1237
1241
|
if (record.expiresAt === null) {
|
|
1238
|
-
throw trpcUserError('BAD_REQUEST', 'auth.share-never-expiring-extend', undefined, 'A never-expiring share token cannot be extended');
|
|
1242
|
+
throw (0, user_error_js_1.trpcUserError)('BAD_REQUEST', 'auth.share-never-expiring-extend', undefined, 'A never-expiring share token cannot be extended');
|
|
1239
1243
|
}
|
|
1240
1244
|
return { id: record.id, expiresAt: record.expiresAt };
|
|
1241
1245
|
}
|
|
1242
1246
|
catch (error) {
|
|
1243
1247
|
const message = error instanceof Error ? error.message : 'Share token extend failed';
|
|
1244
1248
|
if (/not found|expired/i.test(message)) {
|
|
1245
|
-
throw new TRPCError({ code: 'NOT_FOUND', message });
|
|
1249
|
+
throw new server_1.TRPCError({ code: 'NOT_FOUND', message });
|
|
1246
1250
|
}
|
|
1247
1251
|
if (/owner or an admin|never-expiring/i.test(message)) {
|
|
1248
|
-
throw new TRPCError({ code: 'FORBIDDEN', message });
|
|
1252
|
+
throw new server_1.TRPCError({ code: 'FORBIDDEN', message });
|
|
1249
1253
|
}
|
|
1250
|
-
throw new TRPCError({ code: 'BAD_REQUEST', message });
|
|
1254
|
+
throw new server_1.TRPCError({ code: 'BAD_REQUEST', message });
|
|
1251
1255
|
}
|
|
1252
1256
|
}),
|
|
1253
|
-
revokeShareToken: protectedProcedure
|
|
1254
|
-
.input(z.object({ id: z.string().min(1) }))
|
|
1255
|
-
.output(z.object({ success: z.boolean() }))
|
|
1257
|
+
revokeShareToken: trpc_middleware_js_1.protectedProcedure
|
|
1258
|
+
.input(zod_1.z.object({ id: zod_1.z.string().min(1) }))
|
|
1259
|
+
.output(zod_1.z.object({ success: zod_1.z.boolean() }))
|
|
1256
1260
|
.mutation(async ({ input, ctx }) => {
|
|
1257
1261
|
assertRealUserSession(ctx.user);
|
|
1258
1262
|
const service = requireShareTokens();
|
|
@@ -1263,7 +1267,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1263
1267
|
callerIsAdmin: ctx.user.isAdmin,
|
|
1264
1268
|
});
|
|
1265
1269
|
if (removed) {
|
|
1266
|
-
const internal = registry === null ? null : userManagementInternal(registry);
|
|
1270
|
+
const internal = registry === null ? null : (0, hub_sessions_js_1.userManagementInternal)(registry);
|
|
1267
1271
|
if (internal !== null) {
|
|
1268
1272
|
const ip = network.clientAddress(ctx.req).ip;
|
|
1269
1273
|
await internal.audit.record({
|
|
@@ -1283,7 +1287,7 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1283
1287
|
return { success: removed };
|
|
1284
1288
|
}
|
|
1285
1289
|
catch (error) {
|
|
1286
|
-
throw new TRPCError({
|
|
1290
|
+
throw new server_1.TRPCError({
|
|
1287
1291
|
code: 'FORBIDDEN',
|
|
1288
1292
|
message: error instanceof Error ? error.message : 'Share token revoke failed',
|
|
1289
1293
|
});
|
|
@@ -1294,15 +1298,15 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1294
1298
|
* `owner: 'all'` — every user's, admin only. Omitted keeps the original
|
|
1295
1299
|
* answer (own for a user, all for an admin) for clients that predate it.
|
|
1296
1300
|
*/
|
|
1297
|
-
listShareTokens: protectedProcedure
|
|
1298
|
-
.input(z.object({ owner: z.enum(['self', 'all']).optional() }).optional())
|
|
1299
|
-
.output(z.array(ShareTokenSummarySchema))
|
|
1301
|
+
listShareTokens: trpc_middleware_js_1.protectedProcedure
|
|
1302
|
+
.input(zod_1.z.object({ owner: zod_1.z.enum(['self', 'all']).optional() }).optional())
|
|
1303
|
+
.output(zod_1.z.array(ShareTokenSummarySchema))
|
|
1300
1304
|
.query(async ({ ctx, input }) => {
|
|
1301
1305
|
assertRealUserSession(ctx.user);
|
|
1302
1306
|
const service = requireShareTokens();
|
|
1303
1307
|
const owner = input?.owner ?? (ctx.user.isAdmin ? 'all' : 'self');
|
|
1304
1308
|
if (owner === 'all' && !ctx.user.isAdmin) {
|
|
1305
|
-
throw new TRPCError({
|
|
1309
|
+
throw new server_1.TRPCError({
|
|
1306
1310
|
code: 'FORBIDDEN',
|
|
1307
1311
|
message: "Listing every user's share links requires an admin",
|
|
1308
1312
|
});
|
|
@@ -1310,11 +1314,11 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1310
1314
|
const records = owner === 'all' ? await service.listAll() : await service.listForUser(ctx.user.id);
|
|
1311
1315
|
return records.map(toShareTokenSummary);
|
|
1312
1316
|
}),
|
|
1313
|
-
...createSessionProcedures({ registry, minter, credentialProcedure }),
|
|
1314
|
-
...createDeviceCertProcedures({
|
|
1317
|
+
...(0, auth_sessions_procedures_js_1.createSessionProcedures)({ registry, minter, credentialProcedure }),
|
|
1318
|
+
...(0, auth_device_cert_procedures_js_1.createDeviceCertProcedures)({
|
|
1315
1319
|
registry,
|
|
1316
1320
|
minter,
|
|
1317
|
-
publicProcedure,
|
|
1321
|
+
publicProcedure: trpc_middleware_js_1.publicProcedure,
|
|
1318
1322
|
auth,
|
|
1319
1323
|
credentialLimiter: limiters.credential,
|
|
1320
1324
|
ceremonyLimiter: limiters.ceremony,
|
|
@@ -1326,9 +1330,9 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1326
1330
|
resolveOrigin: resolveDeviceOrigin,
|
|
1327
1331
|
issueFor,
|
|
1328
1332
|
}),
|
|
1329
|
-
...createReauthProcedures({ auth, registry, moleculer, limiters }),
|
|
1330
|
-
...createAdminTokenProcedures({ auth, registry, network }),
|
|
1331
|
-
...createRevokeCredentialsProcedures({ registry, shareTokens, network }),
|
|
1333
|
+
...(0, auth_reauth_procedures_js_1.createReauthProcedures)({ auth, registry, moleculer, limiters }),
|
|
1334
|
+
...(0, auth_admin_tokens_procedures_js_1.createAdminTokenProcedures)({ auth, registry, network }),
|
|
1335
|
+
...(0, auth_revoke_credentials_procedures_js_1.createRevokeCredentialsProcedures)({ registry, shareTokens, network }),
|
|
1332
1336
|
// ── External sign-in identities (D782) ────────────────────────
|
|
1333
1337
|
//
|
|
1334
1338
|
// A signed-in user links an OIDC identity to THEIR OWN account. The
|
|
@@ -1336,9 +1340,9 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1336
1340
|
// which also requires the same user's session cookie — the user id never
|
|
1337
1341
|
// travels through the browser.
|
|
1338
1342
|
/** Sign-in providers the caller can link (redirect methods declaring `linkable`). */
|
|
1339
|
-
listLinkableProviders: protectedProcedure
|
|
1340
|
-
.input(z.void())
|
|
1341
|
-
.output(z.array(z.object({ provider: z.string(), label: z.string() })))
|
|
1343
|
+
listLinkableProviders: trpc_middleware_js_1.protectedProcedure
|
|
1344
|
+
.input(zod_1.z.void())
|
|
1345
|
+
.output(zod_1.z.array(zod_1.z.object({ provider: zod_1.z.string(), label: zod_1.z.string() })))
|
|
1342
1346
|
.query(async () => (await linkableProviders()).map(({ provider, label }) => ({ provider, label }))),
|
|
1343
1347
|
/**
|
|
1344
1348
|
* Start linking `provider` to the caller; the client navigates to `url`.
|
|
@@ -1346,33 +1350,33 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1346
1350
|
* (`APP_AUTH_CALLBACK_URLS`); the finish then parks the link for the app
|
|
1347
1351
|
* to claim with `completeExternalLink` instead of needing a session cookie.
|
|
1348
1352
|
*/
|
|
1349
|
-
beginExternalLink: protectedProcedure
|
|
1350
|
-
.input(z.object({
|
|
1351
|
-
provider: z.string().min(1),
|
|
1352
|
-
returnTo: z.string().optional(),
|
|
1353
|
+
beginExternalLink: trpc_middleware_js_1.protectedProcedure
|
|
1354
|
+
.input(zod_1.z.object({
|
|
1355
|
+
provider: zod_1.z.string().min(1),
|
|
1356
|
+
returnTo: zod_1.z.string().optional(),
|
|
1353
1357
|
/** From `auth.reauthenticate` — linking needs a fresh proof, not just a session. */
|
|
1354
|
-
reauthToken: ReauthTokenInput.optional(),
|
|
1358
|
+
reauthToken: auth_reauth_procedures_js_1.ReauthTokenInput.optional(),
|
|
1355
1359
|
}))
|
|
1356
|
-
.output(z.object({ url: z.string() }))
|
|
1360
|
+
.output(zod_1.z.object({ url: zod_1.z.string() }))
|
|
1357
1361
|
.mutation(async ({ ctx, input }) => {
|
|
1358
1362
|
if (!ctx.user)
|
|
1359
|
-
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
1363
|
+
throw new server_1.TRPCError({ code: 'UNAUTHORIZED' });
|
|
1360
1364
|
assertRealUserSession(ctx.user, 'Linking a sign-in account');
|
|
1361
1365
|
// Per user AND per client: each call mints an entry in a bounded
|
|
1362
1366
|
// shared map, so a flood must not evict other users' pending links.
|
|
1363
|
-
limitByUser(limiters.link, 'auth.beginExternalLink', ctx.user.id);
|
|
1364
|
-
limitByClient(limiters.ceremony, 'auth.beginExternalLink', ctx.req, network);
|
|
1365
|
-
assertReauthenticated(auth, ctx.user, input.reauthToken);
|
|
1366
|
-
const returnTo = input.returnTo === undefined ? undefined : parseAppAuthCallback(input.returnTo);
|
|
1367
|
+
(0, auth_limits_js_1.limitByUser)(limiters.link, 'auth.beginExternalLink', ctx.user.id);
|
|
1368
|
+
(0, auth_limits_js_1.limitByClient)(limiters.ceremony, 'auth.beginExternalLink', ctx.req, network);
|
|
1369
|
+
(0, auth_reauth_procedures_js_1.assertReauthenticated)(auth, ctx.user, input.reauthToken);
|
|
1370
|
+
const returnTo = input.returnTo === undefined ? undefined : (0, types_1.parseAppAuthCallback)(input.returnTo);
|
|
1367
1371
|
if (returnTo === null) {
|
|
1368
|
-
throw new TRPCError({
|
|
1372
|
+
throw new server_1.TRPCError({
|
|
1369
1373
|
code: 'BAD_REQUEST',
|
|
1370
1374
|
message: 'returnTo is not an allowed app callback',
|
|
1371
1375
|
});
|
|
1372
1376
|
}
|
|
1373
1377
|
const target = (await linkableProviders()).find((p) => p.provider === input.provider);
|
|
1374
1378
|
if (target === undefined) {
|
|
1375
|
-
throw new TRPCError({
|
|
1379
|
+
throw new server_1.TRPCError({
|
|
1376
1380
|
code: 'BAD_REQUEST',
|
|
1377
1381
|
message: `Sign-in provider "${input.provider}" is not available for linking`,
|
|
1378
1382
|
});
|
|
@@ -1388,17 +1392,17 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1388
1392
|
* whatever the outcome.
|
|
1389
1393
|
*/
|
|
1390
1394
|
completeExternalLink: selfCodeProcedure
|
|
1391
|
-
.input(z.object({ code: z.string().min(1).max(256) }))
|
|
1392
|
-
.output(z.object({
|
|
1393
|
-
outcome: z.enum(['linked', 'conflict', 'expired', 'session']),
|
|
1394
|
-
provider: z.string().optional(),
|
|
1395
|
+
.input(zod_1.z.object({ code: zod_1.z.string().min(1).max(256) }))
|
|
1396
|
+
.output(zod_1.z.object({
|
|
1397
|
+
outcome: zod_1.z.enum(['linked', 'conflict', 'expired', 'session']),
|
|
1398
|
+
provider: zod_1.z.string().optional(),
|
|
1395
1399
|
}))
|
|
1396
1400
|
.mutation(async ({ ctx, input }) => {
|
|
1397
1401
|
if (!ctx.user)
|
|
1398
|
-
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
1402
|
+
throw new server_1.TRPCError({ code: 'UNAUTHORIZED' });
|
|
1399
1403
|
assertRealUserSession(ctx.user, 'Linking a sign-in account');
|
|
1400
1404
|
if (nativeLink === null) {
|
|
1401
|
-
throw new TRPCError({
|
|
1405
|
+
throw new server_1.TRPCError({
|
|
1402
1406
|
code: 'PRECONDITION_FAILED',
|
|
1403
1407
|
message: 'Native linking is not available',
|
|
1404
1408
|
});
|
|
@@ -1418,14 +1422,14 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1418
1422
|
* lands on that page only: the route takes no destination.
|
|
1419
1423
|
*/
|
|
1420
1424
|
createBrowserHandoff: selfCodeProcedure
|
|
1421
|
-
.input(z.void())
|
|
1422
|
-
.output(z.object({ path: z.string(), expiresAt: z.number() }))
|
|
1425
|
+
.input(zod_1.z.void())
|
|
1426
|
+
.output(zod_1.z.object({ path: zod_1.z.string(), expiresAt: zod_1.z.number() }))
|
|
1423
1427
|
.mutation(({ ctx }) => {
|
|
1424
1428
|
if (!ctx.user)
|
|
1425
|
-
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
1429
|
+
throw new server_1.TRPCError({ code: 'UNAUTHORIZED' });
|
|
1426
1430
|
assertRealUserSession(ctx.user, 'Opening the account page in a browser');
|
|
1427
1431
|
if (nativeLink === null) {
|
|
1428
|
-
throw new TRPCError({
|
|
1432
|
+
throw new server_1.TRPCError({
|
|
1429
1433
|
code: 'PRECONDITION_FAILED',
|
|
1430
1434
|
message: 'Browser handoff is not available',
|
|
1431
1435
|
});
|
|
@@ -1435,12 +1439,12 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1435
1439
|
purpose: 'new-session',
|
|
1436
1440
|
...(parentCredential !== undefined ? { credentialId: parentCredential } : {}),
|
|
1437
1441
|
});
|
|
1438
|
-
return { path: `${BROWSER_HANDOFF_PATH}?code=${encodeURIComponent(code)}`, expiresAt };
|
|
1442
|
+
return { path: `${exports.BROWSER_HANDOFF_PATH}?code=${encodeURIComponent(code)}`, expiresAt };
|
|
1439
1443
|
}),
|
|
1440
1444
|
/** The caller's linked identities; `available: false` when the provider instance is gone or off. */
|
|
1441
|
-
listOwnExternalIdentities: protectedProcedure
|
|
1442
|
-
.input(z.void())
|
|
1443
|
-
.output(z.array(OwnExternalIdentitySchema))
|
|
1445
|
+
listOwnExternalIdentities: trpc_middleware_js_1.protectedProcedure
|
|
1446
|
+
.input(zod_1.z.void())
|
|
1447
|
+
.output(zod_1.z.array(OwnExternalIdentitySchema))
|
|
1444
1448
|
.query(async ({ ctx }) => {
|
|
1445
1449
|
if (!ctx.user)
|
|
1446
1450
|
return [];
|
|
@@ -1459,12 +1463,12 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1459
1463
|
}));
|
|
1460
1464
|
}),
|
|
1461
1465
|
/** Remove one of the caller's own links. */
|
|
1462
|
-
unlinkOwnExternalIdentity: protectedProcedure
|
|
1463
|
-
.input(z.object({ provider: z.string().min(1), subject: z.string().min(1) }))
|
|
1464
|
-
.output(z.object({ success: z.boolean() }))
|
|
1466
|
+
unlinkOwnExternalIdentity: trpc_middleware_js_1.protectedProcedure
|
|
1467
|
+
.input(zod_1.z.object({ provider: zod_1.z.string().min(1), subject: zod_1.z.string().min(1) }))
|
|
1468
|
+
.output(zod_1.z.object({ success: zod_1.z.boolean() }))
|
|
1465
1469
|
.mutation(async ({ ctx, input }) => {
|
|
1466
1470
|
if (!ctx.user)
|
|
1467
|
-
throw new TRPCError({ code: 'UNAUTHORIZED' });
|
|
1471
|
+
throw new server_1.TRPCError({ code: 'UNAUTHORIZED' });
|
|
1468
1472
|
assertRealUserSession(ctx.user, 'Unlinking a sign-in account');
|
|
1469
1473
|
const userMgmt = registry?.getSingleton('user-management');
|
|
1470
1474
|
if (!userMgmt)
|
|
@@ -1491,18 +1495,18 @@ export function createAuthRouter(auth, registry, moleculer = null, shareTokens =
|
|
|
1491
1495
|
* `listProviders`' old resilience) so one bad addon can't lock every
|
|
1492
1496
|
* login method out of the UI.
|
|
1493
1497
|
*/
|
|
1494
|
-
listLoginMethods: publicProcedure
|
|
1495
|
-
.input(z.void())
|
|
1496
|
-
.output(z.array(PublicLoginMethodSchema).readonly())
|
|
1498
|
+
listLoginMethods: trpc_middleware_js_1.publicProcedure
|
|
1499
|
+
.input(zod_1.z.void())
|
|
1500
|
+
.output(zod_1.z.array(PublicLoginMethodSchema).readonly())
|
|
1497
1501
|
.query(async () => aggregateLoginMethods()),
|
|
1498
1502
|
/**
|
|
1499
1503
|
* The hub's human name (D861), public like `listLoginMethods` and exposing
|
|
1500
1504
|
* nothing else. A separate method on purpose: `listLoginMethods` stays the bare
|
|
1501
1505
|
* array every installed viewer already parses.
|
|
1502
1506
|
*/
|
|
1503
|
-
getServerName: publicProcedure
|
|
1504
|
-
.input(z.void())
|
|
1505
|
-
.output(ServerNameInfoSchema)
|
|
1507
|
+
getServerName: trpc_middleware_js_1.publicProcedure
|
|
1508
|
+
.input(zod_1.z.void())
|
|
1509
|
+
.output(types_1.ServerNameInfoSchema)
|
|
1506
1510
|
.query(async () => serverNameReader.read()),
|
|
1507
1511
|
});
|
|
1508
1512
|
}
|