@rebasepro/server 0.0.1-canary.4829d6e
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/LICENSE +22 -0
- package/README.md +77 -0
- package/dist/api/ast-schema-editor.d.ts +21 -0
- package/dist/api/collections_for_test/callbacks_test_collection.d.ts +2 -0
- package/dist/api/errors.d.ts +53 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/logs-routes.d.ts +37 -0
- package/dist/api/openapi-generator.d.ts +16 -0
- package/dist/api/rest/api-generator.d.ts +68 -0
- package/dist/api/rest/index.d.ts +1 -0
- package/dist/api/rest/query-parser.d.ts +6 -0
- package/dist/api/schema-editor-routes.d.ts +3 -0
- package/dist/api/types.d.ts +56 -0
- package/dist/auth/adapter-middleware.d.ts +43 -0
- package/dist/auth/admin-roles-route.d.ts +18 -0
- package/dist/auth/admin-user-ops.d.ts +80 -0
- package/dist/auth/admin-users-route.d.ts +28 -0
- package/dist/auth/api-keys/api-key-middleware.d.ts +39 -0
- package/dist/auth/api-keys/api-key-permission-guard.d.ts +32 -0
- package/dist/auth/api-keys/api-key-routes.d.ts +20 -0
- package/dist/auth/api-keys/api-key-store.d.ts +35 -0
- package/dist/auth/api-keys/api-key-types.d.ts +96 -0
- package/dist/auth/api-keys/index.d.ts +17 -0
- package/dist/auth/apple-oauth.d.ts +30 -0
- package/dist/auth/auth-hooks.d.ts +242 -0
- package/dist/auth/bitbucket-oauth.d.ts +11 -0
- package/dist/auth/builtin-auth-adapter.d.ts +55 -0
- package/dist/auth/cookie-utils.d.ts +32 -0
- package/dist/auth/crypto-utils.d.ts +16 -0
- package/dist/auth/custom-auth-adapter.d.ts +39 -0
- package/dist/auth/discord-oauth.d.ts +14 -0
- package/dist/auth/facebook-oauth.d.ts +14 -0
- package/dist/auth/github-oauth.d.ts +15 -0
- package/dist/auth/gitlab-oauth.d.ts +13 -0
- package/dist/auth/google-oauth.d.ts +47 -0
- package/dist/auth/index.d.ts +38 -0
- package/dist/auth/interfaces.d.ts +431 -0
- package/dist/auth/jwt.d.ts +67 -0
- package/dist/auth/linkedin-oauth.d.ts +18 -0
- package/dist/auth/magic-link-routes.d.ts +32 -0
- package/dist/auth/mfa-crypto.d.ts +23 -0
- package/dist/auth/mfa-routes.d.ts +7 -0
- package/dist/auth/mfa.d.ts +49 -0
- package/dist/auth/microsoft-oauth.d.ts +16 -0
- package/dist/auth/middleware.d.ts +158 -0
- package/dist/auth/password.d.ts +22 -0
- package/dist/auth/rate-limiter.d.ts +50 -0
- package/dist/auth/reset-password-admin.d.ts +29 -0
- package/dist/auth/rls-scope.d.ts +31 -0
- package/dist/auth/routes.d.ts +66 -0
- package/dist/auth/session-routes.d.ts +29 -0
- package/dist/auth/slack-oauth.d.ts +12 -0
- package/dist/auth/spotify-oauth.d.ts +12 -0
- package/dist/auth/twitter-oauth.d.ts +18 -0
- package/dist/backup/backup-common.d.ts +31 -0
- package/dist/backup/backup-routes.d.ts +22 -0
- package/dist/backup/index.d.ts +7 -0
- package/dist/collections/BackendCollectionRegistry.d.ts +13 -0
- package/dist/collections/loader.d.ts +39 -0
- package/dist/cron/cron-loader.d.ts +18 -0
- package/dist/cron/cron-routes.d.ts +14 -0
- package/dist/cron/cron-scheduler.d.ts +106 -0
- package/dist/cron/cron-store.d.ts +32 -0
- package/dist/cron/define-cron.d.ts +28 -0
- package/dist/cron/index.d.ts +7 -0
- package/dist/db/interfaces.d.ts +18 -0
- package/dist/dynamic-import-Dvh-K5fl.js +22 -0
- package/dist/dynamic-import-Dvh-K5fl.js.map +1 -0
- package/dist/email/index.d.ts +6 -0
- package/dist/email/smtp-email-service.d.ts +30 -0
- package/dist/email/templates.d.ts +50 -0
- package/dist/email/types.d.ts +126 -0
- package/dist/env.d.ts +102 -0
- package/dist/functions/define-function.d.ts +55 -0
- package/dist/functions/function-loader.d.ts +18 -0
- package/dist/functions/function-routes.d.ts +10 -0
- package/dist/functions/index.d.ts +5 -0
- package/dist/history/history-routes.d.ts +23 -0
- package/dist/history/index.d.ts +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.es.js +18458 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +48745 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/init/docs.d.ts +4 -0
- package/dist/init/health.d.ts +2 -0
- package/dist/init/middlewares.d.ts +10 -0
- package/dist/init/shutdown.d.ts +65 -0
- package/dist/init/storage.d.ts +5 -0
- package/dist/init.d.ts +375 -0
- package/dist/jwt-BwIn8xmk.js +4200 -0
- package/dist/jwt-BwIn8xmk.js.map +1 -0
- package/dist/logger-BYU66ENZ.js +94 -0
- package/dist/logger-BYU66ENZ.js.map +1 -0
- package/dist/ms-DnYXB-Wd.js +162 -0
- package/dist/ms-DnYXB-Wd.js.map +1 -0
- package/dist/openapi-generator-Z9oYWLf_.js +586 -0
- package/dist/openapi-generator-Z9oYWLf_.js.map +1 -0
- package/dist/schema-editor-routes-D3ef8zu1.js +219 -0
- package/dist/schema-editor-routes-D3ef8zu1.js.map +1 -0
- package/dist/serve-spa.d.ts +36 -0
- package/dist/services/driver-registry.d.ts +78 -0
- package/dist/services/routed-realtime-service.d.ts +43 -0
- package/dist/services/webhook-service.d.ts +29 -0
- package/dist/singleton.d.ts +51 -0
- package/dist/src-B4OLmNVa.js +437 -0
- package/dist/src-B4OLmNVa.js.map +1 -0
- package/dist/src-B9tjYmqP.js +24598 -0
- package/dist/src-B9tjYmqP.js.map +1 -0
- package/dist/storage/GCSStorageController.d.ts +43 -0
- package/dist/storage/LocalStorageController.d.ts +46 -0
- package/dist/storage/S3StorageController.d.ts +40 -0
- package/dist/storage/image-transform.d.ts +50 -0
- package/dist/storage/index.d.ts +31 -0
- package/dist/storage/routes.d.ts +70 -0
- package/dist/storage/storage-registry.d.ts +78 -0
- package/dist/storage/tus-handler.d.ts +53 -0
- package/dist/storage/types.d.ts +128 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/utils/dev-port.d.ts +45 -0
- package/dist/utils/dynamic-import.d.ts +25 -0
- package/dist/utils/logger.d.ts +31 -0
- package/dist/utils/logging.d.ts +9 -0
- package/dist/utils/request-id.d.ts +4 -0
- package/dist/utils/request-logger.d.ts +19 -0
- package/dist/utils/sql.d.ts +27 -0
- package/package.json +115 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TOTP (Time-based One-Time Password) implementation.
|
|
3
|
+
*
|
|
4
|
+
* Pure Node.js crypto implementation — no external dependencies required.
|
|
5
|
+
* Implements RFC 6238 (TOTP) and RFC 4226 (HOTP).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Encode a Buffer to Base32 string (RFC 4648)
|
|
9
|
+
*/
|
|
10
|
+
export declare function base32Encode(buffer: Buffer): string;
|
|
11
|
+
/**
|
|
12
|
+
* Decode a Base32 string to Buffer
|
|
13
|
+
*/
|
|
14
|
+
export declare function base32Decode(encoded: string): Buffer;
|
|
15
|
+
/**
|
|
16
|
+
* Generate a TOTP value for the current time step
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateTotp(secret: Buffer, timeStep?: number): string;
|
|
19
|
+
/**
|
|
20
|
+
* Verify a TOTP token with a configurable time window
|
|
21
|
+
*
|
|
22
|
+
* @param secret - The shared secret as a Buffer
|
|
23
|
+
* @param token - The 6-digit TOTP code to verify
|
|
24
|
+
* @param window - Number of time steps to check on each side (default: 1)
|
|
25
|
+
* @returns true if the token is valid within the window
|
|
26
|
+
*/
|
|
27
|
+
export declare function verifyTotp(secret: Buffer, token: string, window?: number): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Generate a new TOTP secret and return the setup information
|
|
30
|
+
*
|
|
31
|
+
* @param issuer - The issuer name (app name) for the QR code
|
|
32
|
+
* @param accountName - The account identifier (usually email)
|
|
33
|
+
* @returns Object with base32 secret and otpauth URI
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateTotpSecret(issuer: string, accountName: string): {
|
|
36
|
+
secret: string;
|
|
37
|
+
uri: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Generate a set of one-time recovery codes
|
|
41
|
+
*
|
|
42
|
+
* @param count - Number of recovery codes to generate (default: 10)
|
|
43
|
+
* @returns Array of formatted recovery code strings (e.g. "A1B2C-D3E4F")
|
|
44
|
+
*/
|
|
45
|
+
export declare function generateRecoveryCodes(count?: number): string[];
|
|
46
|
+
/**
|
|
47
|
+
* Hash a recovery code for storage
|
|
48
|
+
*/
|
|
49
|
+
export declare function hashRecoveryCode(code: string): string;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a Microsoft / Entra ID (Azure AD) OAuth Provider integration.
|
|
4
|
+
*
|
|
5
|
+
* Supports both personal Microsoft accounts and work/school (Azure AD) accounts
|
|
6
|
+
* via the "common" tenant endpoint. Uses the authorization code flow.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createMicrosoftProvider(config: {
|
|
9
|
+
clientId: string;
|
|
10
|
+
clientSecret: string;
|
|
11
|
+
/** Tenant ID. Defaults to "common" which allows both personal and organizational accounts. */
|
|
12
|
+
tenantId?: string;
|
|
13
|
+
}): OAuthProvider<{
|
|
14
|
+
code: string;
|
|
15
|
+
redirectUri: string;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { MiddlewareHandler, Context } from "hono";
|
|
2
|
+
import { DataDriver } from "@rebasepro/types";
|
|
3
|
+
import { AccessTokenPayload } from "./jwt";
|
|
4
|
+
import { HonoEnv } from "../api/types";
|
|
5
|
+
import type { ApiKeyStore } from "./api-keys/api-key-store";
|
|
6
|
+
/**
|
|
7
|
+
* Result from a custom auth validator.
|
|
8
|
+
* - `false`/`null`/`undefined` = not authenticated
|
|
9
|
+
* - `true` = authenticated as default user
|
|
10
|
+
* - object with `userId` or `uid` = authenticated with user info
|
|
11
|
+
*/
|
|
12
|
+
export type AuthResult = boolean | null | undefined | {
|
|
13
|
+
userId?: string;
|
|
14
|
+
uid?: string;
|
|
15
|
+
roles?: string[];
|
|
16
|
+
[key: string]: unknown;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Options for creating an auth middleware via createAuthMiddleware()
|
|
20
|
+
*/
|
|
21
|
+
export interface AuthMiddlewareOptions {
|
|
22
|
+
/** DataDriver to scope via withAuth() for RLS */
|
|
23
|
+
driver: DataDriver;
|
|
24
|
+
/**
|
|
25
|
+
* Optional per-request driver resolver for multi-data-source backends.
|
|
26
|
+
* Given the request context, returns the unscoped delegate to use (e.g.
|
|
27
|
+
* Postgres vs Mongo, picked by the request's collection data source).
|
|
28
|
+
* When omitted, `driver` is used for every request.
|
|
29
|
+
*/
|
|
30
|
+
resolveDriver?: (c: Context<HonoEnv>) => DataDriver;
|
|
31
|
+
/**
|
|
32
|
+
* If true, return 401 when no valid token is present.
|
|
33
|
+
*
|
|
34
|
+
* **Defaults to `true` (secure by default).** Set to `false` only for
|
|
35
|
+
* intentionally public endpoints where access control is fully delegated
|
|
36
|
+
* to Postgres Row-Level Security policies.
|
|
37
|
+
*/
|
|
38
|
+
requireAuth?: boolean;
|
|
39
|
+
/** Optional custom validator (for non-JWT auth, e.g. external auth providers) */
|
|
40
|
+
validator?: (c: Context<HonoEnv>) => Promise<AuthResult>;
|
|
41
|
+
/**
|
|
42
|
+
* A static secret key for server-to-server / script authentication.
|
|
43
|
+
*
|
|
44
|
+
* When a request sends `Authorization: Bearer <key>` and the key matches
|
|
45
|
+
* this value, the request is granted admin-level access (uid: `service`,
|
|
46
|
+
* roles: `["admin"]`) **without** JWT verification. The driver is scoped
|
|
47
|
+
* via `withAuth()` with the service identity.
|
|
48
|
+
*
|
|
49
|
+
* This is the Rebase equivalent of a Service Account key.
|
|
50
|
+
* Set via `REBASE_SERVICE_KEY` in `.env` and pass through the backend config.
|
|
51
|
+
*
|
|
52
|
+
* **Security:** The comparison uses constant-time equality to prevent
|
|
53
|
+
* timing attacks. The key must be at least 32 characters.
|
|
54
|
+
*/
|
|
55
|
+
serviceKey?: string;
|
|
56
|
+
/**
|
|
57
|
+
* API key store for authenticating `rk_` prefixed tokens.
|
|
58
|
+
* When set, tokens starting with `rk_` are validated against the
|
|
59
|
+
* database instead of being treated as JWTs.
|
|
60
|
+
*/
|
|
61
|
+
apiKeyStore?: ApiKeyStore;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Hono middleware that requires a valid JWT token via Authorization header.
|
|
65
|
+
* Returns 401 if token is missing or invalid.
|
|
66
|
+
*
|
|
67
|
+
* **Security:** Tokens are only accepted via the `Authorization: Bearer`
|
|
68
|
+
* header. Query-string tokens (`?token=`) are intentionally NOT accepted
|
|
69
|
+
* here because URLs leak into access logs, proxies, Referer headers, and
|
|
70
|
+
* browser history. Use {@link queryTokenAuth} on routes that legitimately
|
|
71
|
+
* need query-string tokens (e.g. storage file serving for `<img src>`).
|
|
72
|
+
*/
|
|
73
|
+
export declare const requireAuth: MiddlewareHandler<HonoEnv>;
|
|
74
|
+
/**
|
|
75
|
+
* Factory that creates a requireAuth middleware with optional service key support.
|
|
76
|
+
*
|
|
77
|
+
* When `serviceKey` is provided, the middleware will check if the Bearer token
|
|
78
|
+
* matches the service key using constant-time comparison. If it matches, the
|
|
79
|
+
* request is authenticated as a service user with admin privileges.
|
|
80
|
+
*
|
|
81
|
+
* This allows admin routes (which use standalone requireAuth + requireAdmin)
|
|
82
|
+
* to be accessed via service keys for scripts and server-to-server calls.
|
|
83
|
+
*/
|
|
84
|
+
export declare function createRequireAuth(options?: {
|
|
85
|
+
serviceKey?: string;
|
|
86
|
+
}): MiddlewareHandler<HonoEnv>;
|
|
87
|
+
/**
|
|
88
|
+
* Middleware that requires the user to have an admin or schema-admin role.
|
|
89
|
+
* Must be used AFTER requireAuth or on a route where user is guaranteed.
|
|
90
|
+
*/
|
|
91
|
+
export declare const requireAdmin: MiddlewareHandler<HonoEnv>;
|
|
92
|
+
/**
|
|
93
|
+
* Middleware that optionally extracts user from JWT via Authorization header.
|
|
94
|
+
* Does not return 401 if token is missing — allows anonymous access.
|
|
95
|
+
*
|
|
96
|
+
* Query-string tokens are NOT accepted here. Use {@link queryTokenAuth}
|
|
97
|
+
* on routes that need them.
|
|
98
|
+
*/
|
|
99
|
+
export declare const optionalAuth: MiddlewareHandler<HonoEnv>;
|
|
100
|
+
/**
|
|
101
|
+
* Extract user from token - for WebSocket authentication
|
|
102
|
+
*/
|
|
103
|
+
export declare function extractUserFromToken(token: string): AccessTokenPayload | null;
|
|
104
|
+
/**
|
|
105
|
+
* Create a configurable auth middleware that handles:
|
|
106
|
+
* 1. Token extraction (via custom validator or JWT Bearer token)
|
|
107
|
+
* 2. RLS-scoped DataDriver via withAuth()
|
|
108
|
+
* 3. Enforcement (401 when requireAuth is true and no user)
|
|
109
|
+
*
|
|
110
|
+
* **Secure by default:** `requireAuth` defaults to `true`. Anonymous
|
|
111
|
+
* access is only allowed when the developer explicitly opts out by
|
|
112
|
+
* setting `requireAuth: false`, indicating that Postgres RLS policies
|
|
113
|
+
* fully control access.
|
|
114
|
+
*
|
|
115
|
+
* **Fail-closed:** The raw unscoped driver is never placed in the
|
|
116
|
+
* request context. Every code path either scopes via `withAuth()` or
|
|
117
|
+
* rejects the request. This prevents silent RLS bypass.
|
|
118
|
+
*
|
|
119
|
+
* This is the single source of truth for HTTP auth in Rebase.
|
|
120
|
+
* Use this instead of manually parsing tokens in route handlers.
|
|
121
|
+
*/
|
|
122
|
+
export declare function createAuthMiddleware(options: AuthMiddlewareOptions): MiddlewareHandler<HonoEnv>;
|
|
123
|
+
/**
|
|
124
|
+
* Middleware that authenticates via a `?token=` query parameter.
|
|
125
|
+
*
|
|
126
|
+
* **Use sparingly.** Tokens in URLs leak into access logs, proxy logs,
|
|
127
|
+
* Referer headers, and browser history. This middleware exists solely for
|
|
128
|
+
* routes where the consumer cannot set HTTP headers — e.g. `<img src>`,
|
|
129
|
+
* `<a href>` for file downloads, or similar browser-native requests.
|
|
130
|
+
*
|
|
131
|
+
* Apply it **before** `requireAuth` or `optionalAuth` on the specific
|
|
132
|
+
* route that needs it. Those middlewares will see the user context this
|
|
133
|
+
* middleware sets and skip their own 401 check.
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* router.get("/file/*", queryTokenAuth, readAuthMiddleware, handler);
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
export declare const queryTokenAuth: MiddlewareHandler<HonoEnv>;
|
|
141
|
+
/**
|
|
142
|
+
* Authorizes anonymous access to **public** storage objects (those under the
|
|
143
|
+
* public prefix), which are served token-less via stable, permanent URLs.
|
|
144
|
+
*
|
|
145
|
+
* Runs on the storage `/file/*` and `/metadata/*` routes, *after* the token
|
|
146
|
+
* middleware and *before* the read-auth gate. If the request is already
|
|
147
|
+
* authenticated (Bearer or scoped token), it does nothing. Otherwise, when the
|
|
148
|
+
* requested object path is public, it sets a minimal "public" principal so the
|
|
149
|
+
* downstream `requireAuth` gate lets the read through. Private paths are left
|
|
150
|
+
* untouched, so they still require a valid token.
|
|
151
|
+
*/
|
|
152
|
+
export declare const publicObjectAuth: MiddlewareHandler<HonoEnv>;
|
|
153
|
+
/**
|
|
154
|
+
* Middleware that authenticates file-serving routes using scoped download tokens.
|
|
155
|
+
* It enforces that only scoped "file-read" tokens can access "/file/*" and "?token=" query params.
|
|
156
|
+
* Full access JWTs are explicitly rejected on "/file/*" routes, and in the "?token=" query param.
|
|
157
|
+
*/
|
|
158
|
+
export declare const fileTokenAuth: MiddlewareHandler<HonoEnv>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface PasswordValidationResult {
|
|
2
|
+
valid: boolean;
|
|
3
|
+
errors: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Password requirements:
|
|
7
|
+
* - Minimum 8 characters
|
|
8
|
+
* - At least 1 uppercase letter
|
|
9
|
+
* - At least 1 lowercase letter
|
|
10
|
+
* - At least 1 number
|
|
11
|
+
*/
|
|
12
|
+
export declare function validatePasswordStrength(password: string): PasswordValidationResult;
|
|
13
|
+
/**
|
|
14
|
+
* Hash a password using Node's built-in scrypt
|
|
15
|
+
* Returns format: salt:hash (both hex encoded)
|
|
16
|
+
*/
|
|
17
|
+
export declare function hashPassword(password: string): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Verify a password against a scrypt hash
|
|
20
|
+
* Expects format: salt:hash (both hex encoded)
|
|
21
|
+
*/
|
|
22
|
+
export declare function verifyPassword(password: string, storedHash: string): Promise<boolean>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { MiddlewareHandler } from "hono";
|
|
2
|
+
import { HonoEnv } from "../api/types";
|
|
3
|
+
interface RateLimiterOptions {
|
|
4
|
+
/** Time window in milliseconds (default: 15 minutes) */
|
|
5
|
+
windowMs?: number;
|
|
6
|
+
/** Maximum requests per window (default: 100) */
|
|
7
|
+
limit?: number;
|
|
8
|
+
/** Key generator function. Defaults to IP-based keying. */
|
|
9
|
+
keyGenerator?: (c: Parameters<MiddlewareHandler<HonoEnv>>[0]) => string;
|
|
10
|
+
/** Custom message for rate limit responses */
|
|
11
|
+
message?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create a rate-limiting middleware.
|
|
15
|
+
*
|
|
16
|
+
* Uses a sliding window algorithm: only timestamps within the last
|
|
17
|
+
* `windowMs` milliseconds are counted. Old entries are garbage-collected
|
|
18
|
+
* every `windowMs` to prevent unbounded memory growth.
|
|
19
|
+
*/
|
|
20
|
+
export declare function createRateLimiter(options?: RateLimiterOptions): MiddlewareHandler<HonoEnv>;
|
|
21
|
+
/**
|
|
22
|
+
* Pre-configured rate limiter for general auth endpoints (login, register).
|
|
23
|
+
* 200 requests per 15 minutes per IP.
|
|
24
|
+
*/
|
|
25
|
+
export declare const defaultAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
26
|
+
/**
|
|
27
|
+
* Pre-configured strict rate limiter for sensitive endpoints (password reset, verification).
|
|
28
|
+
* 50 requests per 15 minutes per IP.
|
|
29
|
+
*/
|
|
30
|
+
export declare const strictAuthLimiter: MiddlewareHandler<HonoEnv>;
|
|
31
|
+
/**
|
|
32
|
+
* Key generator for API-key-based rate limiting.
|
|
33
|
+
*
|
|
34
|
+
* Uses the API key ID (from `c.get("apiKey")`) as the rate limit key.
|
|
35
|
+
* Falls back to IP-based keying when the request is not authenticated
|
|
36
|
+
* via an API key.
|
|
37
|
+
*/
|
|
38
|
+
export declare function apiKeyKeyGenerator(c: Parameters<MiddlewareHandler<HonoEnv>>[0]): string;
|
|
39
|
+
/**
|
|
40
|
+
* Create a rate limiter specifically for API key requests.
|
|
41
|
+
*
|
|
42
|
+
* When a request is authenticated via an API key that has a `rate_limit`
|
|
43
|
+
* configured, this limiter enforces per-key limits using the key's ID
|
|
44
|
+
* as the rate limit bucket.
|
|
45
|
+
*
|
|
46
|
+
* @param defaultLimit - Fallback limit when the key has no `rate_limit` set.
|
|
47
|
+
* @param windowMs - Time window in milliseconds (default: 15 minutes).
|
|
48
|
+
*/
|
|
49
|
+
export declare function createApiKeyRateLimiter(defaultLimit?: number, windowMs?: number): MiddlewareHandler<HonoEnv>;
|
|
50
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standalone admin endpoint for resetting a user's password.
|
|
3
|
+
*
|
|
4
|
+
* Hook resolution order:
|
|
5
|
+
* 1. Collection-level hook (`auth.onResetPassword` on the collection)
|
|
6
|
+
* 2. Backend-level hook (`AuthHooks.onAdminResetPassword`)
|
|
7
|
+
* 3. Built-in default (send reset email, or generate temp password)
|
|
8
|
+
*/
|
|
9
|
+
import { Hono } from "hono";
|
|
10
|
+
import type { AuthRepository } from "./interfaces";
|
|
11
|
+
import type { AuthHooks } from "./auth-hooks";
|
|
12
|
+
import type { EmailService, EmailConfig } from "../email";
|
|
13
|
+
import type { HonoEnv } from "../api/types";
|
|
14
|
+
import type { AuthCollectionConfig } from "@rebasepro/types";
|
|
15
|
+
export interface ResetPasswordRouteConfig {
|
|
16
|
+
authRepo: AuthRepository;
|
|
17
|
+
emailService?: EmailService;
|
|
18
|
+
emailConfig?: EmailConfig;
|
|
19
|
+
serviceKey?: string;
|
|
20
|
+
authHooks?: AuthHooks;
|
|
21
|
+
/** The parsed auth config from the collection, if available. */
|
|
22
|
+
collectionAuthConfig?: AuthCollectionConfig;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Create a standalone admin route for resetting user passwords.
|
|
26
|
+
*
|
|
27
|
+
* Mounts: POST /users/:userId/reset-password
|
|
28
|
+
*/
|
|
29
|
+
export declare function createResetPasswordRoute(config: ResetPasswordRouteConfig): Hono<HonoEnv>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared RLS (Row-Level Security) scoping helper.
|
|
3
|
+
*
|
|
4
|
+
* DataDrivers may implement a `withAuth()` method that returns a scoped
|
|
5
|
+
* clone of the driver with RLS policies applied for the given user.
|
|
6
|
+
* This is database-specific (e.g. Postgres SET LOCAL ROLE) and is not
|
|
7
|
+
* part of the core DataDriver interface.
|
|
8
|
+
*
|
|
9
|
+
* This module provides the shared duck-typing logic used by the
|
|
10
|
+
* adapter-aware middleware.
|
|
11
|
+
*
|
|
12
|
+
* @module
|
|
13
|
+
*/
|
|
14
|
+
import type { DataDriver } from "@rebasepro/types";
|
|
15
|
+
/**
|
|
16
|
+
* Scope a DataDriver via `withAuth()` for RLS.
|
|
17
|
+
*
|
|
18
|
+
* SECURITY: If `withAuth()` is available but fails, the error is re-thrown
|
|
19
|
+
* so the request is **denied** rather than proceeding with unscoped access
|
|
20
|
+
* (fail-closed behavior).
|
|
21
|
+
*
|
|
22
|
+
* If the driver does not support RLS, the original driver is returned.
|
|
23
|
+
*
|
|
24
|
+
* @param driver - The DataDriver to scope.
|
|
25
|
+
* @param user - The authenticated user identity for RLS.
|
|
26
|
+
* @returns The RLS-scoped DataDriver (or the original if RLS is unsupported).
|
|
27
|
+
*/
|
|
28
|
+
export declare function scopeDataDriver(driver: DataDriver, user: {
|
|
29
|
+
uid: string;
|
|
30
|
+
roles?: string[];
|
|
31
|
+
}): Promise<DataDriver>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { AuthRepository, OAuthProvider } from "./interfaces";
|
|
3
|
+
import type { AuthHooks } from "./auth-hooks";
|
|
4
|
+
import { EmailService, EmailConfig } from "../email";
|
|
5
|
+
import { HonoEnv } from "../api/types";
|
|
6
|
+
/**
|
|
7
|
+
* Shared configuration for auth and admin route factories.
|
|
8
|
+
*/
|
|
9
|
+
export interface AuthModuleConfig {
|
|
10
|
+
authRepo: AuthRepository;
|
|
11
|
+
emailService?: EmailService;
|
|
12
|
+
emailConfig?: EmailConfig;
|
|
13
|
+
/** Allow new user registration (default: false). */
|
|
14
|
+
allowRegistration?: boolean;
|
|
15
|
+
/** Expose the authenticated email→minimal-profile lookup route (default: false). */
|
|
16
|
+
allowUserLookup?: boolean;
|
|
17
|
+
/** Default role ID to assign to new users (default: none). Must NOT be "admin". */
|
|
18
|
+
defaultRole?: string;
|
|
19
|
+
/** Optional array of OAuth providers */
|
|
20
|
+
oauthProviders?: OAuthProvider<unknown>[];
|
|
21
|
+
/** When true, blocks all self-registration regardless of `allowRegistration`. */
|
|
22
|
+
disableSelfRegistration?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Auth hooks for customizing password hashing, credential
|
|
25
|
+
* verification, lifecycle hooks, etc.
|
|
26
|
+
*/
|
|
27
|
+
authHooks?: AuthHooks;
|
|
28
|
+
/**
|
|
29
|
+
* Callback that checks if bootstrap has already been completed.
|
|
30
|
+
* Used by GET /auth/config to report `needsSetup` status.
|
|
31
|
+
* When not provided, falls back to checking if any users exist.
|
|
32
|
+
*/
|
|
33
|
+
isBootstrapCompleted?: () => Promise<boolean>;
|
|
34
|
+
/** Enable magic link (passwordless email) login. Requires email service. */
|
|
35
|
+
enableMagicLink?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Opt-in httpOnly cookie mode for refresh tokens.
|
|
38
|
+
*
|
|
39
|
+
* When set, the refresh token is delivered as an `httpOnly`, `Secure`,
|
|
40
|
+
* `SameSite` cookie instead of in the JSON response body. This
|
|
41
|
+
* prevents XSS from stealing the long-lived refresh token.
|
|
42
|
+
*
|
|
43
|
+
* The access token remains in the JSON body so the client can use it
|
|
44
|
+
* in `Authorization: Bearer` headers for API calls.
|
|
45
|
+
*
|
|
46
|
+
* **Requires** `credentials: "include"` on client-side fetch calls to
|
|
47
|
+
* auth endpoints, and CORS must allow credentials (no `origin: "*"`).
|
|
48
|
+
*/
|
|
49
|
+
cookieAuth?: CookieAuthConfig;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Configuration for httpOnly refresh-token cookies.
|
|
53
|
+
*/
|
|
54
|
+
export interface CookieAuthConfig {
|
|
55
|
+
/** Cookie name (default: "__rb_refresh"). */
|
|
56
|
+
cookieName?: string;
|
|
57
|
+
/** Cookie domain. Omit to use the current domain. */
|
|
58
|
+
domain?: string;
|
|
59
|
+
/** Cookie path (default: "/"). */
|
|
60
|
+
path?: string;
|
|
61
|
+
/** SameSite attribute (default: "Lax"). */
|
|
62
|
+
sameSite?: "Strict" | "Lax" | "None";
|
|
63
|
+
/** Force the Secure flag. Defaults to `true` when SameSite is "None", otherwise auto-detected from the request protocol. */
|
|
64
|
+
secure?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export declare function createAuthRoutes(config: AuthModuleConfig): Hono<HonoEnv>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { HonoEnv } from "../api/types";
|
|
4
|
+
import type { AuthModuleConfig } from "./routes";
|
|
5
|
+
import type { AuthResponsePayload, TransformAuthResponseContext } from "@rebasepro/types";
|
|
6
|
+
import type { resolveAuthHooks } from "./auth-hooks";
|
|
7
|
+
interface SessionRoutesConfig {
|
|
8
|
+
router: Hono<HonoEnv>;
|
|
9
|
+
config: AuthModuleConfig;
|
|
10
|
+
ops: ReturnType<typeof resolveAuthHooks>;
|
|
11
|
+
parseBody: <T>(schema: z.ZodSchema<T>, body: unknown) => T;
|
|
12
|
+
buildAuthResponse: (user: {
|
|
13
|
+
id: string;
|
|
14
|
+
email: string;
|
|
15
|
+
displayName?: string | null;
|
|
16
|
+
photoUrl?: string | null;
|
|
17
|
+
emailVerified?: boolean;
|
|
18
|
+
isAnonymous?: boolean;
|
|
19
|
+
metadata?: Record<string, unknown> | null;
|
|
20
|
+
}, roleIds: string[], accessToken: string, refreshToken: string, providerId: string) => unknown;
|
|
21
|
+
createSessionAndTokens: (userId: string, userAgent: string, ipAddress: string) => Promise<{
|
|
22
|
+
roleIds: string[];
|
|
23
|
+
accessToken: string;
|
|
24
|
+
refreshToken: string;
|
|
25
|
+
}>;
|
|
26
|
+
applyTransformHook: (response: AuthResponsePayload, method: TransformAuthResponseContext["method"], request: Request, userId: string) => Promise<AuthResponsePayload>;
|
|
27
|
+
}
|
|
28
|
+
export declare function mountSessionRoutes(opts: SessionRoutesConfig): void;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a Slack OAuth Provider integration (OAuth 2.0 / "Sign in with Slack").
|
|
4
|
+
* Uses the OpenID Connect flow with the "openid,email,profile" scopes.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSlackProvider(config: {
|
|
7
|
+
clientId: string;
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
}): OAuthProvider<{
|
|
10
|
+
code: string;
|
|
11
|
+
redirectUri: string;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a Spotify OAuth Provider integration.
|
|
4
|
+
* Uses the authorization code flow with the "user-read-email" scope.
|
|
5
|
+
*/
|
|
6
|
+
export declare function createSpotifyProvider(config: {
|
|
7
|
+
clientId: string;
|
|
8
|
+
clientSecret: string;
|
|
9
|
+
}): OAuthProvider<{
|
|
10
|
+
code: string;
|
|
11
|
+
redirectUri: string;
|
|
12
|
+
}>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { OAuthProvider } from "./interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a Twitter/X OAuth 2.0 Provider integration.
|
|
4
|
+
*
|
|
5
|
+
* Uses OAuth 2.0 with PKCE (authorization code flow). The frontend must include
|
|
6
|
+
* the PKCE `code_verifier` when sending the authorization code.
|
|
7
|
+
*
|
|
8
|
+
* Twitter API v2 requires the "tweet.read" and "users.read" scopes at minimum,
|
|
9
|
+
* plus "offline.access" if refresh tokens are needed on Twitter's side.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createTwitterProvider(config: {
|
|
12
|
+
clientId: string;
|
|
13
|
+
clientSecret: string;
|
|
14
|
+
}): OAuthProvider<{
|
|
15
|
+
code: string;
|
|
16
|
+
redirectUri: string;
|
|
17
|
+
codeVerifier: string;
|
|
18
|
+
}>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BackupInfo } from "@rebasepro/types";
|
|
2
|
+
import type { StorageController } from "../storage";
|
|
3
|
+
export type BackupDestination = {
|
|
4
|
+
kind: "local";
|
|
5
|
+
path: string;
|
|
6
|
+
} | {
|
|
7
|
+
kind: "s3";
|
|
8
|
+
bucket: string;
|
|
9
|
+
prefix: string;
|
|
10
|
+
} | {
|
|
11
|
+
kind: "gcs";
|
|
12
|
+
bucket: string;
|
|
13
|
+
prefix: string;
|
|
14
|
+
};
|
|
15
|
+
/** Parse a destination string (`s3://…`, `gs://…`, or a local path). */
|
|
16
|
+
export declare function parseBackupDestination(out: string): BackupDestination;
|
|
17
|
+
/**
|
|
18
|
+
* Recover the UTC creation time encoded in a `rebase-<db>-<ts>.dump` name.
|
|
19
|
+
* Returns `null` for names that don't match, so foreign objects are ignored.
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseBackupTimestamp(fileName: string): Date | null;
|
|
22
|
+
/**
|
|
23
|
+
* List the backups at a destination as {@link BackupInfo}, newest first.
|
|
24
|
+
* Only `.dump` files are considered.
|
|
25
|
+
*/
|
|
26
|
+
export declare function listBackupObjects(dest: BackupDestination, storage?: StorageController): Promise<BackupInfo[]>;
|
|
27
|
+
/** Read a single backup's bytes. Guards against path traversal for local. */
|
|
28
|
+
export declare function readBackupBytes(dest: BackupDestination, key: string, storage?: StorageController): Promise<{
|
|
29
|
+
bytes: Uint8Array<ArrayBuffer>;
|
|
30
|
+
name: string;
|
|
31
|
+
} | null>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { HonoEnv } from "../api/types";
|
|
3
|
+
import type { StorageController } from "../storage";
|
|
4
|
+
import { BackupDestination } from "./backup-common";
|
|
5
|
+
export interface BackupRoutesConfig {
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the current backup destination, or `null` when backups are not
|
|
8
|
+
* configured (`BACKUP_DESTINATION` unset). Read lazily so a restart isn't
|
|
9
|
+
* required to pick up config.
|
|
10
|
+
*/
|
|
11
|
+
getDestination: () => BackupDestination | null;
|
|
12
|
+
/** Storage controller for object-storage destinations. */
|
|
13
|
+
storage?: StorageController;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Admin REST routes for the Backups panel.
|
|
17
|
+
*
|
|
18
|
+
* Routes (mounted under `/admin/backups`, admin-guarded by the caller):
|
|
19
|
+
* GET / → list available backups
|
|
20
|
+
* GET /download → download a backup's bytes (?key=…)
|
|
21
|
+
*/
|
|
22
|
+
export declare function createBackupRoutes(config: BackupRoutesConfig): Hono<HonoEnv>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage-generic backup helpers and admin routes for the Backups panel.
|
|
3
|
+
* The `pg_dump`/`pg_restore` machinery lives in `@rebasepro/server-postgres`.
|
|
4
|
+
*/
|
|
5
|
+
export * from "./backup-common";
|
|
6
|
+
export { createBackupRoutes } from "./backup-routes";
|
|
7
|
+
export type { BackupRoutesConfig } from "./backup-routes";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CollectionRegistry } from "@rebasepro/common";
|
|
2
|
+
import { CollectionRegistryInterface } from "../db/interfaces";
|
|
3
|
+
/**
|
|
4
|
+
* Backend-agnostic collection registry.
|
|
5
|
+
* Satisfies CollectionRegistryInterface through inheritance from CollectionRegistry.
|
|
6
|
+
*/
|
|
7
|
+
export declare class BackendCollectionRegistry extends CollectionRegistry implements CollectionRegistryInterface {
|
|
8
|
+
/**
|
|
9
|
+
* Get the available relation keys for a given collection path.
|
|
10
|
+
* Maps from the collection's relation property names to the relation names.
|
|
11
|
+
*/
|
|
12
|
+
getRelationKeysForCollection(collectionPath: string): string[];
|
|
13
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CollectionConfig, SecurityRule } from "@rebasepro/types";
|
|
2
|
+
/**
|
|
3
|
+
* The one definition of "the collections".
|
|
4
|
+
*
|
|
5
|
+
* Four copies of this scan used to exist — the runtime, the drizzle-schema
|
|
6
|
+
* generator, the policy generator and the doctor — each deciding for itself
|
|
7
|
+
* which files counted. They agreed only by discipline, and any drift between
|
|
8
|
+
* them would silently serve one set of collections while pushing policies for
|
|
9
|
+
* another. Everything that needs to know what the collections are calls this.
|
|
10
|
+
*/
|
|
11
|
+
/** Read from a directory's `index` module, or from a single-file source. */
|
|
12
|
+
export interface CollectionDefaults {
|
|
13
|
+
/**
|
|
14
|
+
* Applied to every collection that declares no `securityRules` of its own.
|
|
15
|
+
*
|
|
16
|
+
* This lives with the collections rather than in the server config because
|
|
17
|
+
* `db push` generates the actual Postgres policies from these files and
|
|
18
|
+
* never sees the running server — a default declared on the server could
|
|
19
|
+
* never reach the database, and would look like an authorization setting
|
|
20
|
+
* while enforcing nothing.
|
|
21
|
+
*/
|
|
22
|
+
defaultSecurityRules?: SecurityRule[];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Apply directory-level defaults. A collection declaring its own rules is left
|
|
26
|
+
* alone; one declaring none inherits these. Declaring neither leaves
|
|
27
|
+
* `securityRules` unset, which the policy generator treats as locked-by-default.
|
|
28
|
+
*/
|
|
29
|
+
export declare function applyCollectionDefaults(collections: CollectionConfig[], defaults: CollectionDefaults): CollectionConfig[];
|
|
30
|
+
/**
|
|
31
|
+
* Load collections from a directory of collection files, or from a single
|
|
32
|
+
* module exporting `backendCollections` / `collections`.
|
|
33
|
+
*
|
|
34
|
+
* Throws if any file fails to import. A collection that cannot be loaded is a
|
|
35
|
+
* configuration error, and continuing produces the worst outcome available: an
|
|
36
|
+
* API missing a route, or a policy file missing a table, with a successful exit
|
|
37
|
+
* code. Both read as "no data" rather than as a failure.
|
|
38
|
+
*/
|
|
39
|
+
export declare function loadCollectionsFromDirectory(source: string): Promise<CollectionConfig[]>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CronJobDefinition } from "@rebasepro/types";
|
|
2
|
+
import { type ModuleImporter } from "../utils/dynamic-import.js";
|
|
3
|
+
export interface LoadedCronJob {
|
|
4
|
+
/** Job ID derived from filename (e.g. "cleanup-sessions"). */
|
|
5
|
+
id: string;
|
|
6
|
+
/** The full definition. */
|
|
7
|
+
definition: CronJobDefinition;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Auto-discover cron job files from a directory.
|
|
11
|
+
*
|
|
12
|
+
* Each file should default-export a `CronJobDefinition`.
|
|
13
|
+
* The filename (without extension) becomes the job ID:
|
|
14
|
+
* `crons/cleanup-sessions.ts` → id = "cleanup-sessions"
|
|
15
|
+
*
|
|
16
|
+
* Follows the same discovery pattern as `loadFunctionsFromDirectory`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function loadCronJobsFromDirectory(directory: string, importModule?: ModuleImporter): Promise<LoadedCronJob[]>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { HonoEnv } from "../api/types";
|
|
3
|
+
import type { CronScheduler } from "./cron-scheduler";
|
|
4
|
+
/**
|
|
5
|
+
* Create admin REST routes for managing cron jobs.
|
|
6
|
+
*
|
|
7
|
+
* Routes:
|
|
8
|
+
* GET / → list all cron jobs
|
|
9
|
+
* GET /:id → get a single job's status
|
|
10
|
+
* POST /:id/trigger → manually trigger a job
|
|
11
|
+
* GET /:id/logs → get execution logs for a job
|
|
12
|
+
* PUT /:id → update job (enable/disable)
|
|
13
|
+
*/
|
|
14
|
+
export declare function createCronRoutes(scheduler: CronScheduler): Hono<HonoEnv>;
|