@rebasepro/server 0.24.0 → 0.24.1-canary.gcb918fc
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 +27 -2
- package/dist/GCSStorageController-fv6JAZ87.js +402 -0
- package/dist/GCSStorageController-fv6JAZ87.js.map +1 -0
- package/dist/S3StorageController-BNg-pXiY.js +480 -0
- package/dist/S3StorageController-BNg-pXiY.js.map +1 -0
- package/dist/api/mount-path.d.ts +30 -0
- package/dist/api/mount.d.ts +6 -13
- package/dist/api/rest/api-generator.d.ts +53 -1
- 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 +7 -5
- 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 +35 -0
- package/dist/{ast-schema-editor-CWqS_sLJ.js → ast-schema-editor-mCeSC03x.js} +3 -3
- package/dist/{ast-schema-editor-CWqS_sLJ.js.map → ast-schema-editor-mCeSC03x.js.map} +1 -1
- package/dist/auth/access.d.ts +57 -8
- package/dist/auth/admin-user-ops.d.ts +24 -2
- package/dist/auth/admin-users-route.d.ts +1 -0
- package/dist/auth/api-keys/api-key-middleware.d.ts +10 -3
- package/dist/auth/api-keys/api-key-routes.d.ts +4 -1
- package/dist/auth/builtin-auth-adapter.d.ts +13 -0
- package/dist/auth/email-change-routes.d.ts +3 -0
- package/dist/auth/expired-token-sweep.d.ts +5 -1
- package/dist/auth/interfaces.d.ts +10 -0
- 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 +282 -166
- package/dist/auth/magic-link-routes.d.ts +3 -0
- 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 +6 -0
- package/dist/auth/middleware.d.ts +9 -2
- package/dist/auth/otp-routes.d.ts +3 -0
- package/dist/auth/rate-limiter.d.ts +61 -34
- package/dist/auth/registration-policy.d.ts +17 -0
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/routes.d.ts +16 -0
- package/dist/auth/session-routes.d.ts +6 -0
- package/dist/auth/user-picking.d.ts +37 -0
- package/dist/auth/verify-credential.d.ts +25 -4
- package/dist/{auth-DMLngxn_.js → auth-GnONzteu.js} +2869 -1871
- package/dist/auth-GnONzteu.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/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 +14 -3
- package/dist/backup/backup-routes.d.ts +23 -2
- package/dist/backup/backup-storage.d.ts +3 -1
- package/dist/backup/index.d.ts +3 -1
- package/dist/{backup-CN0s50D2.js → backup-BnvkSLHi.js} +176 -35
- package/dist/backup-BnvkSLHi.js.map +1 -0
- package/dist/boot/boot.d.ts +2 -2
- package/dist/boot/driver.d.ts +3 -0
- package/dist/boot/env.d.ts +9 -2
- 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/runtime-cors.d.ts +17 -0
- package/dist/boot/sources.d.ts +2 -0
- package/dist/boot/static-routing.d.ts +9 -0
- package/dist/{contract-routes-fz8i4pxs.js → contract-routes-Ey6ftnKH.js} +4 -20
- package/dist/contract-routes-Ey6ftnKH.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 +69 -3
- package/dist/cron/cron-store.d.ts +33 -5
- package/dist/cron/define-cron.d.ts +6 -2
- package/dist/cron/index.d.ts +3 -3
- package/dist/cron-loader-B-u0snqq.js +202 -0
- package/dist/cron-loader-B-u0snqq.js.map +1 -0
- package/dist/{cron-routes-Bc-SB0Se.js → cron-routes-OD6BstUj.js} +27 -4
- package/dist/cron-routes-OD6BstUj.js.map +1 -0
- package/dist/{cron-scheduler-CYQgco86.js → cron-scheduler-idtLPoN-.js} +299 -33
- package/dist/cron-scheduler-idtLPoN-.js.map +1 -0
- package/dist/cron-store-CZ30ZBi-.js +577 -0
- package/dist/cron-store-CZ30ZBi-.js.map +1 -0
- package/dist/email/smtp-email-service.d.ts +23 -0
- package/dist/email/types.d.ts +18 -0
- package/dist/env.d.ts +0 -37
- package/dist/filter-dialect-O1HK6Nvr.js +1628 -0
- package/dist/filter-dialect-O1HK6Nvr.js.map +1 -0
- package/dist/{function-loader-D7o5Epjj.js → function-loader-iKhOZatS.js} +68 -38
- package/dist/function-loader-iKhOZatS.js.map +1 -0
- package/dist/{function-routes-CaNG4waN.js → function-routes-j9TwpvQe.js} +5 -4
- package/dist/function-routes-j9TwpvQe.js.map +1 -0
- package/dist/functions/context.d.ts +9 -0
- 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/index.d.ts +5 -4
- package/dist/functions/index.js +42 -13
- 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-Nr8zLvoU.js → history-recorder-BfWRwmPy.js} +3 -3
- package/dist/{history-recorder-Nr8zLvoU.js.map → history-recorder-BfWRwmPy.js.map} +1 -1
- package/dist/{history-store-rcAm_xFR.js → history-store-DPofGVDp.js} +2 -2
- package/dist/{history-store-rcAm_xFR.js.map → history-store-DPofGVDp.js.map} +1 -1
- package/dist/index.d.ts +23 -10
- package/dist/index.es.js +24423 -20038
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +27 -10
- package/dist/init/process-safety.d.ts +7 -2
- package/dist/init/shutdown.d.ts +18 -3
- package/dist/init.d.ts +49 -865
- 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-DqYNfquG.js → jobs-BCbflZj2.js} +234 -24
- package/dist/jobs-BCbflZj2.js.map +1 -0
- package/dist/{jwt-R6bSPMjk.js → jwt-BlvuKoR6.js} +529 -454
- package/dist/jwt-BlvuKoR6.js.map +1 -0
- package/dist/{keys-GAVZqbqx.js → keys-COzQ2aE8.js} +2 -2
- package/dist/{keys-GAVZqbqx.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/mcp/mcp-routes.d.ts +6 -0
- package/dist/mcp/mcp-tools.d.ts +8 -0
- package/dist/mcp/oauth-routes.d.ts +7 -0
- 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-DAq_XVDu.js → openapi-generator-D9zUQmEp.js} +366 -82
- package/dist/openapi-generator-D9zUQmEp.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-qRlqeUmO.js → proxy-CkTlMGmh.js} +4 -3
- package/dist/proxy-CkTlMGmh.js.map +1 -0
- package/dist/{query-parser-BgiKJKvc.js → query-parser-4WkMoA_K.js} +510 -15
- package/dist/query-parser-4WkMoA_K.js.map +1 -0
- package/dist/{request-timeout-DgH7j8qO.js → request-timeout-Dnl2_OBc.js} +15 -8
- package/dist/request-timeout-Dnl2_OBc.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 +10 -0
- package/dist/schema-edit/local-source.d.ts +29 -0
- package/dist/schema-edit/remote-source.d.ts +13 -3
- package/dist/schema-edit/source-editor.d.ts +28 -0
- package/dist/{schema-editor-routes-oIyuWl3L.js → schema-editor-routes-C11Tumyd.js} +54 -10
- package/dist/schema-editor-routes-C11Tumyd.js.map +1 -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 +5 -0
- package/dist/services/webhook-service.d.ts +66 -14
- package/dist/singleton.d.ts +9 -5
- package/dist/soft-delete-params-DfV3vVN5.js +668 -0
- package/dist/soft-delete-params-DfV3vVN5.js.map +1 -0
- package/dist/sql-export-routes-ClRwzIsC.js +240 -0
- package/dist/sql-export-routes-ClRwzIsC.js.map +1 -0
- package/dist/{src-CatHFUym.js → src-D5Y3N-S4.js} +2 -1
- package/dist/{src-CatHFUym.js.map → src-D5Y3N-S4.js.map} +1 -1
- package/dist/storage/GCSStorageController.d.ts +46 -2
- package/dist/storage/LocalStorageController.d.ts +67 -2
- package/dist/storage/S3StorageController.d.ts +37 -3
- package/dist/storage/image-transform.d.ts +5 -0
- package/dist/storage/maintenance-routes.d.ts +23 -0
- package/dist/storage/maintenance.d.ts +126 -0
- package/dist/storage/rendition-cache.d.ts +9 -11
- package/dist/storage/request-principals.d.ts +30 -0
- package/dist/storage/routes.d.ts +20 -0
- package/dist/storage/source-variables.d.ts +10 -0
- package/dist/storage/streams.d.ts +42 -0
- package/dist/storage/tus-handler.d.ts +46 -2
- package/dist/storage/types.d.ts +82 -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-Dd-fnsbA.js +172 -0
- package/dist/upload-validation-Dd-fnsbA.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/package.json +5 -5
- package/dist/GCSStorageController-BSiP1c-f.js +0 -256
- package/dist/GCSStorageController-BSiP1c-f.js.map +0 -1
- package/dist/S3StorageController-CAwFRgjV.js +0 -276
- package/dist/S3StorageController-CAwFRgjV.js.map +0 -1
- package/dist/auth-DMLngxn_.js.map +0 -1
- package/dist/backup-CN0s50D2.js.map +0 -1
- package/dist/contract-routes-fz8i4pxs.js.map +0 -1
- package/dist/cron-loader-CwaANlOG.js +0 -118
- package/dist/cron-loader-CwaANlOG.js.map +0 -1
- package/dist/cron-routes-Bc-SB0Se.js.map +0 -1
- package/dist/cron-scheduler-CYQgco86.js.map +0 -1
- package/dist/cron-store-D2Q9-Aco.js +0 -300
- package/dist/cron-store-D2Q9-Aco.js.map +0 -1
- package/dist/dynamic-import-X40pTZUQ.js +0 -23
- package/dist/dynamic-import-X40pTZUQ.js.map +0 -1
- package/dist/function-loader-D7o5Epjj.js.map +0 -1
- package/dist/function-routes-CaNG4waN.js.map +0 -1
- package/dist/jobs-DqYNfquG.js.map +0 -1
- package/dist/jwt-R6bSPMjk.js.map +0 -1
- package/dist/openapi-generator-DAq_XVDu.js.map +0 -1
- package/dist/proxy-qRlqeUmO.js.map +0 -1
- package/dist/query-parser-BgiKJKvc.js.map +0 -1
- package/dist/request-timeout-DgH7j8qO.js.map +0 -1
- package/dist/schema-editor-routes-oIyuWl3L.js.map +0 -1
- package/dist/soft-delete-params-BWPilMPF.js +0 -59
- package/dist/soft-delete-params-BWPilMPF.js.map +0 -1
- package/dist/src-I3aG1PcY.js +0 -6870
- package/dist/src-I3aG1PcY.js.map +0 -1
- package/dist/types-BfKcm9do.js +0 -39
- package/dist/types-BfKcm9do.js.map +0 -1
|
@@ -3,6 +3,7 @@ import type { MiddlewareHandler } from "hono";
|
|
|
3
3
|
import type { AuthModuleConfig, CreateSessionAndTokens } from "./routes.js";
|
|
4
4
|
import type { ResolvedAuthHooks } from "./auth-hooks.js";
|
|
5
5
|
import type { HonoEnv } from "../api/types.js";
|
|
6
|
+
import { type AuthLimiters } from "./rate-limiter.js";
|
|
6
7
|
import { z } from "zod";
|
|
7
8
|
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
8
9
|
/**
|
|
@@ -13,6 +14,8 @@ import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasep
|
|
|
13
14
|
export declare function mountMagicLinkRoutes(deps: {
|
|
14
15
|
router: Hono<HonoEnv>;
|
|
15
16
|
config: AuthModuleConfig;
|
|
17
|
+
/** The backend's auth limiters. */
|
|
18
|
+
limiters: AuthLimiters;
|
|
16
19
|
ops: ResolvedAuthHooks;
|
|
17
20
|
parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T;
|
|
18
21
|
buildAuthResponse: (user: {
|
|
@@ -36,13 +36,16 @@
|
|
|
36
36
|
*
|
|
37
37
|
* @module
|
|
38
38
|
*/
|
|
39
|
+
import { type JwtService } from "./jwt.js";
|
|
39
40
|
/**
|
|
40
41
|
* Encrypt a plaintext TOTP secret.
|
|
41
42
|
*
|
|
42
43
|
* @param plaintext - The Base32 TOTP secret to encrypt.
|
|
44
|
+
* @param jwt - The backend whose JWT secret is the last key fallback. The
|
|
45
|
+
* process default when omitted.
|
|
43
46
|
* @returns A string in the format `v1.<keyId>:iv_hex:authTag_hex:ciphertext_hex`.
|
|
44
47
|
*/
|
|
45
|
-
export declare function encryptTotpSecret(plaintext: string): string;
|
|
48
|
+
export declare function encryptTotpSecret(plaintext: string, jwt?: JwtService): string;
|
|
46
49
|
/** What a factor's stored secret opened to, and whether it should be re-stored. */
|
|
47
50
|
export interface OpenedTotpSecret {
|
|
48
51
|
/** The Base32 TOTP secret. */
|
|
@@ -59,8 +62,10 @@ export interface OpenedTotpSecret {
|
|
|
59
62
|
*
|
|
60
63
|
* Accepts both the key-stamped format and the original unstamped
|
|
61
64
|
* `iv:authTag:ciphertext`, which is tried against each candidate in turn.
|
|
65
|
+
* `jwt` is the backend whose JWT secret is the last key fallback — the process
|
|
66
|
+
* default when omitted.
|
|
62
67
|
*/
|
|
63
|
-
export declare function openTotpSecret(ciphertext: string): OpenedTotpSecret;
|
|
68
|
+
export declare function openTotpSecret(ciphertext: string, jwt?: JwtService): OpenedTotpSecret;
|
|
64
69
|
/**
|
|
65
70
|
* Decrypt a previously encrypted TOTP secret.
|
|
66
71
|
*
|
|
@@ -69,6 +74,7 @@ export declare function openTotpSecret(ciphertext: string): OpenedTotpSecret;
|
|
|
69
74
|
* on whichever key it was written with.
|
|
70
75
|
*
|
|
71
76
|
* @param ciphertext - A stored TOTP secret, in either format.
|
|
77
|
+
* @param jwt - The backend whose JWT secret is the last key fallback.
|
|
72
78
|
* @returns The original Base32 TOTP secret.
|
|
73
79
|
*/
|
|
74
|
-
export declare function decryptTotpSecret(ciphertext: string): string;
|
|
80
|
+
export declare function decryptTotpSecret(ciphertext: string, jwt?: JwtService): string;
|
package/dist/auth/mfa-gate.d.ts
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*
|
|
13
13
|
* @module
|
|
14
14
|
*/
|
|
15
|
+
import type { JwtService } from "./jwt.js";
|
|
15
16
|
import type { AuthRepository } from "./interfaces.js";
|
|
16
17
|
/** Error code a client watches for to switch a sign-in into its second step. */
|
|
17
18
|
export declare const MFA_REQUIRED_CODE = "MFA_REQUIRED";
|
|
@@ -37,6 +38,7 @@ export interface MfaRequiredDetails {
|
|
|
37
38
|
*
|
|
38
39
|
* A 401 rather than a 200 with a different body: a client that has not been
|
|
39
40
|
* taught about MFA must fail, not proceed. The credential in `details` is
|
|
40
|
-
* useless for anything except the challenge routes
|
|
41
|
+
* useless for anything except the challenge routes, and is signed by `jwt` —
|
|
42
|
+
* the backend's own key.
|
|
41
43
|
*/
|
|
42
|
-
export declare function assertMfaSatisfied(authRepo: AuthRepository, uid: string): Promise<void>;
|
|
44
|
+
export declare function assertMfaSatisfied(authRepo: AuthRepository, uid: string, jwt: JwtService): Promise<void>;
|
|
@@ -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 AuthLimiters } from "./rate-limiter.js";
|
|
5
|
+
import type { JwtService } from "./jwt.js";
|
|
4
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
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MiddlewareHandler, Context } from "hono";
|
|
2
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";
|
|
@@ -151,7 +151,14 @@ export declare const requireAdmin: MiddlewareHandler<HonoEnv>;
|
|
|
151
151
|
*/
|
|
152
152
|
export declare const optionalAuth: MiddlewareHandler<HonoEnv>;
|
|
153
153
|
/**
|
|
154
|
-
*
|
|
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.
|
|
155
162
|
*/
|
|
156
163
|
export declare function extractUserFromToken(token: string): Promise<AccessTokenPayload | null>;
|
|
157
164
|
/**
|
|
@@ -45,6 +45,7 @@ import { z } from "zod";
|
|
|
45
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: {
|
|
@@ -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
|
*
|
|
@@ -118,15 +129,7 @@ export declare function createRateLimiter(options?: RateLimiterOptions): Middlew
|
|
|
118
129
|
* `"unknown"` for every direct connection.
|
|
119
130
|
*/
|
|
120
131
|
export declare function requestClientAddress(c: Parameters<MiddlewareHandler<HonoEnv>>[0]): string;
|
|
121
|
-
/**
|
|
122
|
-
* Pre-configured rate limiter for general auth endpoints (login, register).
|
|
123
|
-
* 200 requests per 15 minutes per IP.
|
|
124
|
-
*/
|
|
125
132
|
export declare const defaultAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
126
|
-
/**
|
|
127
|
-
* Pre-configured strict rate limiter for sensitive endpoints (password reset, verification).
|
|
128
|
-
* 50 requests per 15 minutes per IP.
|
|
129
|
-
*/
|
|
130
133
|
export declare const strictAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
131
134
|
/**
|
|
132
135
|
* Limiter for `POST /auth/send-verification`, keyed by the authenticated user.
|
|
@@ -159,22 +162,6 @@ export declare const strictAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
|
159
162
|
* that names the field; failing here would answer 429 to bad JSON.
|
|
160
163
|
*/
|
|
161
164
|
export declare const captureRecipientEmail: MiddlewareHandler<HonoEnv>;
|
|
162
|
-
/**
|
|
163
|
-
* Per-ADDRESS throttle for a route that mails an address the caller named.
|
|
164
|
-
*
|
|
165
|
-
* `strictAuthLimiter` bounds a machine, and a machine is the attacker's to
|
|
166
|
-
* multiply. The mailbox being filled belongs to somebody who cannot rotate
|
|
167
|
-
* anything, and the domain the messages come from is this deployment's
|
|
168
|
-
* reputation — so a distributed run against one address passed the IP limiter
|
|
169
|
-
* untouched and cost the operator their sender score.
|
|
170
|
-
*
|
|
171
|
-
* Five per fifteen minutes: generous for "I didn't get it, send it again",
|
|
172
|
-
* useless as a mail bomb. The same numbers as `verificationEmailLimiter`,
|
|
173
|
-
* which bounds the same act for a signed-in caller.
|
|
174
|
-
*
|
|
175
|
-
* Falls back to the IP bucket for a request whose body named no address, so
|
|
176
|
-
* the limiter is never silently a no-op.
|
|
177
|
-
*/
|
|
178
165
|
export declare const recipientEmailLimiter: MiddlewareHandler<HonoEnv>;
|
|
179
166
|
/**
|
|
180
167
|
* How long a route that answers "if an account exists…" takes, whoever asked.
|
|
@@ -198,6 +185,43 @@ export declare const RECIPIENT_ROUTE_FLOOR_MS = 400;
|
|
|
198
185
|
/** Hold a result until at least `floorMs` has passed since `startedAt`. */
|
|
199
186
|
export declare function notBefore<T>(startedAt: number, floorMs: number, result: T): Promise<T>;
|
|
200
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;
|
|
201
225
|
/**
|
|
202
226
|
* Key generator for API-key-based rate limiting.
|
|
203
227
|
*
|
|
@@ -270,7 +294,11 @@ export declare const DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT = 3000;
|
|
|
270
294
|
* set them, and one that already has a proxy doing this should pass
|
|
271
295
|
* `enabled: false` rather than pay for it twice.
|
|
272
296
|
*/
|
|
273
|
-
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>;
|
|
274
302
|
/**
|
|
275
303
|
* The data API's per-caller limit, as a check rather than a middleware — for
|
|
276
304
|
* the door into the same data that is not an HTTP request.
|
|
@@ -283,4 +311,3 @@ export declare function createDataRateLimiter(config?: DataRateLimitConfig): Mid
|
|
|
283
311
|
* same key: one person's allowance, spent through either door.
|
|
284
312
|
*/
|
|
285
313
|
export declare function createDataRateLimitCheck(config?: DataRateLimitConfig): (caller: DataRateLimitCaller) => Promise<RateLimitDecision | null>;
|
|
286
|
-
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,9 +1,12 @@
|
|
|
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";
|
|
7
10
|
import { isDeliverableAddress } from "./deliverable-address.js";
|
|
8
11
|
export { isDeliverableAddress };
|
|
9
12
|
/**
|
|
@@ -11,6 +14,19 @@ export { isDeliverableAddress };
|
|
|
11
14
|
*/
|
|
12
15
|
export interface AuthModuleConfig {
|
|
13
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;
|
|
14
30
|
/**
|
|
15
31
|
* Bot protection. Off unless `enabled`.
|
|
16
32
|
*
|
|
@@ -2,11 +2,17 @@ import { Hono } from "hono";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { HonoEnv } from "../api/types.js";
|
|
4
4
|
import type { MiddlewareHandler } from "hono";
|
|
5
|
+
import { type AuthLimiters } from "./rate-limiter.js";
|
|
6
|
+
import { type JwtService } from "./jwt.js";
|
|
5
7
|
import type { AuthModuleConfig, CreateSessionAndTokens } from "./routes.js";
|
|
6
8
|
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
7
9
|
import type { resolveAuthHooks } from "./auth-hooks.js";
|
|
8
10
|
interface SessionRoutesConfig {
|
|
9
11
|
router: Hono<HonoEnv>;
|
|
12
|
+
/** The backend these routes sign and verify for. */
|
|
13
|
+
jwt: JwtService;
|
|
14
|
+
/** The backend's auth limiters. */
|
|
15
|
+
limiters: AuthLimiters;
|
|
10
16
|
config: AuthModuleConfig;
|
|
11
17
|
/**
|
|
12
18
|
* The caller's guard for a signed-in user, with the revocation watermark
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who may read the user picker (`GET /api/admin/users/pick`).
|
|
3
|
+
*
|
|
4
|
+
* A `userSelect` field stores a user's id, and the person filling it in picks
|
|
5
|
+
* that user from a list. Listing the users is an admin-plane read
|
|
6
|
+
* (`users:read`), which an editor does not hold — so the picker answers a
|
|
7
|
+
* narrower question for a wider audience: id, name, email and avatar, to
|
|
8
|
+
* anyone who may write a collection that has such a field.
|
|
9
|
+
*
|
|
10
|
+
* "May write" is the collection's `securityRules` for an insert or an update,
|
|
11
|
+
* evaluated the way the admin panel decides whether to offer the form, with
|
|
12
|
+
* one difference. A rule that depends only on the row (an owner field) counts
|
|
13
|
+
* as allowing, since the person may write some row. A rule written as SQL the
|
|
14
|
+
* policy model cannot read cannot be judged ahead, and here it counts as
|
|
15
|
+
* refusing: read optimistically, it would let any signed-in person list every
|
|
16
|
+
* user's name and email. A key or token narrowed by scopes must also hold
|
|
17
|
+
* `data:write` on that collection.
|
|
18
|
+
*
|
|
19
|
+
* The collections are the backend's own (`c.var.services`), read when the
|
|
20
|
+
* question is asked, so a schema edited live is what is judged.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import type { Context } from "hono";
|
|
25
|
+
import { type CollectionConfig, type Properties } from "@rebasepro/types";
|
|
26
|
+
import type { HonoEnv } from "../api/types.js";
|
|
27
|
+
/** Tell the process default's picker which collections it serves. */
|
|
28
|
+
export declare function configureUserPicking(collections: () => readonly CollectionConfig[]): void;
|
|
29
|
+
/** @internal The process default's collections getter, to snapshot or restore it. */
|
|
30
|
+
export declare function defaultUserPicking(): () => readonly CollectionConfig[];
|
|
31
|
+
/** Whether any property, at any depth, is a `userSelect` field. */
|
|
32
|
+
export declare function propertiesReferenceUsers(properties: Properties | undefined): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Whether this request's caller may read the user picker: they hold
|
|
35
|
+
* `users:read`, or they may write a collection with a `userSelect` field.
|
|
36
|
+
*/
|
|
37
|
+
export declare function mayPickUsers(c: Context<HonoEnv>): boolean;
|
|
@@ -7,9 +7,15 @@
|
|
|
7
7
|
* token, and an API key (`rk_`). Both come back as who the caller acts as and
|
|
8
8
|
* what it may do, so the endpoint checks a scope the same way either way.
|
|
9
9
|
*
|
|
10
|
+
* A backend answers for itself — `backend.verifyCredential(token)`, against its
|
|
11
|
+
* own keys, store and access model. {@link verifyCredential} answers for the
|
|
12
|
+
* process default.
|
|
13
|
+
*
|
|
10
14
|
* @module
|
|
11
15
|
*/
|
|
12
16
|
import type { ApiKeyStore } from "./api-keys/api-key-store.js";
|
|
17
|
+
import { type AccessControl } from "./access.js";
|
|
18
|
+
import { type JwtService } from "./jwt.js";
|
|
13
19
|
/** Who a verified credential acts as, and what it may do. */
|
|
14
20
|
export interface VerifiedCredential {
|
|
15
21
|
uid: string;
|
|
@@ -18,11 +24,26 @@ export interface VerifiedCredential {
|
|
|
18
24
|
/** `"api-key"` when an `rk_` key was presented, otherwise `"session"`. */
|
|
19
25
|
kind: "session" | "api-key";
|
|
20
26
|
}
|
|
21
|
-
/**
|
|
27
|
+
/** What a credential is checked against: one backend's keys, key store and access model. */
|
|
28
|
+
export interface CredentialAuthority {
|
|
29
|
+
jwt: JwtService;
|
|
30
|
+
access: AccessControl;
|
|
31
|
+
apiKeyStore?: ApiKeyStore;
|
|
32
|
+
}
|
|
33
|
+
/** Install the key store the process default's {@link verifyCredential} checks `rk_` keys against. */
|
|
22
34
|
export declare function configureCredentialStore(store: ApiKeyStore | undefined): void;
|
|
35
|
+
/** @internal The process default's key store, to snapshot or restore it. */
|
|
36
|
+
export declare function defaultCredentialStore(): ApiKeyStore | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The identity and scopes behind a bearer credential, checked against one
|
|
39
|
+
* backend, or null when it does not verify — expired, revoked, unknown, or a
|
|
40
|
+
* key on a backend with no key store.
|
|
41
|
+
*/
|
|
42
|
+
export declare function verifyCredentialAgainst(authority: CredentialAuthority, token: string): Promise<VerifiedCredential | null>;
|
|
23
43
|
/**
|
|
24
|
-
* The identity and scopes behind a bearer credential,
|
|
25
|
-
*
|
|
26
|
-
*
|
|
44
|
+
* The identity and scopes behind a bearer credential, as the process default
|
|
45
|
+
* answers — expired, revoked, unknown, or a key on a backend with no key store
|
|
46
|
+
* all come back null. A backend built by `createRebaseBackend` answers for
|
|
47
|
+
* itself: `backend.verifyCredential(token)`.
|
|
27
48
|
*/
|
|
28
49
|
export declare function verifyCredential(token: string): Promise<VerifiedCredential | null>;
|