@rebasepro/server 0.23.0 → 0.24.1-canary.g19596ef
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/README.md +28 -3
- package/bin/rebase-server.js +4 -2
- package/dist/GCSStorageController-DEga1ULx.js +402 -0
- package/dist/GCSStorageController-DEga1ULx.js.map +1 -0
- package/dist/S3StorageController-Btx-6bJ5.js +480 -0
- package/dist/S3StorageController-Btx-6bJ5.js.map +1 -0
- package/dist/api/ast-schema-editor.d.ts +92 -1
- package/dist/api/errors.d.ts +41 -0
- package/dist/api/live-schema-routes.d.ts +64 -10
- package/dist/api/logs-routes.d.ts +39 -1
- package/dist/api/mount-path.d.ts +30 -0
- package/dist/api/mount.d.ts +6 -13
- package/dist/api/openapi-generator.d.ts +17 -0
- package/dist/api/rest/api-generator.d.ts +97 -11
- package/dist/api/rest/auth-collection-writes.d.ts +28 -21
- package/dist/api/rest/field-access-query.d.ts +28 -8
- package/dist/api/rest/field-ops.d.ts +19 -7
- package/dist/api/rest/query-body.d.ts +10 -0
- package/dist/api/rest/write-validation.d.ts +9 -7
- package/dist/api/schema-editor-routes.d.ts +10 -1
- package/dist/api/sql-export-routes.d.ts +8 -0
- package/dist/api/types.d.ts +52 -1
- package/dist/{ast-schema-editor-Mvr50v_S.js → ast-schema-editor-mCeSC03x.js} +310 -12
- package/dist/ast-schema-editor-mCeSC03x.js.map +1 -0
- package/dist/auth/access.d.ts +156 -0
- package/dist/auth/adapter-middleware.d.ts +2 -1
- package/dist/auth/address-ownership.d.ts +16 -1
- package/dist/auth/admin-roles-route.d.ts +4 -2
- package/dist/auth/admin-roles.d.ts +17 -20
- package/dist/auth/admin-user-ops.d.ts +24 -2
- package/dist/auth/admin-users-route.d.ts +2 -0
- package/dist/auth/api-keys/api-key-middleware.d.ts +64 -56
- package/dist/auth/api-keys/api-key-routes.d.ts +44 -11
- package/dist/auth/api-keys/api-key-store.d.ts +31 -8
- package/dist/auth/api-keys/api-key-types.d.ts +14 -16
- package/dist/auth/api-keys/http-operation.d.ts +19 -0
- package/dist/auth/api-keys/index.d.ts +11 -11
- package/dist/auth/api-keys/key-grant.d.ts +41 -0
- package/dist/auth/api-keys/legacy-permissions.d.ts +33 -0
- package/dist/auth/auth-hooks.d.ts +46 -7
- package/dist/auth/builtin-auth-adapter.d.ts +21 -0
- package/dist/auth/cookie-utils.d.ts +7 -0
- package/dist/auth/deliverable-address.d.ts +6 -0
- package/dist/auth/email-change-routes.d.ts +44 -0
- package/dist/auth/expired-token-sweep.d.ts +71 -0
- package/dist/auth/impersonation.d.ts +110 -0
- package/dist/auth/index.d.ts +4 -2
- package/dist/auth/interfaces.d.ts +120 -59
- package/dist/auth/jwks-routes.d.ts +5 -1
- package/dist/auth/jwt-crypto.d.ts +7 -0
- package/dist/auth/jwt-keys.d.ts +4 -0
- package/dist/auth/jwt.d.ts +319 -157
- package/dist/auth/magic-link-routes.d.ts +5 -6
- package/dist/auth/mfa-crypto.d.ts +9 -3
- package/dist/auth/mfa-gate.d.ts +4 -2
- package/dist/auth/mfa-routes.d.ts +8 -9
- package/dist/auth/middleware.d.ts +26 -7
- package/dist/auth/otp-routes.d.ts +5 -6
- package/dist/auth/passwordless-signup.d.ts +27 -0
- package/dist/auth/platform-token.d.ts +122 -0
- package/dist/auth/rate-limiter.d.ts +99 -31
- package/dist/auth/registration-policy.d.ts +17 -0
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/routes.d.ts +61 -0
- package/dist/auth/scope-routes.d.ts +22 -0
- package/dist/auth/session-routes.d.ts +17 -6
- package/dist/auth/token-revocation.d.ts +56 -1
- package/dist/auth/user-picking.d.ts +37 -0
- package/dist/auth/verify-credential.d.ts +49 -0
- package/dist/{auth-B-GIMpDG.js → auth-CSBky1mt.js} +4564 -1929
- package/dist/auth-CSBky1mt.js.map +1 -0
- package/dist/auth_adapter-CIItCTc8.js +21 -0
- package/dist/auth_adapter-CIItCTc8.js.map +1 -0
- package/dist/backend/create-backend.d.ts +281 -0
- package/dist/backend/default-backend.d.ts +35 -0
- package/dist/backend/no-collections.d.ts +19 -0
- package/dist/backend/options.d.ts +912 -0
- package/dist/backend/scope.d.ts +23 -0
- package/dist/backend/services.d.ts +54 -0
- package/dist/backend-DTAOsLQc.js.map +1 -1
- package/dist/backup/backup-common.d.ts +24 -3
- package/dist/backup/backup-routes.d.ts +46 -5
- package/dist/backup/backup-schedule.d.ts +33 -0
- package/dist/backup/backup-storage.d.ts +16 -0
- package/dist/backup/index.d.ts +5 -1
- package/dist/backup-DBGRUVTS.js +585 -0
- package/dist/backup-DBGRUVTS.js.map +1 -0
- package/dist/boot/boot.d.ts +2 -2
- package/dist/boot/bundle.d.ts +19 -0
- package/dist/boot/driver.d.ts +3 -0
- package/dist/boot/env.d.ts +58 -6
- package/dist/boot/http-server.d.ts +22 -0
- package/dist/boot/options.d.ts +16 -1
- package/dist/boot/provision.d.ts +4 -2
- package/dist/boot/resource-adapters.d.ts +11 -14
- package/dist/boot/runtime-cors.d.ts +17 -0
- package/dist/boot/security-headers.d.ts +26 -0
- package/dist/boot/sources.d.ts +9 -0
- package/dist/boot/static-routing.d.ts +65 -0
- package/dist/collection_patch-BRu-BvDv.js +472 -0
- package/dist/collection_patch-BRu-BvDv.js.map +1 -0
- package/dist/{contract-routes-CbFjuBwa.js → contract-routes-DiFwiLg2.js} +5 -8
- package/dist/contract-routes-DiFwiLg2.js.map +1 -0
- package/dist/cron/cron-loader.d.ts +77 -18
- package/dist/cron/cron-routes.d.ts +1 -1
- package/dist/cron/cron-scheduler.d.ts +94 -23
- package/dist/cron/cron-store.d.ts +37 -5
- package/dist/cron/define-cron.d.ts +6 -2
- package/dist/cron/index.d.ts +3 -3
- package/dist/cron-loader-NHqRfKF0.js +202 -0
- package/dist/cron-loader-NHqRfKF0.js.map +1 -0
- package/dist/{cron-routes-eE8nif_b.js → cron-routes-DsH8Jwn5.js} +34 -8
- package/dist/cron-routes-DsH8Jwn5.js.map +1 -0
- package/dist/{cron-scheduler-B0pLfAix.js → cron-scheduler-D1DT0nw5.js} +349 -65
- package/dist/cron-scheduler-D1DT0nw5.js.map +1 -0
- package/dist/cron-store-DEpVstUU.js +577 -0
- package/dist/cron-store-DEpVstUU.js.map +1 -0
- package/dist/{ddl-bootstrap-C6mo0Kmz.js → ddl-bootstrap-BNqi2NZe.js} +2 -2
- package/dist/{ddl-bootstrap-C6mo0Kmz.js.map → ddl-bootstrap-BNqi2NZe.js.map} +1 -1
- package/dist/email/index.d.ts +2 -2
- package/dist/email/smtp-email-service.d.ts +23 -0
- package/dist/email/templates.d.ts +22 -0
- package/dist/email/types.d.ts +44 -0
- package/dist/env.d.ts +1 -39
- package/dist/{errors-DWsX4yTd.js → errors-Cqp86KnA.js} +263 -10
- package/dist/errors-Cqp86KnA.js.map +1 -0
- package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
- package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
- package/dist/{function-loader-xnbDAPfa.js → function-loader-DbCSoNJj.js} +69 -39
- package/dist/function-loader-DbCSoNJj.js.map +1 -0
- package/dist/{function-routes-Chet4-lB.js → function-routes-BSTClQNa.js} +28 -15
- package/dist/function-routes-BSTClQNa.js.map +1 -0
- package/dist/functions/context.d.ts +26 -6
- package/dist/functions/define-function.d.ts +10 -6
- package/dist/functions/function-loader.d.ts +75 -18
- package/dist/functions/function-routes.d.ts +2 -1
- package/dist/functions/guards.d.ts +22 -5
- package/dist/functions/index.d.ts +6 -5
- package/dist/functions/index.js +148 -50
- package/dist/functions/index.js.map +1 -1
- package/dist/functions/internal.d.ts +2 -2
- package/dist/functions/proxy.d.ts +6 -2
- package/dist/functions/request-timeout.d.ts +7 -5
- package/dist/history/history-routes.d.ts +9 -0
- package/dist/history/retention-sweep.d.ts +81 -0
- package/dist/{history-recorder-B4MpJfJK.js → history-recorder-RZ1Ow4YY.js} +4 -4
- package/dist/{history-recorder-B4MpJfJK.js.map → history-recorder-RZ1Ow4YY.js.map} +1 -1
- package/dist/{history-store-BhxWOuz9.js → history-store-DPofGVDp.js} +2 -2
- package/dist/{history-store-BhxWOuz9.js.map → history-store-DPofGVDp.js.map} +1 -1
- package/dist/index.d.ts +32 -13
- package/dist/index.es.js +25329 -18393
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +35 -10
- package/dist/init/health.d.ts +17 -2
- package/dist/init/process-safety.d.ts +7 -2
- package/dist/init/shutdown.d.ts +26 -1
- package/dist/init.d.ts +49 -811
- package/dist/internal-tables-L2t39RdT.js +136 -0
- package/dist/internal-tables-L2t39RdT.js.map +1 -0
- package/dist/jobs/job-queue.d.ts +8 -0
- package/dist/jobs/job-store.d.ts +24 -0
- package/dist/jobs/types.d.ts +25 -4
- package/dist/{jobs-CazMYhyy.js → jobs-8G-_agld.js} +235 -25
- package/dist/jobs-8G-_agld.js.map +1 -0
- package/dist/{jwt-DnQHNFCl.js → jwt-CBaFc34Y.js} +546 -447
- package/dist/jwt-CBaFc34Y.js.map +1 -0
- package/dist/{keys-CogCQpxG.js → keys-COzQ2aE8.js} +3 -17
- package/dist/{keys-CogCQpxG.js.map → keys-COzQ2aE8.js.map} +1 -1
- package/dist/load-failure-L5hvfDoG.js +80 -0
- package/dist/load-failure-L5hvfDoG.js.map +1 -0
- package/dist/{logger-DO2PZc4i.js → logger-Bt32sHFw.js} +41 -5
- package/dist/logger-Bt32sHFw.js.map +1 -0
- package/dist/{logs-routes-Bj4TYYUl.js → logs-routes-DQJhrf-b.js} +48 -8
- package/dist/logs-routes-DQJhrf-b.js.map +1 -0
- package/dist/mcp/consent-page.d.ts +1 -1
- package/dist/mcp/mcp-routes.d.ts +13 -0
- package/dist/mcp/mcp-tools.d.ts +23 -9
- package/dist/mcp/oauth-metadata.d.ts +21 -16
- package/dist/mcp/oauth-routes.d.ts +14 -1
- package/dist/metrics/index.d.ts +18 -0
- package/dist/metrics/pool-wait.d.ts +50 -0
- package/dist/offline-QNQgsPOq-B2yGeXkn.js +3305 -0
- package/dist/offline-QNQgsPOq-B2yGeXkn.js.map +1 -0
- package/dist/offline-store-Cm5sAX81-CALiO4Gn.js +1915 -0
- package/dist/offline-store-Cm5sAX81-CALiO4Gn.js.map +1 -0
- package/dist/{openapi-generator-O_O24MAT.js → openapi-generator-CeGW2dLC.js} +455 -80
- package/dist/openapi-generator-CeGW2dLC.js.map +1 -0
- package/dist/policy-PdzX-Opd.js +121 -0
- package/dist/policy-PdzX-Opd.js.map +1 -0
- package/dist/project_manifest-R6y_KHms.js +59 -0
- package/dist/project_manifest-R6y_KHms.js.map +1 -0
- package/dist/{proxy-Czngl3p9.js → proxy-BEKbsil6.js} +5 -4
- package/dist/proxy-BEKbsil6.js.map +1 -0
- package/dist/{query-parser-DGRVFNM3.js → query-parser-ECxP0nDw.js} +497 -52
- package/dist/query-parser-ECxP0nDw.js.map +1 -0
- package/dist/{request-timeout-C_4C2BeR.js → request-timeout-BiRelY-U.js} +17 -10
- package/dist/request-timeout-BiRelY-U.js.map +1 -0
- package/dist/resumable-upload-threshold-CKv-Ry0l.js +24 -0
- package/dist/resumable-upload-threshold-CKv-Ry0l.js.map +1 -0
- package/dist/schema-edit/apply-schema-change.d.ts +73 -3
- package/dist/schema-edit/local-source.d.ts +29 -0
- package/dist/schema-edit/project-root.d.ts +3 -2
- package/dist/schema-edit/remote-source.d.ts +20 -5
- package/dist/schema-edit/source-editor.d.ts +28 -0
- package/dist/schema-editor-routes-DRXBAbZy.js +136 -0
- package/dist/schema-editor-routes-DRXBAbZy.js.map +1 -0
- package/dist/serve-spa.d.ts +58 -0
- package/dist/services/outbound-post.d.ts +50 -0
- package/dist/services/outbound-url-guard.d.ts +34 -5
- package/dist/services/routed-realtime-service.d.ts +16 -0
- package/dist/services/webhook-service.d.ts +66 -14
- package/dist/singleton.d.ts +9 -5
- package/dist/soft-delete-params-CBryZXMq.js +668 -0
- package/dist/soft-delete-params-CBryZXMq.js.map +1 -0
- package/dist/sql-export-routes-D8ZaRvoR.js +240 -0
- package/dist/sql-export-routes-D8ZaRvoR.js.map +1 -0
- package/dist/{src-vkcwKXbT.js → src-D5Y3N-S4.js} +440 -20
- package/dist/src-D5Y3N-S4.js.map +1 -0
- package/dist/storage/GCSStorageController.d.ts +48 -2
- package/dist/storage/LocalStorageController.d.ts +69 -2
- package/dist/storage/S3StorageController.d.ts +39 -3
- package/dist/storage/image-transform.d.ts +15 -0
- package/dist/storage/index.d.ts +2 -2
- package/dist/storage/maintenance-routes.d.ts +23 -0
- package/dist/storage/maintenance.d.ts +126 -0
- package/dist/storage/property-limits.d.ts +41 -6
- package/dist/storage/rendition-cache.d.ts +9 -11
- package/dist/storage/request-keys.d.ts +15 -0
- package/dist/storage/request-principals.d.ts +30 -0
- package/dist/storage/requested-object.d.ts +74 -0
- package/dist/storage/routes.d.ts +52 -14
- package/dist/storage/source-variables.d.ts +10 -0
- package/dist/storage/streams.d.ts +42 -0
- package/dist/storage/tus-handler.d.ts +76 -7
- package/dist/storage/types.d.ts +101 -7
- package/dist/storage/upload-validation.d.ts +13 -0
- package/dist/storage-resumable-VO-cMpse-C_YX71pO.js +125 -0
- package/dist/storage-resumable-VO-cMpse-C_YX71pO.js.map +1 -0
- package/dist/strings.es-BeZWAodn.js +256 -0
- package/dist/strings.es-BeZWAodn.js.map +1 -0
- package/dist/upload-validation-CVobI5xO.js +172 -0
- package/dist/upload-validation-CVobI5xO.js.map +1 -0
- package/dist/utils/byte-size.d.ts +10 -0
- package/dist/utils/compression.d.ts +6 -0
- package/dist/utils/load-failure.d.ts +14 -0
- package/dist/utils/logger.d.ts +21 -0
- package/package.json +5 -5
- package/dist/GCSStorageController-CjrA4PMo.js +0 -242
- package/dist/GCSStorageController-CjrA4PMo.js.map +0 -1
- package/dist/S3StorageController-B6pKDNVj.js +0 -264
- package/dist/S3StorageController-B6pKDNVj.js.map +0 -1
- package/dist/admin-roles-vYdp_Pil.js +0 -36
- package/dist/admin-roles-vYdp_Pil.js.map +0 -1
- package/dist/admin_block-DxKLmdiv.js +0 -206
- package/dist/admin_block-DxKLmdiv.js.map +0 -1
- package/dist/ast-schema-editor-Mvr50v_S.js.map +0 -1
- package/dist/auth/api-keys/api-key-permission-guard.d.ts +0 -65
- package/dist/auth-B-GIMpDG.js.map +0 -1
- package/dist/backup-D7YR94N3.js +0 -253
- package/dist/backup-D7YR94N3.js.map +0 -1
- package/dist/contract-routes-CbFjuBwa.js.map +0 -1
- package/dist/cron-loader-DfTj2Hbi.js +0 -118
- package/dist/cron-loader-DfTj2Hbi.js.map +0 -1
- package/dist/cron-routes-eE8nif_b.js.map +0 -1
- package/dist/cron-scheduler-B0pLfAix.js.map +0 -1
- package/dist/cron-store-TcoGz-xS.js +0 -305
- package/dist/cron-store-TcoGz-xS.js.map +0 -1
- package/dist/dynamic-import-X40pTZUQ.js +0 -23
- package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
- package/dist/errors-DWsX4yTd.js.map +0 -1
- package/dist/function-loader-xnbDAPfa.js.map +0 -1
- package/dist/function-routes-Chet4-lB.js.map +0 -1
- package/dist/jobs-CazMYhyy.js.map +0 -1
- package/dist/jwt-DnQHNFCl.js.map +0 -1
- package/dist/logger-DO2PZc4i.js.map +0 -1
- package/dist/logs-routes-Bj4TYYUl.js.map +0 -1
- package/dist/openapi-generator-O_O24MAT.js.map +0 -1
- package/dist/proxy-Czngl3p9.js.map +0 -1
- package/dist/query-parser-DGRVFNM3.js.map +0 -1
- package/dist/request-timeout-C_4C2BeR.js.map +0 -1
- package/dist/schema-editor-routes-C5-lh_jO.js +0 -87
- package/dist/schema-editor-routes-C5-lh_jO.js.map +0 -1
- package/dist/src-pmvW7BFx.js +0 -6688
- package/dist/src-pmvW7BFx.js.map +0 -1
- package/dist/src-vkcwKXbT.js.map +0 -1
- package/dist/types-BfKcm9do.js +0 -39
- package/dist/types-BfKcm9do.js.map +0 -1
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { Hono, type MiddlewareHandler } from "hono";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { HonoEnv } from "../api/types.js";
|
|
4
|
-
import type
|
|
4
|
+
import { type AuthLimiters } from "./rate-limiter.js";
|
|
5
|
+
import type { JwtService } from "./jwt.js";
|
|
6
|
+
import type { AuthModuleConfig, CreateSessionAndTokens } from "./routes.js";
|
|
5
7
|
import { resolveAuthHooks } from "./auth-hooks.js";
|
|
6
8
|
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
7
9
|
interface MfaRoutesConfig {
|
|
8
10
|
router: Hono<HonoEnv>;
|
|
9
11
|
config: AuthModuleConfig;
|
|
12
|
+
/** The backend these routes sign and verify for; its secret is also the TOTP key's last fallback. */
|
|
13
|
+
jwt: JwtService;
|
|
14
|
+
/** The backend's auth limiters. */
|
|
15
|
+
limiters: AuthLimiters;
|
|
10
16
|
/**
|
|
11
17
|
* The caller's guard for a signed-in user, with the revocation watermark
|
|
12
18
|
* consulted. Enrolling, confirming or removing a factor is a persistence
|
|
@@ -27,14 +33,7 @@ interface MfaRoutesConfig {
|
|
|
27
33
|
isAnonymous?: boolean;
|
|
28
34
|
metadata?: Record<string, unknown> | null;
|
|
29
35
|
}, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
|
|
30
|
-
createSessionAndTokens:
|
|
31
|
-
skipMfaGate?: boolean;
|
|
32
|
-
aal?: "aal1" | "aal2";
|
|
33
|
-
}) => Promise<{
|
|
34
|
-
roleIds: string[];
|
|
35
|
-
accessToken: string;
|
|
36
|
-
refreshToken: string;
|
|
37
|
-
}>;
|
|
36
|
+
createSessionAndTokens: CreateSessionAndTokens;
|
|
38
37
|
applyTransformHook?: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>;
|
|
39
38
|
}
|
|
40
39
|
export declare function mountMfaRoutes(opts: MfaRoutesConfig): void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MiddlewareHandler, Context } from "hono";
|
|
2
|
-
import type
|
|
2
|
+
import { type AccessJudgeRepository } from "./token-revocation.js";
|
|
3
3
|
import { DataDriver } from "@rebasepro/types";
|
|
4
|
-
import { AccessTokenPayload } from "./jwt.js";
|
|
4
|
+
import { AccessTokenPayload, type JwtService } from "./jwt.js";
|
|
5
5
|
import type { HonoEnv } from "../api/types.js";
|
|
6
6
|
import { ApiError } from "../api/errors.js";
|
|
7
7
|
import type { ApiKeyStore } from "./api-keys/api-key-store.js";
|
|
@@ -131,11 +131,15 @@ export declare function createRequireAuth(options?: {
|
|
|
131
131
|
* invalidated by `logout` or a password reset stops working on admin routes
|
|
132
132
|
* too, not just on the data plane.
|
|
133
133
|
*/
|
|
134
|
-
revocationRepo?:
|
|
134
|
+
revocationRepo?: AccessJudgeRepository;
|
|
135
135
|
}): MiddlewareHandler<HonoEnv>;
|
|
136
136
|
/**
|
|
137
|
-
* Middleware that requires the user to
|
|
138
|
-
* Must be used AFTER requireAuth or on a route where user is
|
|
137
|
+
* Middleware that requires the user to hold the `admin` role, which holds
|
|
138
|
+
* every scope. Must be used AFTER requireAuth or on a route where user is
|
|
139
|
+
* guaranteed.
|
|
140
|
+
*
|
|
141
|
+
* Prefer `requireScope` from `./access` for anything a scope names: a scope
|
|
142
|
+
* can be granted to a narrower role and to a key, and `admin` cannot.
|
|
139
143
|
*/
|
|
140
144
|
export declare const requireAdmin: MiddlewareHandler<HonoEnv>;
|
|
141
145
|
/**
|
|
@@ -147,7 +151,14 @@ export declare const requireAdmin: MiddlewareHandler<HonoEnv>;
|
|
|
147
151
|
*/
|
|
148
152
|
export declare const optionalAuth: MiddlewareHandler<HonoEnv>;
|
|
149
153
|
/**
|
|
150
|
-
*
|
|
154
|
+
* Who a session token names, as `jwt` verifies it — or "nobody" rather than a
|
|
155
|
+
* throw on a backend with no JWT of its own, so a socket closes as
|
|
156
|
+
* unauthenticated, which is the outcome this describes.
|
|
157
|
+
*/
|
|
158
|
+
export declare function userFromToken(jwt: JwtService, token: string): Promise<AccessTokenPayload | null>;
|
|
159
|
+
/**
|
|
160
|
+
* Extract user from token - for WebSocket authentication. Answers for the
|
|
161
|
+
* process default; a backend's own socket verifies with its own keys.
|
|
151
162
|
*/
|
|
152
163
|
export declare function extractUserFromToken(token: string): Promise<AccessTokenPayload | null>;
|
|
153
164
|
/**
|
|
@@ -197,6 +208,14 @@ export declare const queryTokenAuth: MiddlewareHandler<HonoEnv>;
|
|
|
197
208
|
* requested object path is public, it sets a minimal "public" principal so the
|
|
198
209
|
* downstream `requireAuth` gate lets the read through. Private paths are left
|
|
199
210
|
* untouched, so they still require a valid token.
|
|
211
|
+
*
|
|
212
|
+
* Public means the object the route will serve is public, so the decision is
|
|
213
|
+
* made on that object's canonical key, derived by the route's own function
|
|
214
|
+
* (`requestedStorageObject`). It used to be made on the raw path, through a
|
|
215
|
+
* check that strips a `scheme://`: `notes://public/secret.txt` read as
|
|
216
|
+
* `public/secret.txt` here while the route served the private
|
|
217
|
+
* `notes:/public/secret.txt`, and the authorize hook — not asked about this
|
|
218
|
+
* principal — never saw it.
|
|
200
219
|
*/
|
|
201
220
|
export declare const publicObjectAuth: MiddlewareHandler<HonoEnv>;
|
|
202
221
|
/**
|
|
@@ -217,7 +236,7 @@ export declare const publicObjectAuth: MiddlewareHandler<HonoEnv>;
|
|
|
217
236
|
* Hono routes the request, so this comparison already runs on a resolved path.
|
|
218
237
|
* But that is a guarantee of the runtime rather than of this code, and it is
|
|
219
238
|
* one line to not depend on it. The same rule already guards the public-object
|
|
220
|
-
* path — see `
|
|
239
|
+
* path — see `isPublicStorageKey`.
|
|
221
240
|
*/
|
|
222
241
|
export declare function isPathMatch(requested: string, allowed: string): boolean;
|
|
223
242
|
/**
|
|
@@ -42,9 +42,10 @@
|
|
|
42
42
|
import { Hono } from "hono";
|
|
43
43
|
import type { MiddlewareHandler } from "hono";
|
|
44
44
|
import { z } from "zod";
|
|
45
|
-
import type { AuthModuleConfig } from "./routes.js";
|
|
45
|
+
import type { AuthModuleConfig, CreateSessionAndTokens } from "./routes.js";
|
|
46
46
|
import type { ResolvedAuthHooks } from "./auth-hooks.js";
|
|
47
47
|
import type { HonoEnv } from "../api/types.js";
|
|
48
|
+
import { type AuthLimiters } from "./rate-limiter.js";
|
|
48
49
|
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
49
50
|
/** How long a code is good for. */
|
|
50
51
|
export declare const OTP_TTL_MS: number;
|
|
@@ -67,6 +68,8 @@ export declare function otpTokenMaterial(email: string, code: string): string;
|
|
|
67
68
|
export declare function mountOtpRoutes(deps: {
|
|
68
69
|
router: Hono<HonoEnv>;
|
|
69
70
|
config: AuthModuleConfig;
|
|
71
|
+
/** The backend's auth limiters; the per-address ones count where they do. */
|
|
72
|
+
limiters: AuthLimiters;
|
|
70
73
|
ops: ResolvedAuthHooks;
|
|
71
74
|
parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T;
|
|
72
75
|
buildAuthResponse: (user: {
|
|
@@ -78,11 +81,7 @@ export declare function mountOtpRoutes(deps: {
|
|
|
78
81
|
isAnonymous?: boolean;
|
|
79
82
|
metadata?: Record<string, unknown> | null;
|
|
80
83
|
}, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
|
|
81
|
-
createSessionAndTokens:
|
|
82
|
-
roleIds: string[];
|
|
83
|
-
accessToken: string;
|
|
84
|
-
refreshToken: string;
|
|
85
|
-
}>;
|
|
84
|
+
createSessionAndTokens: CreateSessionAndTokens;
|
|
86
85
|
applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, uid: string) => Promise<AuthResponsePayload>;
|
|
87
86
|
/** Built by the caller, as for magic link. Absent when captcha is off. */
|
|
88
87
|
captchaMiddleware?: MiddlewareHandler<HonoEnv>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sign-up by magic link or email code (`auth.magicLinkCreatesUsers`).
|
|
3
|
+
*
|
|
4
|
+
* Both passwordless doors refuse an address with no account — silently, so
|
|
5
|
+
* they do not say which addresses have one. A passwordless-only app then had
|
|
6
|
+
* no way to create accounts at all. With the option on, and registration open,
|
|
7
|
+
* an unknown address gets an account at request time — no password, unverified
|
|
8
|
+
* — and the link or code mailed to it is what proves the address and signs it
|
|
9
|
+
* in, exactly as for an existing account. Supabase's `shouldCreateUser`.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { AuthModuleConfig } from "./routes.js";
|
|
14
|
+
import type { ResolvedAuthHooks } from "./auth-hooks.js";
|
|
15
|
+
import type { UserData } from "./interfaces.js";
|
|
16
|
+
/**
|
|
17
|
+
* The account a passwordless request for `email` should mail, creating it
|
|
18
|
+
* when the deployment lets passwordless requests sign people up. `null` when
|
|
19
|
+
* there is none and none may be made — the caller answers as for any unknown
|
|
20
|
+
* address.
|
|
21
|
+
*
|
|
22
|
+
* Registration's controls hold: the kill switch, `allowRegistration` (with no
|
|
23
|
+
* first-user exception: the first admin is made by registering or by the
|
|
24
|
+
* operator, never by whoever asks for a link first), `beforeUserCreate`,
|
|
25
|
+
* `afterUserCreate` and the default role.
|
|
26
|
+
*/
|
|
27
|
+
export declare function accountForPasswordlessRequest(config: AuthModuleConfig, ops: ResolvedAuthHooks, email: string): Promise<UserData | null>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform tokens: a short-lived credential the platform hosting this server
|
|
3
|
+
* mints for one person, for one project, for a few read-only scopes.
|
|
4
|
+
*
|
|
5
|
+
* ## Why this exists
|
|
6
|
+
*
|
|
7
|
+
* On Rebase Cloud the owner of a project is signed in to the *control plane*,
|
|
8
|
+
* not to their own app. Their app's admin surfaces — the cron job list and its
|
|
9
|
+
* run history first — accept an admin user of the app, an `rk_` key, or the
|
|
10
|
+
* service key, and an owner may hold none of them: a fresh deploy has no admin
|
|
11
|
+
* account, and the service key is admin on the whole API, which is the wrong
|
|
12
|
+
* thing to hand someone who wants to read why last night's job failed.
|
|
13
|
+
*
|
|
14
|
+
* So the control plane signs a token instead. It checks the caller's project
|
|
15
|
+
* membership, then signs `{ aud: <project>, sub: <who>, scope: "cron:read" }`
|
|
16
|
+
* with a key only it holds, valid for minutes. This server verifies it against
|
|
17
|
+
* the public half — `REBASE_PLATFORM_TOKEN_KEY` — which the platform sets at
|
|
18
|
+
* deploy. Nothing secret lives in the tenant: the env holds a public key, and
|
|
19
|
+
* leaking it lets nobody mint anything.
|
|
20
|
+
*
|
|
21
|
+
* ## What a platform token can never do
|
|
22
|
+
*
|
|
23
|
+
* - **Exceed {@link PLATFORM_TOKEN_SCOPES}.** The token names scopes; this
|
|
24
|
+
* server grants only the ones on that list, whatever the platform signed. The
|
|
25
|
+
* ceiling lives here, in the tenant's code, so a compromised or buggy control
|
|
26
|
+
* plane cannot widen it.
|
|
27
|
+
* - **Outlive {@link PLATFORM_TOKEN_MAX_LIFETIME_SECONDS}.** A token whose
|
|
28
|
+
* `exp - iat` is longer is refused, not clamped: a long-lived platform token
|
|
29
|
+
* is a static secret by another name.
|
|
30
|
+
* - **Reach another project.** One platform key signs for every tenant, so the
|
|
31
|
+
* audience is what binds a token to this one: `aud` must equal
|
|
32
|
+
* `REBASE_PLATFORM_TOKEN_AUDIENCE`.
|
|
33
|
+
* - **Act as a person of this app.** The caller is `platform:<sub>` with no
|
|
34
|
+
* roles: row-level security sees nobody it knows, and every surface that
|
|
35
|
+
* checks a scope other than the granted ones refuses it.
|
|
36
|
+
*
|
|
37
|
+
* ## Wire format
|
|
38
|
+
*
|
|
39
|
+
* `rpt_` followed by a compact ES256 JWS. The prefix keeps the credential
|
|
40
|
+
* classes apart the way `rk_` does: a platform token is never tried as a user
|
|
41
|
+
* session, and a user session is never tried as a platform token.
|
|
42
|
+
*
|
|
43
|
+
* @module
|
|
44
|
+
*/
|
|
45
|
+
import type { MiddlewareHandler } from "hono";
|
|
46
|
+
import type { AdminScope } from "@rebasepro/types";
|
|
47
|
+
import type { HonoEnv } from "../api/types.js";
|
|
48
|
+
/** Marks a bearer token as a platform token. */
|
|
49
|
+
export declare const PLATFORM_TOKEN_PREFIX = "rpt_";
|
|
50
|
+
/** The `iss` every platform token carries. */
|
|
51
|
+
export declare const PLATFORM_TOKEN_ISSUER = "rebase-cloud";
|
|
52
|
+
/**
|
|
53
|
+
* Everything a platform token can be granted on this server.
|
|
54
|
+
*
|
|
55
|
+
* Read-only on purpose. Adding a scope here is a decision about what the
|
|
56
|
+
* platform may do inside a customer's app on a person's behalf, and belongs in
|
|
57
|
+
* its own change.
|
|
58
|
+
*/
|
|
59
|
+
export declare const PLATFORM_TOKEN_SCOPES: readonly AdminScope[];
|
|
60
|
+
/** The longest `exp - iat` a platform token may declare. */
|
|
61
|
+
export declare const PLATFORM_TOKEN_MAX_LIFETIME_SECONDS = 600;
|
|
62
|
+
/** The environment variables a platform sets to turn platform tokens on. */
|
|
63
|
+
export declare const PLATFORM_TOKEN_KEY_ENV = "REBASE_PLATFORM_TOKEN_KEY";
|
|
64
|
+
export declare const PLATFORM_TOKEN_AUDIENCE_ENV = "REBASE_PLATFORM_TOKEN_AUDIENCE";
|
|
65
|
+
/** What this server verifies platform tokens against. */
|
|
66
|
+
export interface PlatformTokenConfig {
|
|
67
|
+
/**
|
|
68
|
+
* PEM-encoded SPKI public keys, EC P-256. More than one during a key
|
|
69
|
+
* rotation: a token verifies against any of them.
|
|
70
|
+
*/
|
|
71
|
+
publicKeys: string[];
|
|
72
|
+
/** This project, as the platform names it in `aud`. */
|
|
73
|
+
audience: string;
|
|
74
|
+
}
|
|
75
|
+
/** A verified platform token, as the request will act. */
|
|
76
|
+
export interface PlatformCaller {
|
|
77
|
+
/** Who the platform minted it for — a control-plane account. */
|
|
78
|
+
subject: string;
|
|
79
|
+
/** The granted scopes: what the token asked for, within the ceiling. */
|
|
80
|
+
scopes: string[];
|
|
81
|
+
/** `jti`, when the platform set one — what an audit line quotes. */
|
|
82
|
+
tokenId?: string;
|
|
83
|
+
}
|
|
84
|
+
/** Why a presented platform token does not authenticate. */
|
|
85
|
+
export interface PlatformTokenRefusal {
|
|
86
|
+
refusal: string;
|
|
87
|
+
}
|
|
88
|
+
export declare function isPlatformToken(token: string): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* The PEM blocks in an env value: real newlines, `\n`-escaped ones (what a
|
|
91
|
+
* one-line `.env` holds), or the whole thing base64-encoded.
|
|
92
|
+
*/
|
|
93
|
+
export declare function parsePublicKeys(value: string): string[];
|
|
94
|
+
/**
|
|
95
|
+
* Read the platform-token configuration from the environment.
|
|
96
|
+
*
|
|
97
|
+
* `undefined` when platform tokens are off — neither variable set, which is
|
|
98
|
+
* every self-hosted server — or misconfigured. A misconfiguration is logged and
|
|
99
|
+
* leaves them off rather than failing the boot: the platform set these values,
|
|
100
|
+
* the app's owner cannot fix them, and the app serving traffic matters more
|
|
101
|
+
* than its cron history being readable from the CLI.
|
|
102
|
+
*/
|
|
103
|
+
export declare function platformTokensFromEnv(env: Record<string, string | undefined>): Promise<PlatformTokenConfig | undefined>;
|
|
104
|
+
/**
|
|
105
|
+
* Verify a presented platform token: signature, issuer, audience, lifetime, and
|
|
106
|
+
* the scopes it may be granted here.
|
|
107
|
+
*/
|
|
108
|
+
export declare function verifyPlatformToken(token: string, config: PlatformTokenConfig, nowSeconds?: number): Promise<PlatformCaller | PlatformTokenRefusal>;
|
|
109
|
+
/**
|
|
110
|
+
* Authenticate an `rpt_` bearer token ahead of an admin gate.
|
|
111
|
+
*
|
|
112
|
+
* Mounted where the `rk_` pre-auth is, and shaped like it: a request it does not
|
|
113
|
+
* recognise passes through untouched, a recognised one either becomes a caller
|
|
114
|
+
* with narrowed `scopes` or is refused here. The gate's scope check then decides
|
|
115
|
+
* — so a token holding `cron:read` reads cron, and is a 403 on every other
|
|
116
|
+
* surface.
|
|
117
|
+
*
|
|
118
|
+
* With `config` undefined, platform tokens are off on this server; an `rpt_`
|
|
119
|
+
* token is still recognised, so its holder learns that rather than the generic
|
|
120
|
+
* "invalid token" a JWT parser would answer.
|
|
121
|
+
*/
|
|
122
|
+
export declare function createPlatformTokenPreAuth(config: PlatformTokenConfig | undefined): MiddlewareHandler<HonoEnv>;
|
|
@@ -8,7 +8,7 @@ import { RateLimitDecision, RateLimitStore } from "./rate-limit-store.js";
|
|
|
8
8
|
* The counting lives in a {@link RateLimitStore} — in this process's memory by
|
|
9
9
|
* default, which is a per-replica limit and says so. See `rate-limit-store.ts`.
|
|
10
10
|
*/
|
|
11
|
-
interface RateLimiterOptions {
|
|
11
|
+
export interface RateLimiterOptions {
|
|
12
12
|
/** Time window in milliseconds (default: 15 minutes) */
|
|
13
13
|
windowMs?: number;
|
|
14
14
|
/** Maximum requests per window (default: 100) */
|
|
@@ -30,12 +30,13 @@ interface RateLimiterOptions {
|
|
|
30
30
|
*/
|
|
31
31
|
store?: RateLimitStore;
|
|
32
32
|
/**
|
|
33
|
-
* Count in the
|
|
33
|
+
* Count in the process default's shared store once one is installed, under
|
|
34
34
|
* this name. For a limiter declared at module load, which runs before any
|
|
35
35
|
* configuration exists and so cannot be handed a `store` — see
|
|
36
36
|
* {@link setSharedRateLimitStore}. The name namespaces the limiter's keys
|
|
37
37
|
* there: two limiters keyed by the same IP must not share one count.
|
|
38
|
-
* Ignored when `store` is given.
|
|
38
|
+
* Ignored when `store` is given. A backend's own limiters are built by
|
|
39
|
+
* {@link createAuthLimiters} and never read the process's store.
|
|
39
40
|
*/
|
|
40
41
|
name?: string;
|
|
41
42
|
/**
|
|
@@ -44,6 +45,14 @@ interface RateLimiterOptions {
|
|
|
44
45
|
* `limit`; returning `null` skips the limiter for this request.
|
|
45
46
|
*/
|
|
46
47
|
resolveLimit?: (c: Parameters<MiddlewareHandler<HonoEnv>>[0]) => number | null | undefined | Promise<number | null | undefined>;
|
|
48
|
+
/**
|
|
49
|
+
* How many requests this one counts as. Default 1. For a request that
|
|
50
|
+
* does the work of several — a batch — so batching is cheaper than the
|
|
51
|
+
* requests it replaces without being free. Charged one hit at a time, and
|
|
52
|
+
* refused at the first that does not fit; the hits before it stay charged,
|
|
53
|
+
* as the requests a batch replaces would have been.
|
|
54
|
+
*/
|
|
55
|
+
cost?: (c: Parameters<MiddlewareHandler<HonoEnv>>[0]) => number | Promise<number>;
|
|
47
56
|
/**
|
|
48
57
|
* Number of trusted reverse-proxy hops in front of this server. Each hop
|
|
49
58
|
* appends the address it saw to `X-Forwarded-For`, so the real client IP is
|
|
@@ -70,13 +79,15 @@ interface RateLimiterOptions {
|
|
|
70
79
|
trustedProxyHops?: number;
|
|
71
80
|
}
|
|
72
81
|
/**
|
|
73
|
-
* Point every named limiter
|
|
74
|
-
* `undefined`, back at its own memory.
|
|
75
|
-
* the
|
|
76
|
-
*
|
|
77
|
-
*
|
|
82
|
+
* Point every named limiter of the process default at a shared store — or,
|
|
83
|
+
* with `undefined`, back at its own memory. `setDefaultBackend` calls it with
|
|
84
|
+
* the store the installed backend shares (SQL, or one the operator supplied):
|
|
85
|
+
* the default memory store is swept on the data window, which is not every
|
|
86
|
+
* limiter's window.
|
|
78
87
|
*/
|
|
79
88
|
export declare function setSharedRateLimitStore(store: RateLimitStore | undefined): void;
|
|
89
|
+
/** @internal The process default's shared store, to snapshot or restore it. */
|
|
90
|
+
export declare function sharedRateLimitStoreOfProcess(): RateLimitStore | undefined;
|
|
80
91
|
/**
|
|
81
92
|
* Create a rate-limiting middleware.
|
|
82
93
|
*
|
|
@@ -84,14 +95,41 @@ export declare function setSharedRateLimitStore(store: RateLimitStore | undefine
|
|
|
84
95
|
*/
|
|
85
96
|
export declare function createRateLimiter(options?: RateLimiterOptions): MiddlewareHandler<HonoEnv>;
|
|
86
97
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
98
|
+
* Default key generator: the client's address, from the most trustworthy source
|
|
99
|
+
* this deployment has.
|
|
100
|
+
*
|
|
101
|
+
* `X-Forwarded-For` is a client-writable header; only the entries appended by
|
|
102
|
+
* trusted reverse proxies can be believed. With `trustedProxyHops` proxies in
|
|
103
|
+
* front, each appends the address it saw, so the real client IP is the
|
|
104
|
+
* `trustedProxyHops`-th entry from the right — everything further left is
|
|
105
|
+
* client-supplied and must be ignored. This is what prevents a caller from
|
|
106
|
+
* spoofing `X-Forwarded-For` to spread its requests across many rate-limit keys.
|
|
107
|
+
*
|
|
108
|
+
* `X-Real-IP` is the *same* kind of header and needs the same rule, which it
|
|
109
|
+
* did not have: it was read unconditionally, including under
|
|
110
|
+
* `trustedProxyHops === 0` — the mode whose entire meaning is "no proxy is in
|
|
111
|
+
* front of me". With no proxy there, nothing writes `X-Real-IP` except the
|
|
112
|
+
* caller, so the key was theirs to choose: one header per request bought an
|
|
113
|
+
* unlimited number of buckets, and the limiters on login, registration and
|
|
114
|
+
* password reset counted to one. The reasoning had been done carefully for one
|
|
115
|
+
* spelling of a proxy header and not carried to its twin.
|
|
116
|
+
*
|
|
117
|
+
* So `X-Real-IP` is now believed only where a proxy is declared to exist. With
|
|
118
|
+
* none, the connection's own address is used — unforgeable, and available
|
|
119
|
+
* because the server runs on `@hono/node-server`. `"unknown"` is the last
|
|
120
|
+
* resort only, and it is a single shared bucket by design: better that
|
|
121
|
+
* anonymous callers throttle each other than that any of them throttles nobody.
|
|
89
122
|
*/
|
|
90
|
-
export declare const defaultAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
91
123
|
/**
|
|
92
|
-
*
|
|
93
|
-
*
|
|
124
|
+
* Where a request comes from, as the rate limiters judge it: the socket's own
|
|
125
|
+
* address, or — only behind as many proxies as `TRUSTED_PROXY_HOPS` declares —
|
|
126
|
+
* the address they report. What a session row records as its IP, so the
|
|
127
|
+
* sessions list shows the same address the limiter counted, rather than the
|
|
128
|
+
* raw `X-Forwarded-For` (whose leftmost entry the caller chooses) or
|
|
129
|
+
* `"unknown"` for every direct connection.
|
|
94
130
|
*/
|
|
131
|
+
export declare function requestClientAddress(c: Parameters<MiddlewareHandler<HonoEnv>>[0]): string;
|
|
132
|
+
export declare const defaultAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
95
133
|
export declare const strictAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
96
134
|
/**
|
|
97
135
|
* Limiter for `POST /auth/send-verification`, keyed by the authenticated user.
|
|
@@ -124,22 +162,6 @@ export declare const strictAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
|
124
162
|
* that names the field; failing here would answer 429 to bad JSON.
|
|
125
163
|
*/
|
|
126
164
|
export declare const captureRecipientEmail: MiddlewareHandler<HonoEnv>;
|
|
127
|
-
/**
|
|
128
|
-
* Per-ADDRESS throttle for a route that mails an address the caller named.
|
|
129
|
-
*
|
|
130
|
-
* `strictAuthLimiter` bounds a machine, and a machine is the attacker's to
|
|
131
|
-
* multiply. The mailbox being filled belongs to somebody who cannot rotate
|
|
132
|
-
* anything, and the domain the messages come from is this deployment's
|
|
133
|
-
* reputation — so a distributed run against one address passed the IP limiter
|
|
134
|
-
* untouched and cost the operator their sender score.
|
|
135
|
-
*
|
|
136
|
-
* Five per fifteen minutes: generous for "I didn't get it, send it again",
|
|
137
|
-
* useless as a mail bomb. The same numbers as `verificationEmailLimiter`,
|
|
138
|
-
* which bounds the same act for a signed-in caller.
|
|
139
|
-
*
|
|
140
|
-
* Falls back to the IP bucket for a request whose body named no address, so
|
|
141
|
-
* the limiter is never silently a no-op.
|
|
142
|
-
*/
|
|
143
165
|
export declare const recipientEmailLimiter: MiddlewareHandler<HonoEnv>;
|
|
144
166
|
/**
|
|
145
167
|
* How long a route that answers "if an account exists…" takes, whoever asked.
|
|
@@ -163,6 +185,43 @@ export declare const RECIPIENT_ROUTE_FLOOR_MS = 400;
|
|
|
163
185
|
/** Hold a result until at least `floorMs` has passed since `startedAt`. */
|
|
164
186
|
export declare function notBefore<T>(startedAt: number, floorMs: number, result: T): Promise<T>;
|
|
165
187
|
export declare const verificationEmailLimiter: MiddlewareHandler<HonoEnv>;
|
|
188
|
+
/** A limiter's options, with the name it counts under in a shared store. */
|
|
189
|
+
export type NamedRateLimiterOptions = Omit<RateLimiterOptions, "store" | "name"> & {
|
|
190
|
+
name: string;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* One backend's auth limiters — login and registration, the sensitive
|
|
194
|
+
* endpoints, the per-address and per-account mail budgets — and the way its
|
|
195
|
+
* route modules build the rest of theirs (the OTP and MFA attempt limits).
|
|
196
|
+
*
|
|
197
|
+
* Every backend has its own set ({@link createAuthLimiters}), so a caller
|
|
198
|
+
* spending one backend's allowance spends nothing of another's in the same
|
|
199
|
+
* process. The module constants above ({@link defaultAuthLimiter} and its
|
|
200
|
+
* siblings) are the process default's set, for a router built outside any
|
|
201
|
+
* backend.
|
|
202
|
+
*/
|
|
203
|
+
export interface AuthLimiters {
|
|
204
|
+
/** General auth endpoints (login, register): 200 requests per 15 minutes per address. */
|
|
205
|
+
default: MiddlewareHandler<HonoEnv>;
|
|
206
|
+
/** Sensitive endpoints (password reset, verification): 50 requests per 15 minutes per address. */
|
|
207
|
+
strict: MiddlewareHandler<HonoEnv>;
|
|
208
|
+
/** Mail to an address the caller named: 5 per 15 minutes per address. See {@link recipientEmailLimiter}. */
|
|
209
|
+
recipientEmail: MiddlewareHandler<HonoEnv>;
|
|
210
|
+
/** Verification mail for a signed-in caller: 5 per 15 minutes per account. See {@link verificationEmailLimiter}. */
|
|
211
|
+
verificationEmail: MiddlewareHandler<HonoEnv>;
|
|
212
|
+
/** Another limiter that counts where these do, under its own name. */
|
|
213
|
+
named(options: NamedRateLimiterOptions): MiddlewareHandler<HonoEnv>;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Build a backend's auth limiters.
|
|
217
|
+
*
|
|
218
|
+
* With `store` — a shared one: SQL, or what the operator passed as
|
|
219
|
+
* `rateLimit.store` — every limiter counts there under its own name, so the
|
|
220
|
+
* replicas of one deployment agree. Without one each limiter counts in its own
|
|
221
|
+
* memory: the data limiter's memory store is swept on the data window, which
|
|
222
|
+
* is not every limiter's window.
|
|
223
|
+
*/
|
|
224
|
+
export declare function createAuthLimiters(store?: RateLimitStore): AuthLimiters;
|
|
166
225
|
/**
|
|
167
226
|
* Key generator for API-key-based rate limiting.
|
|
168
227
|
*
|
|
@@ -209,6 +268,12 @@ export interface DataRateLimitConfig {
|
|
|
209
268
|
anonymousFunctions?: number | null;
|
|
210
269
|
/** Share counts across replicas. Defaults to this process's memory. */
|
|
211
270
|
store?: RateLimitStore;
|
|
271
|
+
/**
|
|
272
|
+
* The deployment's service key, recognised as a Bearer before any auth
|
|
273
|
+
* middleware has run — the storage router's limiter runs ahead of its
|
|
274
|
+
* routes' auth — and never limited. See {@link dataRateLimitBuckets}.
|
|
275
|
+
*/
|
|
276
|
+
serviceKey?: string;
|
|
212
277
|
}
|
|
213
278
|
/** @see DataRateLimitConfig.anonymousFunctions */
|
|
214
279
|
export declare const DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT = 3000;
|
|
@@ -229,7 +294,11 @@ export declare const DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT = 3000;
|
|
|
229
294
|
* set them, and one that already has a proxy doing this should pass
|
|
230
295
|
* `enabled: false` rather than pay for it twice.
|
|
231
296
|
*/
|
|
232
|
-
export declare function createDataRateLimiter(config?: DataRateLimitConfig
|
|
297
|
+
export declare function createDataRateLimiter(config?: DataRateLimitConfig,
|
|
298
|
+
/** See {@link RateLimiterOptions.cost}: what one request on this router counts as. */
|
|
299
|
+
options?: {
|
|
300
|
+
cost?: RateLimiterOptions["cost"];
|
|
301
|
+
}): MiddlewareHandler<HonoEnv>;
|
|
233
302
|
/**
|
|
234
303
|
* The data API's per-caller limit, as a check rather than a middleware — for
|
|
235
304
|
* the door into the same data that is not an HTTP request.
|
|
@@ -242,4 +311,3 @@ export declare function createDataRateLimiter(config?: DataRateLimitConfig): Mid
|
|
|
242
311
|
* same key: one person's allowance, spent through either door.
|
|
243
312
|
*/
|
|
244
313
|
export declare function createDataRateLimitCheck(config?: DataRateLimitConfig): (caller: DataRateLimitCaller) => Promise<RateLimitDecision | null>;
|
|
245
|
-
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AuthRepository } from "./interfaces.js";
|
|
1
2
|
/**
|
|
2
3
|
* Whether a registration may proceed — computed in exactly one place.
|
|
3
4
|
*
|
|
@@ -66,6 +67,21 @@ export interface RegistrationPolicy {
|
|
|
66
67
|
export declare function isBootstrapWindowOpen(env?: {
|
|
67
68
|
NODE_ENV?: string;
|
|
68
69
|
}): boolean;
|
|
70
|
+
type UserPresenceRepository = Pick<AuthRepository, "firstUserIds" | "listUsersPaginated">;
|
|
71
|
+
/**
|
|
72
|
+
* Whether the users table is empty — the question behind the bootstrap window.
|
|
73
|
+
*
|
|
74
|
+
* Through `AuthRepository.firstUserIds` when the repository has it: one
|
|
75
|
+
* unordered `LIMIT 1` read. Otherwise through `listUsersPaginated`, which also
|
|
76
|
+
* counts and sorts the whole table, so it is only the fallback.
|
|
77
|
+
*/
|
|
78
|
+
export declare function isUserTableEmpty(repo: UserPresenceRepository): Promise<boolean>;
|
|
79
|
+
/**
|
|
80
|
+
* Whether the account just created is the only one there is. Two ids at most:
|
|
81
|
+
* whether anyone else exists, and, when nobody does, whether it is this one.
|
|
82
|
+
* Same fallback as {@link isUserTableEmpty}.
|
|
83
|
+
*/
|
|
84
|
+
export declare function isOnlyUser(repo: UserPresenceRepository, uid: string): Promise<boolean>;
|
|
69
85
|
/**
|
|
70
86
|
* What to tell a caller who hit an empty production database with the window
|
|
71
87
|
* shut. Named here so the register route and the bootstrap route say the same
|
|
@@ -113,3 +129,4 @@ export declare function isAnonymousAuthOpen(policy: {
|
|
|
113
129
|
allowAnonymous?: boolean;
|
|
114
130
|
disableSelfRegistration?: boolean;
|
|
115
131
|
}): boolean;
|
|
132
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthAdapter } from "@rebasepro/types";
|
|
2
|
-
import type { RebaseAuthConfig } from "../
|
|
2
|
+
import type { RebaseAuthConfig } from "../backend/options.js";
|
|
3
3
|
/**
|
|
4
4
|
* Whether the `auth` config is an `AuthAdapter` (it can verify a request) or a
|
|
5
5
|
* plain `RebaseAuthConfig`. Lives here rather than in `init.ts` so this module
|
package/dist/auth/routes.d.ts
CHANGED
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import type { AuthRepository, OAuthProvider } from "./interfaces.js";
|
|
3
|
+
import { type JwtService } from "./jwt.js";
|
|
3
4
|
import type { AuthHooks } from "./auth-hooks.js";
|
|
4
5
|
import { EmailService, EmailConfig } from "../email/index.js";
|
|
5
6
|
import { HonoEnv } from "../api/types.js";
|
|
7
|
+
import { type AuthLimiters } from "./rate-limiter.js";
|
|
6
8
|
import { type CaptchaConfig } from "./captcha.js";
|
|
9
|
+
import { type AccessControl } from "./access.js";
|
|
10
|
+
import { isDeliverableAddress } from "./deliverable-address.js";
|
|
11
|
+
export { isDeliverableAddress };
|
|
7
12
|
/**
|
|
8
13
|
* Shared configuration for auth and admin route factories.
|
|
9
14
|
*/
|
|
10
15
|
export interface AuthModuleConfig {
|
|
11
16
|
authRepo: AuthRepository;
|
|
17
|
+
/**
|
|
18
|
+
* The backend these routes sign sessions for: its JWT keys and token
|
|
19
|
+
* lifetimes. The process default when omitted — the one `configureJwt`
|
|
20
|
+
* sets.
|
|
21
|
+
*/
|
|
22
|
+
jwt?: JwtService;
|
|
23
|
+
/** The backend's auth limiters, counting in its own store. The process default's set when omitted. */
|
|
24
|
+
limiters?: AuthLimiters;
|
|
25
|
+
/**
|
|
26
|
+
* The backend's access model — what the default role may hold is checked
|
|
27
|
+
* against it. The process default when omitted.
|
|
28
|
+
*/
|
|
29
|
+
access?: AccessControl;
|
|
12
30
|
/**
|
|
13
31
|
* Bot protection. Off unless `enabled`.
|
|
14
32
|
*
|
|
@@ -86,7 +104,30 @@ export interface AuthModuleConfig {
|
|
|
86
104
|
* how long a captured token stays useful to someone who copied it.
|
|
87
105
|
*/
|
|
88
106
|
refreshTokenReuseIntervalSeconds?: number;
|
|
107
|
+
/**
|
|
108
|
+
* Let a magic-link or email-code request for an address with no account
|
|
109
|
+
* create one (no password, unverified until the link or code is used),
|
|
110
|
+
* while registration is open. Off by default. See `passwordless-signup.ts`.
|
|
111
|
+
*/
|
|
112
|
+
magicLinkCreatesUsers?: boolean;
|
|
113
|
+
/**
|
|
114
|
+
* What a refresh token presented after its reuse window does to its
|
|
115
|
+
* session. See `RebaseAuthConfig.refreshTokenReuse`. Default `"reject"`.
|
|
116
|
+
*/
|
|
117
|
+
refreshTokenReuse?: RefreshTokenReusePolicy;
|
|
118
|
+
/**
|
|
119
|
+
* Refuse password sign-in until the account's address is verified, and
|
|
120
|
+
* register confirm-first: `POST /auth/register` answers the same "check
|
|
121
|
+
* your inbox" whether or not the address already has an account, and
|
|
122
|
+
* signs nobody in. Off by default. Needs email; the boot refuses it
|
|
123
|
+
* without. See `RebaseAuthConfig.requireEmailVerification`.
|
|
124
|
+
*/
|
|
125
|
+
requireEmailVerification?: boolean;
|
|
89
126
|
}
|
|
127
|
+
/** What a refresh token replayed after its reuse window does to its session. */
|
|
128
|
+
export type RefreshTokenReusePolicy = "reject" | "revoke-session";
|
|
129
|
+
/** How long an email-verification link stays usable. */
|
|
130
|
+
export declare const EMAIL_VERIFICATION_TTL_MS: number;
|
|
90
131
|
/**
|
|
91
132
|
* Configuration for httpOnly refresh-token cookies.
|
|
92
133
|
*/
|
|
@@ -109,4 +150,24 @@ export interface CookieAuthConfig {
|
|
|
109
150
|
*/
|
|
110
151
|
secure?: boolean;
|
|
111
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* What {@link CreateSessionAndTokens} is told about the sign-in it opens.
|
|
155
|
+
*
|
|
156
|
+
* `method` is what `providerId` says for the session from now on — stored on
|
|
157
|
+
* its refresh token and carried across every rotation — so each door names
|
|
158
|
+
* its own rather than leaving it to a default.
|
|
159
|
+
*/
|
|
160
|
+
export interface SessionOptions {
|
|
161
|
+
/** `"password"`, `"anonymous"`, `"magic-link"`, `"otp"`, `"mfa"` or a provider id. */
|
|
162
|
+
method: string;
|
|
163
|
+
/** Only for the route that has just seen the second factor. */
|
|
164
|
+
skipMfaGate?: boolean;
|
|
165
|
+
aal?: "aal1" | "aal2";
|
|
166
|
+
}
|
|
167
|
+
/** Mint a session, as every sign-in door does. See `createSessionAndTokens`. */
|
|
168
|
+
export type CreateSessionAndTokens = (uid: string, userAgent: string, ipAddress: string, options: SessionOptions) => Promise<{
|
|
169
|
+
roleIds: string[];
|
|
170
|
+
accessToken: string;
|
|
171
|
+
refreshToken: string;
|
|
172
|
+
}>;
|
|
112
173
|
export declare function createAuthRoutes(config: AuthModuleConfig): Hono<HonoEnv>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `GET /auth/scopes` — every scope this backend knows, described, and the
|
|
3
|
+
* ones the caller holds.
|
|
4
|
+
*
|
|
5
|
+
* What a screen needs to offer scopes for a key or a role: the built-in ones,
|
|
6
|
+
* the app's own `auth.scopes`, their wording and what their targets name. Any
|
|
7
|
+
* authenticated caller may read it; it describes the backend's vocabulary,
|
|
8
|
+
* not anybody's data.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import { Hono, type MiddlewareHandler } from "hono";
|
|
13
|
+
import type { AccessJudgeRepository } from "./token-revocation.js";
|
|
14
|
+
import type { HonoEnv } from "../api/types.js";
|
|
15
|
+
export interface ScopeRouteOptions {
|
|
16
|
+
serviceKey?: string;
|
|
17
|
+
resolveRoles?: (uid: string) => Promise<string[]>;
|
|
18
|
+
revocationRepo?: AccessJudgeRepository;
|
|
19
|
+
/** Authenticates `rk_` keys first, so a key can read what it holds. */
|
|
20
|
+
apiKeyPreAuth?: MiddlewareHandler<HonoEnv>;
|
|
21
|
+
}
|
|
22
|
+
export declare function createScopeRoutes(options: ScopeRouteOptions): Hono<HonoEnv>;
|