@rebasepro/server 0.16.0 → 0.16.1-canary.g2d1aec8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/contract-routes.d.ts +1 -1
- package/dist/api/errors.d.ts +1 -1
- package/dist/api/index.d.ts +3 -3
- package/dist/api/live-schema-routes.d.ts +111 -0
- package/dist/api/logs-routes.d.ts +1 -1
- package/dist/api/mount.d.ts +41 -0
- package/dist/api/rest/api-generator.d.ts +2 -2
- package/dist/api/rest/index.d.ts +1 -1
- package/dist/api/rest/query-parser.d.ts +1 -1
- package/dist/api/schema-editor-routes.d.ts +1 -1
- package/dist/api/types.d.ts +3 -4
- package/dist/{schema-editor-routes-CV9k0w3G.js → ast-schema-editor-BpFYpT38.js} +2 -39
- package/dist/ast-schema-editor-BpFYpT38.js.map +1 -0
- package/dist/auth/adapter-middleware.d.ts +2 -2
- package/dist/auth/admin-roles-route.d.ts +2 -2
- package/dist/auth/admin-user-ops.d.ts +3 -3
- package/dist/auth/admin-users-route.d.ts +4 -4
- package/dist/auth/api-keys/api-key-middleware.d.ts +2 -2
- package/dist/auth/api-keys/api-key-permission-guard.d.ts +1 -1
- package/dist/auth/api-keys/api-key-routes.d.ts +2 -2
- package/dist/auth/api-keys/api-key-store.d.ts +1 -1
- package/dist/auth/api-keys/index.d.ts +9 -9
- package/dist/auth/apple-oauth.d.ts +2 -2
- package/dist/auth/auth-hooks.d.ts +3 -3
- package/dist/auth/bitbucket-oauth.d.ts +2 -2
- package/dist/auth/builtin-auth-adapter.d.ts +7 -4
- package/dist/auth/captcha.d.ts +86 -0
- package/dist/auth/cookie-utils.d.ts +2 -2
- package/dist/auth/discord-oauth.d.ts +2 -2
- package/dist/auth/facebook-oauth.d.ts +2 -2
- package/dist/auth/github-oauth.d.ts +2 -2
- package/dist/auth/gitlab-oauth.d.ts +2 -2
- package/dist/auth/google-oauth.d.ts +1 -1
- package/dist/auth/index.d.ts +56 -54
- package/dist/auth/jwks-routes.d.ts +1 -1
- package/dist/auth/jwt.d.ts +1 -1
- package/dist/auth/linkedin-oauth.d.ts +2 -2
- package/dist/auth/magic-link-routes.d.ts +10 -3
- package/dist/auth/mfa-gate.d.ts +1 -1
- package/dist/auth/mfa-routes.d.ts +3 -3
- package/dist/auth/microsoft-oauth.d.ts +2 -2
- package/dist/auth/middleware.d.ts +5 -5
- package/dist/auth/rate-limiter.d.ts +2 -2
- package/dist/auth/require-auth.d.ts +1 -1
- package/dist/auth/reset-password-admin.d.ts +4 -4
- package/dist/auth/routes.d.ts +13 -4
- package/dist/auth/session-routes.d.ts +3 -3
- package/dist/auth/slack-oauth.d.ts +2 -2
- package/dist/auth/spotify-oauth.d.ts +2 -2
- package/dist/auth/token-revocation.d.ts +2 -2
- package/dist/auth/twitter-oauth.d.ts +2 -2
- package/dist/{auth-5Et5mnUA.js → auth-C74dqR2B.js} +250 -15
- package/dist/auth-C74dqR2B.js.map +1 -0
- package/dist/backup/backup-common.d.ts +1 -1
- package/dist/backup/backup-routes.d.ts +3 -3
- package/dist/backup/index.d.ts +3 -3
- package/dist/{backup-C6ljYVTp.js → backup-BJ86ah4T.js} +2 -2
- package/dist/{backup-C6ljYVTp.js.map → backup-BJ86ah4T.js.map} +1 -1
- package/dist/boot/boot.d.ts +5 -5
- package/dist/boot/bundle.d.ts +1 -1
- package/dist/boot/driver.d.ts +1 -1
- package/dist/boot/env.d.ts +13 -1
- package/dist/boot/options.d.ts +30 -6
- package/dist/boot/role.d.ts +3 -2
- package/dist/boot/sources.d.ts +1 -1
- package/dist/collections/BackendCollectionRegistry.d.ts +1 -1
- package/dist/collections/loader.d.ts +1 -1
- package/dist/{contract-routes-DZ-LBpSL.js → contract-routes-BEq7euZg.js} +2 -2
- package/dist/contract-routes-BEq7euZg.js.map +1 -0
- package/dist/cron/cron-routes.d.ts +2 -2
- package/dist/cron/cron-scheduler.d.ts +2 -2
- package/dist/cron/index.d.ts +8 -8
- package/dist/{cron-loader-YhhQeVBM.js → cron-loader-BMvtW6-J.js} +2 -2
- package/dist/{cron-loader-YhhQeVBM.js.map → cron-loader-BMvtW6-J.js.map} +1 -1
- package/dist/{cron-routes-maM_RlUu.js → cron-routes-BvYk-Kmi.js} +2 -2
- package/dist/{cron-routes-maM_RlUu.js.map → cron-routes-BvYk-Kmi.js.map} +1 -1
- package/dist/{cron-scheduler-DIpYBmZP.js → cron-scheduler-Buf-uVam.js} +2 -2
- package/dist/{cron-scheduler-DIpYBmZP.js.map → cron-scheduler-Buf-uVam.js.map} +1 -1
- package/dist/{cron-store-DfH_4Cd9.js → cron-store-CyF-oInV.js} +3 -3
- package/dist/{cron-store-DfH_4Cd9.js.map → cron-store-CyF-oInV.js.map} +1 -1
- package/dist/{ddl-bootstrap-Cywoj8Ta.js → ddl-bootstrap-DgSnERYN.js} +17 -3
- package/dist/ddl-bootstrap-DgSnERYN.js.map +1 -0
- package/dist/dev-secrets.d.ts +52 -0
- package/dist/email/dev-sink.d.ts +67 -0
- package/dist/email/index.d.ts +9 -7
- package/dist/email/link-base.d.ts +1 -1
- package/dist/email/smtp-email-service.d.ts +1 -1
- package/dist/env.d.ts +1 -1
- package/dist/{errors-EBYiaJ2E.js → errors-D_LwNKRM.js} +5 -5
- package/dist/errors-D_LwNKRM.js.map +1 -0
- package/dist/{function-loader-DDS1v7YX.js → function-loader-BrLmC_-y.js} +3 -3
- package/dist/{function-loader-DDS1v7YX.js.map → function-loader-BrLmC_-y.js.map} +1 -1
- package/dist/functions/context.d.ts +141 -0
- package/dist/functions/define-function.d.ts +1 -1
- package/dist/functions/function-routes.d.ts +2 -2
- package/dist/functions/guards.d.ts +76 -0
- package/dist/functions/index.d.ts +96 -5
- package/dist/functions/index.js +919 -0
- package/dist/functions/index.js.map +1 -0
- package/dist/functions/internal.d.ts +26 -0
- package/dist/functions/proxy.d.ts +1 -1
- package/dist/functions/request-timeout.d.ts +9 -1
- package/dist/functions/runtime-env.d.ts +92 -0
- package/dist/functions/wait-until.d.ts +74 -0
- package/dist/history/history-routes.d.ts +2 -2
- package/dist/history/index.d.ts +1 -1
- package/dist/index.d.ts +63 -54
- package/dist/index.es.js +2183 -164
- package/dist/index.es.js.map +1 -1
- package/dist/init/docs.d.ts +1 -1
- package/dist/init/middlewares.d.ts +1 -1
- package/dist/init/shutdown.d.ts +4 -0
- package/dist/init/storage.d.ts +1 -1
- package/dist/init/surfaces.d.ts +10 -0
- package/dist/init.d.ts +104 -18
- package/dist/jobs/index.d.ts +5 -5
- package/dist/{jobs-CyOKXXlu.js → jobs-Bn6nhY8J.js} +3 -3
- package/dist/{jobs-CyOKXXlu.js.map → jobs-Bn6nhY8J.js.map} +1 -1
- package/dist/{jwt-DxH9fLPt.js → jwt-BbJi0TR0.js} +2 -2
- package/dist/{jwt-DxH9fLPt.js.map → jwt-BbJi0TR0.js.map} +1 -1
- package/dist/{logger-DfvF_8r-.js → logger-TdvXIGqR.js} +101 -8
- package/dist/logger-TdvXIGqR.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -1
- package/dist/{proxy-Bj5DVllb.js → proxy-QJKSS-CV.js} +5 -3
- package/dist/{proxy-Bj5DVllb.js.map → proxy-QJKSS-CV.js.map} +1 -1
- package/dist/{request-timeout-BuFoEKwT.js → request-timeout-OofPCHQT.js} +17 -3
- package/dist/request-timeout-OofPCHQT.js.map +1 -0
- package/dist/rls-audit/index.d.ts +111 -0
- package/dist/schema-edit/apply-schema-change.d.ts +141 -0
- package/dist/schema-edit/github-repository.d.ts +67 -0
- package/dist/schema-edit/local-git-repository.d.ts +28 -0
- package/dist/schema-edit/project-root.d.ts +29 -0
- package/dist/schema-edit/remote-source.d.ts +25 -0
- package/dist/schema-edit/schema-edit-permissions.d.ts +129 -0
- package/dist/schema-editor-routes-yh2cQcdJ.js +44 -0
- package/dist/schema-editor-routes-yh2cQcdJ.js.map +1 -0
- package/dist/services/webhook-service.d.ts +1 -1
- package/dist/singleton.d.ts +7 -0
- package/dist/storage/GCSStorageController.d.ts +1 -1
- package/dist/storage/LocalStorageController.d.ts +1 -1
- package/dist/storage/S3StorageController.d.ts +1 -1
- package/dist/storage/cache-headers.d.ts +87 -0
- package/dist/storage/index.d.ts +11 -11
- package/dist/storage/policies.d.ts +88 -0
- package/dist/storage/range.d.ts +63 -0
- package/dist/storage/routes.d.ts +3 -3
- package/dist/storage/storage-registry.d.ts +1 -1
- package/dist/storage/tus-handler.d.ts +2 -2
- package/dist/utils/host.d.ts +58 -0
- package/dist/utils/logger.d.ts +0 -15
- package/dist/utils/request-id.d.ts +1 -1
- package/functions/package.json +24 -0
- package/package.json +13 -7
- package/dist/auth-5Et5mnUA.js.map +0 -1
- package/dist/contract-routes-DZ-LBpSL.js.map +0 -1
- package/dist/ddl-bootstrap-Cywoj8Ta.js.map +0 -1
- package/dist/errors-EBYiaJ2E.js.map +0 -1
- package/dist/logger-DfvF_8r-.js.map +0 -1
- package/dist/request-timeout-BuFoEKwT.js.map +0 -1
- package/dist/schema-editor-routes-CV9k0w3G.js.map +0 -1
|
@@ -4,15 +4,16 @@ __createRequire(import.meta.url);
|
|
|
4
4
|
import { i as __toESM, n as __exportAll } from "./rolldown-runtime-DSJWtz9O.js";
|
|
5
5
|
import { C as ListLimitError, D as isAnonymousUid, E as ANONYMOUS_USER_ID, T as resolveClientListLimit, a as deserializeLogicalCondition, i as deserializeFilter, r as UnknownFilterOperatorError } from "./src-BPfYOeN4.js";
|
|
6
6
|
import "./src-CrCxd8km.js";
|
|
7
|
-
import { n as createDdlBootstrapper, o as revokeInternalTableSql, s as isSQLAdmin } from "./ddl-bootstrap-
|
|
8
|
-
import { S as canonicalStorageId, T as require_jsonwebtoken, _ as verifyMfaPendingToken, a as generateMfaPendingToken, c as getJwks, d as hasAsymmetricSigningKey, f as hashRefreshToken, g as verifyDownloadToken, h as verifyAccessToken, i as generateDownloadToken, l as getRefreshTokenExpiry, n as configureJwt, o as generateRefreshToken, p as isJwtConfigured, r as generateAccessToken, s as getAccessTokenExpiry, t as MAX_COOKIE_AGE_MS, u as getRefreshTokenTtlMs, w as tryCanonicalStorageKey } from "./jwt-
|
|
9
|
-
import { t as logger } from "./logger-
|
|
10
|
-
import { n as errorHandler, t as ApiError } from "./errors-
|
|
7
|
+
import { n as createDdlBootstrapper, o as revokeInternalTableSql, s as isSQLAdmin } from "./ddl-bootstrap-DgSnERYN.js";
|
|
8
|
+
import { S as canonicalStorageId, T as require_jsonwebtoken, _ as verifyMfaPendingToken, a as generateMfaPendingToken, c as getJwks, d as hasAsymmetricSigningKey, f as hashRefreshToken, g as verifyDownloadToken, h as verifyAccessToken, i as generateDownloadToken, l as getRefreshTokenExpiry, n as configureJwt, o as generateRefreshToken, p as isJwtConfigured, r as generateAccessToken, s as getAccessTokenExpiry, t as MAX_COOKIE_AGE_MS, u as getRefreshTokenTtlMs, w as tryCanonicalStorageKey } from "./jwt-BbJi0TR0.js";
|
|
9
|
+
import { t as logger } from "./logger-TdvXIGqR.js";
|
|
10
|
+
import { n as errorHandler, t as ApiError } from "./errors-D_LwNKRM.js";
|
|
11
11
|
import { createHash, randomBytes, randomInt } from "node:crypto";
|
|
12
12
|
import { Hono } from "hono";
|
|
13
13
|
import { promisify } from "util";
|
|
14
14
|
import { createCipheriv, createDecipheriv, createHash as createHash$1, createHmac, createPublicKey, randomBytes as randomBytes$1, randomUUID as randomUUID$1, scrypt, timingSafeEqual } from "crypto";
|
|
15
15
|
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
16
|
+
import { createMiddleware } from "hono/factory";
|
|
16
17
|
//#region ../types/src/controllers/storage.ts
|
|
17
18
|
/**
|
|
18
19
|
* Path prefix that marks an object as **public**. Files stored under this
|
|
@@ -2458,6 +2459,64 @@ function createEmailService(config) {
|
|
|
2458
2459
|
return new SMTPEmailService(config);
|
|
2459
2460
|
}
|
|
2460
2461
|
//#endregion
|
|
2462
|
+
//#region src/email/dev-sink.ts
|
|
2463
|
+
/** How many messages the ring buffer keeps before dropping the oldest. */
|
|
2464
|
+
var DEFAULT_CAPACITY = 50;
|
|
2465
|
+
/**
|
|
2466
|
+
* Absolute http(s) URLs in a message body.
|
|
2467
|
+
*
|
|
2468
|
+
* Deliberately simple: it reads `href="…"` first, because that is where a real
|
|
2469
|
+
* link lives, and falls back to bare URLs in the text part. Trailing markup and
|
|
2470
|
+
* punctuation are trimmed so the result can be pasted straight into a browser.
|
|
2471
|
+
*/
|
|
2472
|
+
function extractLinks(html, text) {
|
|
2473
|
+
const found = [];
|
|
2474
|
+
const push = (url) => {
|
|
2475
|
+
const cleaned = url.replace(/[)\]}>.,;'"]+$/, "");
|
|
2476
|
+
if (cleaned && !found.includes(cleaned)) found.push(cleaned);
|
|
2477
|
+
};
|
|
2478
|
+
if (html) for (const match of html.matchAll(/href\s*=\s*["'](https?:\/\/[^"']+)["']/gi)) push(match[1]);
|
|
2479
|
+
if (text) for (const match of text.matchAll(/https?:\/\/[^\s<>"']+/gi)) push(match[0]);
|
|
2480
|
+
return found;
|
|
2481
|
+
}
|
|
2482
|
+
/** Whatever `to` was given as, rendered for a log line. */
|
|
2483
|
+
var formatRecipient = (to) => Array.isArray(to) ? to.join(", ") : to;
|
|
2484
|
+
/**
|
|
2485
|
+
* Create a sink. Each call is independent, which is what lets a test hold one
|
|
2486
|
+
* without touching whatever the process is using.
|
|
2487
|
+
*/
|
|
2488
|
+
function createDevEmailSink(options = {}) {
|
|
2489
|
+
const capacity = options.capacity ?? DEFAULT_CAPACITY;
|
|
2490
|
+
const messages = [];
|
|
2491
|
+
let nextId = 1;
|
|
2492
|
+
let announced = false;
|
|
2493
|
+
const sendEmail = async (mail) => {
|
|
2494
|
+
const captured = {
|
|
2495
|
+
id: nextId++,
|
|
2496
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2497
|
+
to: formatRecipient(mail.to),
|
|
2498
|
+
subject: mail.subject,
|
|
2499
|
+
html: mail.html,
|
|
2500
|
+
text: mail.text,
|
|
2501
|
+
links: extractLinks(mail.html, mail.text)
|
|
2502
|
+
};
|
|
2503
|
+
messages.unshift(captured);
|
|
2504
|
+
if (messages.length > capacity) messages.length = capacity;
|
|
2505
|
+
if (!announced) {
|
|
2506
|
+
announced = true;
|
|
2507
|
+
logger.warn("No SMTP is configured, so auth email is being captured here instead of sent. Follow the link below to complete the flow. Set SMTP_HOST to deliver mail for real; this sink is unavailable when NODE_ENV=production.");
|
|
2508
|
+
}
|
|
2509
|
+
logger.info(`[email] ${captured.subject} → ${captured.to}` + (captured.links.length ? `\n ${captured.links.join("\n ")}` : "\n (no links in this message)"));
|
|
2510
|
+
};
|
|
2511
|
+
return {
|
|
2512
|
+
sendEmail,
|
|
2513
|
+
list: () => [...messages],
|
|
2514
|
+
clear: () => {
|
|
2515
|
+
messages.length = 0;
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
}
|
|
2519
|
+
//#endregion
|
|
2461
2520
|
//#region src/auth/rate-limit-store.ts
|
|
2462
2521
|
/**
|
|
2463
2522
|
* The default store: a sliding window in this process's memory.
|
|
@@ -2763,6 +2822,174 @@ function createDataRateLimiter(config = {}) {
|
|
|
2763
2822
|
});
|
|
2764
2823
|
}
|
|
2765
2824
|
//#endregion
|
|
2825
|
+
//#region src/auth/captcha.ts
|
|
2826
|
+
/**
|
|
2827
|
+
* Bot protection on the auth endpoints that cost something to hit.
|
|
2828
|
+
*
|
|
2829
|
+
* Rate limiting was the whole defence, and it bounds a single caller rather
|
|
2830
|
+
* than a botnet: a thousand addresses each sending one request per minute never
|
|
2831
|
+
* touch a per-IP window, and `/auth/register` and `/auth/forgot-password` both
|
|
2832
|
+
* send mail. So the bill for an unprotected signup form is paid in reputation on
|
|
2833
|
+
* a sending domain, not in CPU.
|
|
2834
|
+
*
|
|
2835
|
+
* This adds a challenge the caller has to have solved, verified server-side
|
|
2836
|
+
* against the provider before the route does any work.
|
|
2837
|
+
*
|
|
2838
|
+
* ## Fail closed, and why that is the safe direction here
|
|
2839
|
+
*
|
|
2840
|
+
* If the provider cannot be reached, verification fails and the request is
|
|
2841
|
+
* refused. That is the opposite of the choice made for the RLS audit, which
|
|
2842
|
+
* logs and continues, and the difference is what failure means: an audit that
|
|
2843
|
+
* does not run leaves you where you were, while a challenge that is not checked
|
|
2844
|
+
* leaves the door open for exactly as long as the outage lasts. An attacker who
|
|
2845
|
+
* can cause the outage would otherwise be able to turn the protection off.
|
|
2846
|
+
*
|
|
2847
|
+
* The cost is that a provider outage blocks sign-ups. That is visible, loud, and
|
|
2848
|
+
* recoverable by unsetting one config key — which is a better failure than a
|
|
2849
|
+
* silent one nobody notices until the mail domain is blocklisted.
|
|
2850
|
+
*
|
|
2851
|
+
* ## Why the verifier is injected
|
|
2852
|
+
*
|
|
2853
|
+
* Same reason as the RLS scanner: so the whole thing is testable without a
|
|
2854
|
+
* network, and so no provider SDK enters this package's dependency graph. The
|
|
2855
|
+
* built-in verifier is `fetch` and a form post, which is the entire protocol for
|
|
2856
|
+
* both providers this supports.
|
|
2857
|
+
*/
|
|
2858
|
+
var VERIFY_ENDPOINT = {
|
|
2859
|
+
turnstile: "https://challenges.cloudflare.com/turnstile/v0/siteverify",
|
|
2860
|
+
hcaptcha: "https://api.hcaptcha.com/siteverify"
|
|
2861
|
+
};
|
|
2862
|
+
var DEFAULT_CAPTCHA_ROUTES = [
|
|
2863
|
+
"register",
|
|
2864
|
+
"forgotPassword",
|
|
2865
|
+
"magicLink"
|
|
2866
|
+
];
|
|
2867
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
2868
|
+
var DEFAULT_TOKEN_FIELD = "captchaToken";
|
|
2869
|
+
/** Header names the two widgets post by convention. */
|
|
2870
|
+
var TOKEN_HEADERS = ["cf-turnstile-response", "h-captcha-response"];
|
|
2871
|
+
/**
|
|
2872
|
+
* The built-in verifier: a form post, which is the whole protocol.
|
|
2873
|
+
*
|
|
2874
|
+
* A non-200, a timeout or a malformed body are all "not verified" rather than
|
|
2875
|
+
* exceptions — the caller cannot distinguish them and should not be told which
|
|
2876
|
+
* one happened.
|
|
2877
|
+
*/
|
|
2878
|
+
function createHttpCaptchaVerifier(options) {
|
|
2879
|
+
const endpoint = VERIFY_ENDPOINT[options.provider];
|
|
2880
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
2881
|
+
const doFetch = options.fetchImpl ?? fetch;
|
|
2882
|
+
return async ({ token, remoteIp }) => {
|
|
2883
|
+
const body = new URLSearchParams({
|
|
2884
|
+
secret: options.secret,
|
|
2885
|
+
response: token
|
|
2886
|
+
});
|
|
2887
|
+
if (remoteIp) body.set("remoteip", remoteIp);
|
|
2888
|
+
const controller = new AbortController();
|
|
2889
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
2890
|
+
try {
|
|
2891
|
+
const response = await doFetch(endpoint, {
|
|
2892
|
+
method: "POST",
|
|
2893
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2894
|
+
body,
|
|
2895
|
+
signal: controller.signal
|
|
2896
|
+
});
|
|
2897
|
+
if (!response.ok) return {
|
|
2898
|
+
success: false,
|
|
2899
|
+
errorCodes: [`http-${response.status}`]
|
|
2900
|
+
};
|
|
2901
|
+
const parsed = await response.json();
|
|
2902
|
+
return {
|
|
2903
|
+
success: parsed?.success === true,
|
|
2904
|
+
errorCodes: parsed?.["error-codes"]
|
|
2905
|
+
};
|
|
2906
|
+
} catch (err) {
|
|
2907
|
+
return {
|
|
2908
|
+
success: false,
|
|
2909
|
+
errorCodes: [err instanceof Error && err.name === "AbortError" ? "timeout" : "unreachable"]
|
|
2910
|
+
};
|
|
2911
|
+
} finally {
|
|
2912
|
+
clearTimeout(timer);
|
|
2913
|
+
}
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
/**
|
|
2917
|
+
* Resolve a config into a verifier, or explain why it cannot be used.
|
|
2918
|
+
*
|
|
2919
|
+
* Returns `undefined` when the feature is off. Throws when it is on but
|
|
2920
|
+
* unusable — a misconfigured challenge must not boot as an absent one, because
|
|
2921
|
+
* the whole point is that it is there.
|
|
2922
|
+
*/
|
|
2923
|
+
function resolveCaptchaVerifier(config) {
|
|
2924
|
+
if (!config?.enabled) return void 0;
|
|
2925
|
+
if (config.verify) return config.verify;
|
|
2926
|
+
if (!config.provider) throw new Error("Captcha is enabled but no `provider` is set. Use \"turnstile\" or \"hcaptcha\", or supply your own `verify` function.");
|
|
2927
|
+
if (!(config.provider in VERIFY_ENDPOINT)) throw new Error(`Captcha \`provider\` is "${config.provider}", which is not supported. Use "turnstile" or "hcaptcha", or supply your own \`verify\` function.`);
|
|
2928
|
+
if (!config.secret) throw new Error(`Captcha is enabled for ${config.provider} but no \`secret\` is set. The token has to be verified server-side; a widget on its own protects nothing.`);
|
|
2929
|
+
return createHttpCaptchaVerifier({
|
|
2930
|
+
provider: config.provider,
|
|
2931
|
+
secret: config.secret,
|
|
2932
|
+
timeoutMs: config.timeoutMs
|
|
2933
|
+
});
|
|
2934
|
+
}
|
|
2935
|
+
/** Read the challenge token out of a request, body field first, then headers. */
|
|
2936
|
+
async function extractCaptchaToken(c, field) {
|
|
2937
|
+
for (const header of TOKEN_HEADERS) {
|
|
2938
|
+
const value = c.req.header(header);
|
|
2939
|
+
if (value) return value;
|
|
2940
|
+
}
|
|
2941
|
+
try {
|
|
2942
|
+
const value = (await c.req.json())?.[field];
|
|
2943
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2944
|
+
} catch {
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
/**
|
|
2949
|
+
* Middleware refusing a request whose challenge is missing or unverified.
|
|
2950
|
+
*
|
|
2951
|
+
* The response says only that the challenge failed. Which of "absent",
|
|
2952
|
+
* "malformed", "already used" or "provider unreachable" it was is a log line,
|
|
2953
|
+
* because telling a script which one it hit is telling it how to get closer.
|
|
2954
|
+
*/
|
|
2955
|
+
function createCaptchaMiddleware(options) {
|
|
2956
|
+
const field = options.tokenField ?? DEFAULT_TOKEN_FIELD;
|
|
2957
|
+
return createMiddleware(async (c, next) => {
|
|
2958
|
+
const token = await extractCaptchaToken(c, field);
|
|
2959
|
+
if (!token) {
|
|
2960
|
+
logger.debug(`[captcha] ${options.route}: no token on the request`);
|
|
2961
|
+
throw ApiError.badRequest("A captcha challenge is required for this request.", "CAPTCHA_REQUIRED");
|
|
2962
|
+
}
|
|
2963
|
+
const result = await options.verify({
|
|
2964
|
+
token,
|
|
2965
|
+
remoteIp: c.req.header("cf-connecting-ip") ?? void 0
|
|
2966
|
+
});
|
|
2967
|
+
if (!result.success) {
|
|
2968
|
+
logger.warn(`[captcha] ${options.route}: verification failed` + (result.errorCodes?.length ? ` (${result.errorCodes.join(", ")})` : ""));
|
|
2969
|
+
throw ApiError.badRequest("The captcha challenge could not be verified.", "CAPTCHA_FAILED");
|
|
2970
|
+
}
|
|
2971
|
+
await next();
|
|
2972
|
+
});
|
|
2973
|
+
}
|
|
2974
|
+
/**
|
|
2975
|
+
* A middleware per protected route, or an empty map when the feature is off.
|
|
2976
|
+
*
|
|
2977
|
+
* Routes not named get nothing at all rather than a pass-through, so an unnamed
|
|
2978
|
+
* route costs exactly what it did before.
|
|
2979
|
+
*/
|
|
2980
|
+
function buildCaptchaMiddlewares(config) {
|
|
2981
|
+
const verify = resolveCaptchaVerifier(config);
|
|
2982
|
+
if (!verify) return {};
|
|
2983
|
+
const routes = config?.routes ?? DEFAULT_CAPTCHA_ROUTES;
|
|
2984
|
+
const middlewares = {};
|
|
2985
|
+
for (const route of routes) middlewares[route] = createCaptchaMiddleware({
|
|
2986
|
+
verify,
|
|
2987
|
+
tokenField: config?.tokenField,
|
|
2988
|
+
route
|
|
2989
|
+
});
|
|
2990
|
+
return middlewares;
|
|
2991
|
+
}
|
|
2992
|
+
//#endregion
|
|
2766
2993
|
//#region ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/core/core.js
|
|
2767
2994
|
var _a$1;
|
|
2768
2995
|
function $constructor(name, initializer, params) {
|
|
@@ -7475,7 +7702,7 @@ function mountSessionRoutes(opts) {
|
|
|
7475
7702
|
clearRefreshCookie(c, config.cookieAuth);
|
|
7476
7703
|
const accessToken = extractBearerToken(c.req.header("authorization"));
|
|
7477
7704
|
if (ops.afterLogout && accessToken !== void 0) {
|
|
7478
|
-
const { verifyAccessToken } = await import("./jwt-
|
|
7705
|
+
const { verifyAccessToken } = await import("./jwt-BbJi0TR0.js").then((n) => n.m);
|
|
7479
7706
|
const payload = verifyAccessToken(accessToken);
|
|
7480
7707
|
if (payload) ops.afterLogout(payload.uid).catch((err) => {
|
|
7481
7708
|
logger.error("[AuthHooks] afterLogout error", { error: err instanceof Error ? err.message : err });
|
|
@@ -7714,7 +7941,7 @@ function getMagicLinkExpiry() {
|
|
|
7714
7941
|
* Follows the same delegation pattern as `mountMfaRoutes()` and `mountSessionRoutes()`.
|
|
7715
7942
|
*/
|
|
7716
7943
|
function mountMagicLinkRoutes(deps) {
|
|
7717
|
-
const { router, config, ops, parseBody, buildAuthResponse, createSessionAndTokens, applyTransformHook } = deps;
|
|
7944
|
+
const { router, config, ops, parseBody, buildAuthResponse, createSessionAndTokens, applyTransformHook, captchaMiddleware } = deps;
|
|
7718
7945
|
const { authRepo, emailService, emailConfig } = config;
|
|
7719
7946
|
const magicLinkSchema = object({ email: string().email("Invalid email address").max(255) });
|
|
7720
7947
|
const verifyMagicLinkSchema = object({ token: string().min(1, "Token is required") });
|
|
@@ -7725,7 +7952,7 @@ function mountMagicLinkRoutes(deps) {
|
|
|
7725
7952
|
* POST /auth/magic-link
|
|
7726
7953
|
* Request a magic link email
|
|
7727
7954
|
*/
|
|
7728
|
-
router.post("/magic-link", strictAuthLimiter, async (c) => {
|
|
7955
|
+
router.post("/magic-link", strictAuthLimiter, ...captchaMiddleware ? [captchaMiddleware] : [], async (c) => {
|
|
7729
7956
|
const { email } = parseBody(magicLinkSchema, await c.req.json());
|
|
7730
7957
|
if (!isEmailConfigured()) throw ApiError.serviceUnavailable("Email service not configured. Magic link login is not available.", "EMAIL_NOT_CONFIGURED");
|
|
7731
7958
|
const user = await authRepo.getUserByEmail(email);
|
|
@@ -7877,6 +8104,7 @@ function getPasswordResetExpiry() {
|
|
|
7877
8104
|
}
|
|
7878
8105
|
function createAuthRoutes(config) {
|
|
7879
8106
|
if (config.defaultRole && isAdministrativeRole(config.defaultRole)) throw new Error(`CRITICAL SECURITY ERROR: defaultRole cannot be '${config.defaultRole}'. Administrative privilege escalation via registration is strictly forbidden (administrative roles: ${ADMINISTRATIVE_ROLES.join(", ")}). Use the POST /admin/bootstrap endpoint to promote the initial administrator.`);
|
|
8107
|
+
const captcha = buildCaptchaMiddlewares(config.captcha);
|
|
7880
8108
|
const router = new Hono();
|
|
7881
8109
|
router.onError(errorHandler);
|
|
7882
8110
|
const authRepo = config.authRepo;
|
|
@@ -8017,7 +8245,7 @@ function createAuthRoutes(config) {
|
|
|
8017
8245
|
* POST /auth/register
|
|
8018
8246
|
* Create a new account with email/password
|
|
8019
8247
|
*/
|
|
8020
|
-
router.post("/register", defaultAuthLimiter, async (c) => {
|
|
8248
|
+
router.post("/register", defaultAuthLimiter, ...captcha.register ? [captcha.register] : [], async (c) => {
|
|
8021
8249
|
const { email, password, displayName } = parseBody(registerSchema, await c.req.json());
|
|
8022
8250
|
if (config.disableSelfRegistration) throw ApiError.forbidden("Registration is disabled", "REGISTRATION_DISABLED");
|
|
8023
8251
|
let bootstrapRegistration = false;
|
|
@@ -8065,7 +8293,7 @@ function createAuthRoutes(config) {
|
|
|
8065
8293
|
* POST /auth/login
|
|
8066
8294
|
* Login with email/password
|
|
8067
8295
|
*/
|
|
8068
|
-
router.post("/login", defaultAuthLimiter, async (c) => {
|
|
8296
|
+
router.post("/login", defaultAuthLimiter, ...captcha.login ? [captcha.login] : [], async (c) => {
|
|
8069
8297
|
const { email, password } = parseBody(loginSchema, await c.req.json());
|
|
8070
8298
|
if (ops.beforeLogin) await ops.beforeLogin(email, "login");
|
|
8071
8299
|
let user;
|
|
@@ -8222,7 +8450,7 @@ function createAuthRoutes(config) {
|
|
|
8222
8450
|
* POST /auth/forgot-password
|
|
8223
8451
|
* Request password reset email
|
|
8224
8452
|
*/
|
|
8225
|
-
router.post("/forgot-password", strictAuthLimiter, async (c) => {
|
|
8453
|
+
router.post("/forgot-password", strictAuthLimiter, ...captcha.forgotPassword ? [captcha.forgotPassword] : [], async (c) => {
|
|
8226
8454
|
const { email } = parseBody(forgotPasswordSchema, await c.req.json());
|
|
8227
8455
|
if (!isEmailConfigured()) throw ApiError.serviceUnavailable("Email service not configured. Password reset is not available.", "EMAIL_NOT_CONFIGURED");
|
|
8228
8456
|
const user = await authRepo.getUserByEmail(email);
|
|
@@ -8470,7 +8698,8 @@ function createAuthRoutes(config) {
|
|
|
8470
8698
|
parseBody,
|
|
8471
8699
|
buildAuthResponse,
|
|
8472
8700
|
createSessionAndTokens,
|
|
8473
|
-
applyTransformHook
|
|
8701
|
+
applyTransformHook,
|
|
8702
|
+
captchaMiddleware: captcha.magicLink
|
|
8474
8703
|
});
|
|
8475
8704
|
return router;
|
|
8476
8705
|
}
|
|
@@ -8850,7 +9079,7 @@ function createAdminUsersRoute(config) {
|
|
|
8850
9079
|
* when the user passes a plain `RebaseAuthConfig` object.
|
|
8851
9080
|
*/
|
|
8852
9081
|
function createBuiltinAuthAdapter(config) {
|
|
8853
|
-
const { authRepository, emailService, emailConfig, allowRegistration = false, disableSelfRegistration = false, allowAnonymous = false, allowUserLookup = false, defaultRole, oauthProviders = [], allowedRedirectUris, serviceKey, authHooks, collectionAuthConfig, enableMagicLink = false, cookieAuth } = config;
|
|
9082
|
+
const { authRepository, emailService, emailConfig, allowRegistration = false, disableSelfRegistration = false, allowAnonymous = false, allowUserLookup = false, captcha, defaultRole, oauthProviders = [], allowedRedirectUris, serviceKey, authHooks, collectionAuthConfig, enableMagicLink = false, cookieAuth } = config;
|
|
8854
9083
|
const resolvedOps = resolveAuthHooks(authHooks);
|
|
8855
9084
|
return {
|
|
8856
9085
|
id: "rebase-builtin",
|
|
@@ -8937,7 +9166,8 @@ function createBuiltinAuthAdapter(config) {
|
|
|
8937
9166
|
allowedRedirectUris,
|
|
8938
9167
|
authHooks,
|
|
8939
9168
|
enableMagicLink,
|
|
8940
|
-
cookieAuth
|
|
9169
|
+
cookieAuth,
|
|
9170
|
+
captcha
|
|
8941
9171
|
});
|
|
8942
9172
|
},
|
|
8943
9173
|
createAdminRoutes() {
|
|
@@ -10734,9 +10964,11 @@ function createCustomAuthAdapter(options) {
|
|
|
10734
10964
|
//#endregion
|
|
10735
10965
|
//#region src/auth/index.ts
|
|
10736
10966
|
var auth_exports = /* @__PURE__ */ __exportAll({
|
|
10967
|
+
DEFAULT_CAPTCHA_ROUTES: () => DEFAULT_CAPTCHA_ROUTES,
|
|
10737
10968
|
MemoryRateLimitStore: () => MemoryRateLimitStore,
|
|
10738
10969
|
RateLimitStoreConfigurationError: () => RateLimitStoreConfigurationError,
|
|
10739
10970
|
apiKeyKeyGenerator: () => apiKeyKeyGenerator,
|
|
10971
|
+
buildCaptchaMiddlewares: () => buildCaptchaMiddlewares,
|
|
10740
10972
|
configureJwt: () => configureJwt,
|
|
10741
10973
|
createAdapterAuthMiddleware: () => createAdapterAuthMiddleware,
|
|
10742
10974
|
createApiKeyRoutes: () => createApiKeyRoutes,
|
|
@@ -10746,6 +10978,7 @@ var auth_exports = /* @__PURE__ */ __exportAll({
|
|
|
10746
10978
|
createAuthRoutes: () => createAuthRoutes,
|
|
10747
10979
|
createBitbucketProvider: () => createBitbucketProvider,
|
|
10748
10980
|
createBuiltinAuthAdapter: () => createBuiltinAuthAdapter,
|
|
10981
|
+
createCaptchaMiddleware: () => createCaptchaMiddleware,
|
|
10749
10982
|
createCustomAuthAdapter: () => createCustomAuthAdapter,
|
|
10750
10983
|
createDataRateLimiter: () => createDataRateLimiter,
|
|
10751
10984
|
createDiscordProvider: () => createDiscordProvider,
|
|
@@ -10753,6 +10986,7 @@ var auth_exports = /* @__PURE__ */ __exportAll({
|
|
|
10753
10986
|
createGitHubProvider: () => createGitHubProvider,
|
|
10754
10987
|
createGitLabProvider: () => createGitLabProvider,
|
|
10755
10988
|
createGoogleProvider: () => createGoogleProvider,
|
|
10989
|
+
createHttpCaptchaVerifier: () => createHttpCaptchaVerifier,
|
|
10756
10990
|
createJwksRoutes: () => createJwksRoutes,
|
|
10757
10991
|
createLinkedinProvider: () => createLinkedinProvider,
|
|
10758
10992
|
createMicrosoftProvider: () => createMicrosoftProvider,
|
|
@@ -10794,6 +11028,7 @@ var auth_exports = /* @__PURE__ */ __exportAll({
|
|
|
10794
11028
|
requireAdmin: () => requireAdmin,
|
|
10795
11029
|
requireAuth: () => requireAuth,
|
|
10796
11030
|
resolveAuthHooks: () => resolveAuthHooks,
|
|
11031
|
+
resolveCaptchaVerifier: () => resolveCaptchaVerifier,
|
|
10797
11032
|
resolveRateLimitStoreKind: () => resolveRateLimitStoreKind,
|
|
10798
11033
|
safeCompare: () => safeCompare,
|
|
10799
11034
|
strictAuthLimiter: () => strictAuthLimiter,
|
|
@@ -10806,6 +11041,6 @@ var auth_exports = /* @__PURE__ */ __exportAll({
|
|
|
10806
11041
|
verifyPassword: () => verifyPassword
|
|
10807
11042
|
});
|
|
10808
11043
|
//#endregion
|
|
10809
|
-
export {
|
|
11044
|
+
export { html as $, _coercedNumber as A, resolveAuthHooks as B, providerVerifiedEmail as C, orderByEntriesToTuples as Ct, _enum as D, resolveListLimitParam as Dt, ZodNumber as E, parseQueryOptions as Et, extractLinks as F, getEmailVerificationTemplate as G, validatePasswordStrength as H, SMTPEmailService as I, getUserInvitationTemplate as J, getMagicLinkTemplate as K, createEmailService as L, createDataRateLimiter as M, MemoryRateLimitStore as N, object as O, PUBLIC_STORAGE_PREFIX as Ot, createDevEmailSink as P, escapeHtml as Q, assertEmailLinkBases as R, pkceTokenParams as S, isOperationAllowed as St, createBuiltinAuthAdapter as T, parseGroupBy as Tt, verifyPassword as U, hashPassword as V, generateSecurePassword as W, resolveEmailBranding as X, getWelcomeEmailTemplate as Y, RawHtml as Z, verifyOidcIdToken as _, safeCompare as _t, resolveRateLimitStoreKind as a, fileTokenAuth as at, createGoogleProvider as b, hasAdministrativeRole as bt, createSlackProvider as c, queryTokenAuth as ct, createDiscordProvider as d, createApiKeyPreAuth as dt, raw as et, createTwitterProvider as f, createFunctionApiKeyGuard as ft, tryVerifyOidcIdToken as g, extractBearerToken as gt, createMicrosoftProvider as h, validateApiKey as ht, createApiKeyStore as i, extractUserFromToken as it, DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT as j, string as k, isPublicStoragePath as kt, createBitbucketProvider as l, requireAdmin as lt, createAppleProvider as m, isApiKeyToken as mt, createCustomAuthAdapter as n, createAuthMiddleware as nt, createSqlRateLimitStore as o, optionalAuth as ot, createFacebookProvider as p, createStorageApiKeyGuard as pt, getPasswordResetTemplate as q, createApiKeyRoutes as r, createRequireAuth as rt, createSpotifyProvider as s, publicObjectAuth as st, auth_exports as t, createAdapterAuthMiddleware as tt, createGitLabProvider as u, requireAuth as ut, createGitHubProvider as v, SERVICE_IDENTITY as vt, createJwksRoutes as w, parseAggregateSelect as wt, oauthCodeFlowSchema as x, httpMethodToOperation as xt, createLinkedinProvider as y, scopeDataDriver as yt, resolveEmailLinkBase as z };
|
|
10810
11045
|
|
|
10811
|
-
//# sourceMappingURL=auth-
|
|
11046
|
+
//# sourceMappingURL=auth-C74dqR2B.js.map
|