@rebasepro/server 0.16.1-canary.gef08a6e → 0.17.0
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/{admin_block-BeypnEfb.js → admin_block-BX6YULvJ.js} +8 -8
- package/dist/admin_block-BX6YULvJ.js.map +1 -0
- package/dist/api/ast-schema-editor.d.ts +1 -1
- package/dist/api/rest/idempotency.d.ts +1 -1
- package/dist/{ast-schema-editor-BrarYZCq.js → ast-schema-editor-BLADP9O2.js} +3 -3
- package/dist/ast-schema-editor-BLADP9O2.js.map +1 -0
- package/dist/auth/crypto-utils.d.ts +4 -0
- package/dist/auth/jwt-crypto.d.ts +91 -0
- package/dist/auth/jwt.d.ts +10 -9
- package/dist/auth/middleware.d.ts +1 -1
- package/dist/auth/rate-limiter.d.ts +10 -3
- package/dist/{auth-DU-nUjPp.js → auth-BVPx33qB.js} +49 -76
- package/dist/auth-BVPx33qB.js.map +1 -0
- package/dist/boot/fetch-bundle.d.ts +18 -1
- package/dist/collections/validate-config.d.ts +14 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +248 -66
- package/dist/index.es.js.map +1 -1
- package/dist/{jwt-DoHkMMWF.js → jwt-5VN4C6ln.js} +230 -38
- package/dist/jwt-5VN4C6ln.js.map +1 -0
- package/dist/{schema-editor-routes-Bf5h5Emf.js → schema-editor-routes-BWCIqZoT.js} +2 -2
- package/dist/{schema-editor-routes-Bf5h5Emf.js.map → schema-editor-routes-BWCIqZoT.js.map} +1 -1
- package/dist/src-B-CmIFMr.js.map +1 -1
- package/dist/src-Cdsw7DqV.js.map +1 -1
- package/dist/storage/keys.d.ts +21 -0
- package/dist/utils/ip-address.d.ts +30 -0
- package/dist/utils/portable-crypto.d.ts +71 -0
- package/dist/utils/request-id.d.ts +20 -0
- package/package.json +5 -5
- package/dist/admin_block-BeypnEfb.js.map +0 -1
- package/dist/ast-schema-editor-BrarYZCq.js.map +0 -1
- package/dist/auth-DU-nUjPp.js.map +0 -1
- package/dist/jwt-DoHkMMWF.js.map +0 -1
|
@@ -6,7 +6,7 @@ import { i as __toESM, n as __exportAll } from "./rolldown-runtime-dW7B1o5h.js";
|
|
|
6
6
|
import { D as isAnonymousUid, E as ANONYMOUS_USER_ID } from "./src-B-CmIFMr.js";
|
|
7
7
|
import "./src-Cdsw7DqV.js";
|
|
8
8
|
import { n as createDdlBootstrapper, o as isSQLAdmin } from "./ddl-bootstrap-5YZCZ8qk.js";
|
|
9
|
-
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 { D as randomInt$1, E as constantTimeEqual, O as sha256Hex, 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-5VN4C6ln.js";
|
|
10
10
|
import { t as revokeInternalTableSql } from "./internal-tables-DpxfPaEB.js";
|
|
11
11
|
import { t as logger } from "./logger-DS03e908.js";
|
|
12
12
|
import { n as errorHandler, t as ApiError } from "./errors-DBwpj9N8.js";
|
|
@@ -15,7 +15,7 @@ import { i as object, o as string } from "./schemas-DBxgjM9A.js";
|
|
|
15
15
|
import { createHash, randomBytes, randomInt } from "node:crypto";
|
|
16
16
|
import { Hono } from "hono";
|
|
17
17
|
import { promisify } from "util";
|
|
18
|
-
import { createCipheriv, createDecipheriv, createHash as createHash$1, createHmac, createPublicKey, randomBytes as randomBytes$1, randomUUID
|
|
18
|
+
import { createCipheriv, createDecipheriv, createHash as createHash$1, createHmac, createPublicKey, randomBytes as randomBytes$1, randomUUID, scrypt, timingSafeEqual } from "crypto";
|
|
19
19
|
import { getConnInfo } from "@hono/node-server/conninfo";
|
|
20
20
|
import { createMiddleware } from "hono/factory";
|
|
21
21
|
//#region ../types/src/controllers/storage.ts
|
|
@@ -297,23 +297,16 @@ async function scopeDataDriver(driver, user) {
|
|
|
297
297
|
* Used for comparing service keys, tokens, and other secrets where
|
|
298
298
|
* timing side-channels could leak information about the expected value.
|
|
299
299
|
*
|
|
300
|
+
* The implementation lives in `utils/portable-crypto.ts`, which does this over
|
|
301
|
+
* UTF-8 bytes without `node:crypto` — this function is on the request path, and
|
|
302
|
+
* the byte-level reasoning it depends on is documented there.
|
|
303
|
+
*
|
|
300
304
|
* @param a - First string to compare.
|
|
301
305
|
* @param b - Second string to compare.
|
|
302
306
|
* @returns `true` if the strings are identical, `false` otherwise.
|
|
303
307
|
*/
|
|
304
308
|
function safeCompare(a, b) {
|
|
305
|
-
|
|
306
|
-
const bytesB = Buffer.from(b, "utf8");
|
|
307
|
-
const length = Math.max(bytesA.length, bytesB.length);
|
|
308
|
-
const paddedA = Buffer.alloc(length);
|
|
309
|
-
const paddedB = Buffer.alloc(length);
|
|
310
|
-
bytesA.copy(paddedA);
|
|
311
|
-
bytesB.copy(paddedB);
|
|
312
|
-
try {
|
|
313
|
-
return timingSafeEqual(paddedA, paddedB) && bytesA.length === bytesB.length;
|
|
314
|
-
} catch {
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
309
|
+
return constantTimeEqual(a, b);
|
|
317
310
|
}
|
|
318
311
|
//#endregion
|
|
319
312
|
//#region src/auth/bearer-token.ts
|
|
@@ -352,29 +345,6 @@ function extractBearerToken(authHeader) {
|
|
|
352
345
|
//#endregion
|
|
353
346
|
//#region src/auth/api-keys/api-key-middleware.ts
|
|
354
347
|
/**
|
|
355
|
-
* Hono middleware for authenticating requests via Service API Keys.
|
|
356
|
-
*
|
|
357
|
-
* This middleware is integrated into `createAuthMiddleware()` and
|
|
358
|
-
* activates only when the bearer token starts with `rk_`. It:
|
|
359
|
-
*
|
|
360
|
-
* 1. Hashes the token with SHA-256
|
|
361
|
-
* 2. Looks up the hash in the `rebase.api_keys` table
|
|
362
|
-
* 3. Validates the key is not revoked and not expired
|
|
363
|
-
* 4. Sets `c.set("user", ...)` and `c.set("apiKey", ...)` for downstream use
|
|
364
|
-
* 5. Scopes the DataDriver via `withAuth()` using the API key's service identity
|
|
365
|
-
*
|
|
366
|
-
* Authorization is double-gated for API keys: the key's own permission list
|
|
367
|
-
* (checked by the REST generator) is one ceiling, and Postgres RLS is another,
|
|
368
|
-
* independent one — `withAuth()` runs API-key requests as the restricted
|
|
369
|
-
* `rebase_user` role like any other caller. An `admin` key passes RLS via the
|
|
370
|
-
* injected `default_admin` policies; a non-admin key (roles `["service"]`,
|
|
371
|
-
* uid `api-key:<id>`) only sees rows that a policy explicitly grants to the
|
|
372
|
-
* `service` role or to the public. Owner-style policies
|
|
373
|
-
* (`owner_id = rebase.uid()`) never match an API key's synthetic uid.
|
|
374
|
-
*
|
|
375
|
-
* @module
|
|
376
|
-
*/
|
|
377
|
-
/**
|
|
378
348
|
* Check whether a token looks like a Rebase API key.
|
|
379
349
|
*/
|
|
380
350
|
function isApiKeyToken(token) {
|
|
@@ -382,9 +352,12 @@ function isApiKeyToken(token) {
|
|
|
382
352
|
}
|
|
383
353
|
/**
|
|
384
354
|
* Hash a plaintext API key token for database lookup.
|
|
355
|
+
*
|
|
356
|
+
* Async because it hashes with WebCrypto rather than `node:crypto` — the sole
|
|
357
|
+
* caller was already awaiting the store lookup this feeds.
|
|
385
358
|
*/
|
|
386
359
|
function hashToken$1(token) {
|
|
387
|
-
return
|
|
360
|
+
return sha256Hex(token);
|
|
388
361
|
}
|
|
389
362
|
/**
|
|
390
363
|
* Validate an API key token and populate the Hono context.
|
|
@@ -397,7 +370,7 @@ function hashToken$1(token) {
|
|
|
397
370
|
*/
|
|
398
371
|
async function validateApiKey(c, token, options) {
|
|
399
372
|
const { store, driver } = options;
|
|
400
|
-
const hash = hashToken$1(token);
|
|
373
|
+
const hash = await hashToken$1(token);
|
|
401
374
|
const apiKey = await store.findByKeyHash(hash);
|
|
402
375
|
if (!apiKey) return c.json({ error: {
|
|
403
376
|
message: "Invalid API key",
|
|
@@ -570,7 +543,7 @@ var requireAuth = async (c, next) => {
|
|
|
570
543
|
message: "Authorization header missing or invalid",
|
|
571
544
|
code: "UNAUTHORIZED"
|
|
572
545
|
} }, 401);
|
|
573
|
-
const payload = verifyAccessToken(token);
|
|
546
|
+
const payload = await verifyAccessToken(token);
|
|
574
547
|
if (!payload) return c.json({ error: {
|
|
575
548
|
message: "Invalid or expired token",
|
|
576
549
|
code: "UNAUTHORIZED"
|
|
@@ -607,7 +580,7 @@ function createRequireAuth(options) {
|
|
|
607
580
|
});
|
|
608
581
|
return next();
|
|
609
582
|
}
|
|
610
|
-
const payload = verifyAccessToken(token);
|
|
583
|
+
const payload = await verifyAccessToken(token);
|
|
611
584
|
if (!payload) return c.json({ error: {
|
|
612
585
|
message: "Invalid or expired token",
|
|
613
586
|
code: "UNAUTHORIZED"
|
|
@@ -663,7 +636,7 @@ var optionalAuth = async (c, next) => {
|
|
|
663
636
|
if (c.get("user")) return next();
|
|
664
637
|
const token = extractBearerToken(c.req.header("authorization"));
|
|
665
638
|
if (token !== void 0 && isJwtConfigured()) {
|
|
666
|
-
const payload = verifyAccessToken(token);
|
|
639
|
+
const payload = await verifyAccessToken(token);
|
|
667
640
|
if (payload) c.set("user", payload);
|
|
668
641
|
}
|
|
669
642
|
return next();
|
|
@@ -671,7 +644,7 @@ var optionalAuth = async (c, next) => {
|
|
|
671
644
|
/**
|
|
672
645
|
* Extract user from token - for WebSocket authentication
|
|
673
646
|
*/
|
|
674
|
-
function extractUserFromToken(token) {
|
|
647
|
+
async function extractUserFromToken(token) {
|
|
675
648
|
if (!isJwtConfigured()) return null;
|
|
676
649
|
return verifyAccessToken(token);
|
|
677
650
|
}
|
|
@@ -762,7 +735,7 @@ function createAuthMiddleware(options) {
|
|
|
762
735
|
});
|
|
763
736
|
if (result !== true) return result;
|
|
764
737
|
} else {
|
|
765
|
-
const payload = extractUserFromToken(token);
|
|
738
|
+
const payload = await extractUserFromToken(token);
|
|
766
739
|
if (payload) {
|
|
767
740
|
c.set("user", payload);
|
|
768
741
|
try {
|
|
@@ -824,7 +797,7 @@ var queryTokenAuth = async (c, next) => {
|
|
|
824
797
|
if (extractBearerToken(c.req.header("authorization")) !== void 0) return next();
|
|
825
798
|
const queryToken = c.req.query("token");
|
|
826
799
|
if (queryToken && isJwtConfigured()) {
|
|
827
|
-
const payload = verifyAccessToken(queryToken);
|
|
800
|
+
const payload = await verifyAccessToken(queryToken);
|
|
828
801
|
if (payload) c.set("user", payload);
|
|
829
802
|
}
|
|
830
803
|
return next();
|
|
@@ -947,7 +920,7 @@ var fileTokenAuth = async (c, next) => {
|
|
|
947
920
|
} }, 403);
|
|
948
921
|
const bearerToken = extractBearerToken(authHeader);
|
|
949
922
|
if (bearerToken !== void 0) {
|
|
950
|
-
const payload = verifyDownloadToken(bearerToken);
|
|
923
|
+
const payload = await verifyDownloadToken(bearerToken);
|
|
951
924
|
if (payload) {
|
|
952
925
|
const outcome = evaluateGrant(payload);
|
|
953
926
|
if (outcome === "grant") {
|
|
@@ -966,7 +939,7 @@ var fileTokenAuth = async (c, next) => {
|
|
|
966
939
|
return next();
|
|
967
940
|
}
|
|
968
941
|
if (queryToken) {
|
|
969
|
-
const payload = verifyDownloadToken(queryToken);
|
|
942
|
+
const payload = await verifyDownloadToken(queryToken);
|
|
970
943
|
if (payload) {
|
|
971
944
|
const outcome = evaluateGrant(payload);
|
|
972
945
|
if (outcome === "grant") {
|
|
@@ -2424,10 +2397,10 @@ function createRateLimiter(options = {}) {
|
|
|
2424
2397
|
const trustedProxyHops = resolveTrustedProxyHops(options.trustedProxyHops);
|
|
2425
2398
|
const { windowMs = 900 * 1e3, limit = 100, keyGenerator = (c) => defaultKeyGenerator(c, trustedProxyHops), message = "Too many requests, please try again later.", store = new MemoryRateLimitStore(windowMs), resolveLimit } = options;
|
|
2426
2399
|
return async (c, next) => {
|
|
2427
|
-
const effectiveLimit = resolveLimit ? resolveLimit(c) : limit;
|
|
2400
|
+
const effectiveLimit = resolveLimit ? await resolveLimit(c) : limit;
|
|
2428
2401
|
if (effectiveLimit === null) return next();
|
|
2429
2402
|
const activeLimit = effectiveLimit ?? limit;
|
|
2430
|
-
const decision = await store.hit(keyGenerator(c), windowMs, activeLimit);
|
|
2403
|
+
const decision = await store.hit(await keyGenerator(c), windowMs, activeLimit);
|
|
2431
2404
|
c.header("X-RateLimit-Limit", String(activeLimit));
|
|
2432
2405
|
c.header("X-RateLimit-Remaining", String(decision.remaining));
|
|
2433
2406
|
if (!decision.allowed) {
|
|
@@ -2599,13 +2572,13 @@ function createDataRateLimiter(config = {}) {
|
|
|
2599
2572
|
* to the context; an identity that fails to verify simply buckets by IP,
|
|
2600
2573
|
* exactly as before.
|
|
2601
2574
|
*/
|
|
2602
|
-
const identify = (c) => {
|
|
2575
|
+
const identify = async (c) => {
|
|
2603
2576
|
const user = c.get("user");
|
|
2604
2577
|
if (user?.uid) return isAnonymousUid(user.uid) ? void 0 : user.uid;
|
|
2605
2578
|
if (!isJwtConfigured()) return void 0;
|
|
2606
2579
|
const token = extractBearerToken(c.req.header("authorization"));
|
|
2607
2580
|
if (token === void 0) return void 0;
|
|
2608
|
-
const payload = verifyAccessToken(token);
|
|
2581
|
+
const payload = await verifyAccessToken(token);
|
|
2609
2582
|
if (!payload?.uid || isAnonymousUid(payload.uid)) return void 0;
|
|
2610
2583
|
return payload.uid;
|
|
2611
2584
|
};
|
|
@@ -2613,17 +2586,17 @@ function createDataRateLimiter(config = {}) {
|
|
|
2613
2586
|
windowMs,
|
|
2614
2587
|
store,
|
|
2615
2588
|
message: "Too many requests, please try again later.",
|
|
2616
|
-
keyGenerator: (c) => {
|
|
2589
|
+
keyGenerator: async (c) => {
|
|
2617
2590
|
const key = c.get("apiKey");
|
|
2618
2591
|
if (key) return `api-key:${key.id}`;
|
|
2619
|
-
const uid = identify(c);
|
|
2592
|
+
const uid = await identify(c);
|
|
2620
2593
|
if (uid) return `user:${uid}`;
|
|
2621
2594
|
return `ip:${defaultKeyGenerator(c, trustedProxyHops)}`;
|
|
2622
2595
|
},
|
|
2623
|
-
resolveLimit: (c) => {
|
|
2596
|
+
resolveLimit: async (c) => {
|
|
2624
2597
|
const key = c.get("apiKey");
|
|
2625
2598
|
if (key) return key.rate_limit ?? apiKeyLimit;
|
|
2626
|
-
return identify(c) ? userLimit : anonLimit;
|
|
2599
|
+
return await identify(c) ? userLimit : anonLimit;
|
|
2627
2600
|
}
|
|
2628
2601
|
});
|
|
2629
2602
|
}
|
|
@@ -3165,7 +3138,7 @@ async function openAndRewrap(authRepo, factorId, secretEncrypted) {
|
|
|
3165
3138
|
}
|
|
3166
3139
|
return secret;
|
|
3167
3140
|
}
|
|
3168
|
-
function resolveStepUpPrincipal(c) {
|
|
3141
|
+
async function resolveStepUpPrincipal(c) {
|
|
3169
3142
|
const existing = c.get("user");
|
|
3170
3143
|
if (existing?.uid) return {
|
|
3171
3144
|
uid: existing.uid,
|
|
@@ -3174,13 +3147,13 @@ function resolveStepUpPrincipal(c) {
|
|
|
3174
3147
|
};
|
|
3175
3148
|
const token = extractBearerToken(c.req.header("authorization"));
|
|
3176
3149
|
if (token === void 0) return null;
|
|
3177
|
-
const session = verifyAccessToken(token);
|
|
3150
|
+
const session = await verifyAccessToken(token);
|
|
3178
3151
|
if (session) return {
|
|
3179
3152
|
uid: session.uid,
|
|
3180
3153
|
aal: session.aal === "aal2" ? "aal2" : "aal1",
|
|
3181
3154
|
pending: false
|
|
3182
3155
|
};
|
|
3183
|
-
const pending = verifyMfaPendingToken(token);
|
|
3156
|
+
const pending = await verifyMfaPendingToken(token);
|
|
3184
3157
|
if (pending) return {
|
|
3185
3158
|
uid: pending.uid,
|
|
3186
3159
|
aal: "aal1",
|
|
@@ -3199,7 +3172,7 @@ function resolveStepUpPrincipal(c) {
|
|
|
3199
3172
|
var mfaVerificationLimiter = createRateLimiter({
|
|
3200
3173
|
windowMs: 900 * 1e3,
|
|
3201
3174
|
limit: MFA_VERIFICATION_ATTEMPTS_PER_WINDOW,
|
|
3202
|
-
keyGenerator: (c) => `mfa-verify:${resolveStepUpPrincipal(c)?.uid ?? "unidentified"}`,
|
|
3175
|
+
keyGenerator: async (c) => `mfa-verify:${(await resolveStepUpPrincipal(c))?.uid ?? "unidentified"}`,
|
|
3203
3176
|
message: "Too many verification attempts for this account, please try again later."
|
|
3204
3177
|
});
|
|
3205
3178
|
function mountMfaRoutes(opts) {
|
|
@@ -3303,7 +3276,7 @@ function mountMfaRoutes(opts) {
|
|
|
3303
3276
|
* `MFA_REQUIRED`, or to step an existing session up to `aal2`.
|
|
3304
3277
|
*/
|
|
3305
3278
|
router.post("/mfa/challenge", strictAuthLimiter, async (c) => {
|
|
3306
|
-
const principal = resolveStepUpPrincipal(c);
|
|
3279
|
+
const principal = await resolveStepUpPrincipal(c);
|
|
3307
3280
|
if (!principal) throw ApiError.unauthorized("Not authenticated");
|
|
3308
3281
|
const challengeSchema = object({ factorId: string().min(1, "Factor ID is required") });
|
|
3309
3282
|
const { factorId } = parseBody(challengeSchema, await c.req.json());
|
|
@@ -3324,7 +3297,7 @@ function mountMfaRoutes(opts) {
|
|
|
3324
3297
|
* minted, at `aal2`.
|
|
3325
3298
|
*/
|
|
3326
3299
|
router.post("/mfa/challenge/verify", strictAuthLimiter, mfaVerificationLimiter, async (c) => {
|
|
3327
|
-
const principal = resolveStepUpPrincipal(c);
|
|
3300
|
+
const principal = await resolveStepUpPrincipal(c);
|
|
3328
3301
|
if (!principal) throw ApiError.unauthorized("Not authenticated");
|
|
3329
3302
|
const challengeVerifySchema = object({
|
|
3330
3303
|
challengeId: string().min(1, "Challenge ID is required"),
|
|
@@ -3452,7 +3425,7 @@ async function assertMfaSatisfied(authRepo, uid) {
|
|
|
3452
3425
|
if (!await authRepo.hasVerifiedMfaFactors(uid)) return;
|
|
3453
3426
|
const factors = (await authRepo.getMfaFactors(uid)).filter((f) => f.verified);
|
|
3454
3427
|
const details = {
|
|
3455
|
-
mfaToken: generateMfaPendingToken(uid),
|
|
3428
|
+
mfaToken: await generateMfaPendingToken(uid),
|
|
3456
3429
|
factors: factors.map((f) => ({
|
|
3457
3430
|
id: f.id,
|
|
3458
3431
|
factorType: f.factorType,
|
|
@@ -3554,7 +3527,7 @@ function mountSessionRoutes(opts) {
|
|
|
3554
3527
|
const body = await c.req.json().catch(() => ({}));
|
|
3555
3528
|
const refreshToken = readRefreshToken(c, parseBody(logoutSchema, body), config.cookieAuth);
|
|
3556
3529
|
if (refreshToken) {
|
|
3557
|
-
const tokenHash = hashRefreshToken(refreshToken);
|
|
3530
|
+
const tokenHash = await hashRefreshToken(refreshToken);
|
|
3558
3531
|
const sessionId = (await authRepo.findRefreshTokenByHash(tokenHash).catch(() => null))?.sessionId;
|
|
3559
3532
|
if (sessionId && authRepo.revokeRefreshTokenSession) await authRepo.revokeRefreshTokenSession(sessionId);
|
|
3560
3533
|
else await authRepo.deleteRefreshToken(tokenHash);
|
|
@@ -3562,8 +3535,8 @@ function mountSessionRoutes(opts) {
|
|
|
3562
3535
|
clearRefreshCookie(c, config.cookieAuth);
|
|
3563
3536
|
const accessToken = extractBearerToken(c.req.header("authorization"));
|
|
3564
3537
|
if (ops.afterLogout && accessToken !== void 0) {
|
|
3565
|
-
const { verifyAccessToken } = await import("./jwt-
|
|
3566
|
-
const payload = verifyAccessToken(accessToken);
|
|
3538
|
+
const { verifyAccessToken } = await import("./jwt-5VN4C6ln.js").then((n) => n.m);
|
|
3539
|
+
const payload = await verifyAccessToken(accessToken);
|
|
3567
3540
|
if (payload) ops.afterLogout(payload.uid).catch((err) => {
|
|
3568
3541
|
logger.error("[AuthHooks] afterLogout error", { error: err instanceof Error ? err.message : err });
|
|
3569
3542
|
});
|
|
@@ -3578,7 +3551,7 @@ function mountSessionRoutes(opts) {
|
|
|
3578
3551
|
const userCtx = c.get("user");
|
|
3579
3552
|
if (!userCtx) throw ApiError.unauthorized("Not authenticated");
|
|
3580
3553
|
const currentRefreshToken = c.req.header("x-refresh-token");
|
|
3581
|
-
const currentTokenHash = currentRefreshToken ? hashRefreshToken(currentRefreshToken) : null;
|
|
3554
|
+
const currentTokenHash = currentRefreshToken ? await hashRefreshToken(currentRefreshToken) : null;
|
|
3582
3555
|
const tokens = await authRepo.listRefreshTokensForUser(userCtx.uid);
|
|
3583
3556
|
const bySession = /* @__PURE__ */ new Map();
|
|
3584
3557
|
for (const token of tokens) {
|
|
@@ -3846,7 +3819,7 @@ var OTP_ATTEMPTS_PER_WINDOW = 5;
|
|
|
3846
3819
|
* and one of them is the classic modulo bias.
|
|
3847
3820
|
*/
|
|
3848
3821
|
function generateOtpCode() {
|
|
3849
|
-
return String(randomInt(
|
|
3822
|
+
return String(randomInt$1(10 ** OTP_DIGITS)).padStart(OTP_DIGITS, "0");
|
|
3850
3823
|
}
|
|
3851
3824
|
/**
|
|
3852
3825
|
* What gets hashed and stored.
|
|
@@ -4184,10 +4157,10 @@ function createAuthRoutes(config) {
|
|
|
4184
4157
|
customClaims = await ops.customizeAccessToken(defaultClaims, user);
|
|
4185
4158
|
}
|
|
4186
4159
|
}
|
|
4187
|
-
const accessToken = generateAccessToken(uid, roleIds, aal, customClaims);
|
|
4160
|
+
const accessToken = await generateAccessToken(uid, roleIds, aal, customClaims);
|
|
4188
4161
|
const refreshToken = generateRefreshToken();
|
|
4189
|
-
await authRepo.createRefreshToken(uid, hashRefreshToken(refreshToken), getRefreshTokenExpiry(), userAgent, ipAddress, {
|
|
4190
|
-
id: randomUUID
|
|
4162
|
+
await authRepo.createRefreshToken(uid, await hashRefreshToken(refreshToken), getRefreshTokenExpiry(), userAgent, ipAddress, {
|
|
4163
|
+
id: randomUUID(),
|
|
4191
4164
|
startedAt: /* @__PURE__ */ new Date(),
|
|
4192
4165
|
aal
|
|
4193
4166
|
});
|
|
@@ -4551,7 +4524,7 @@ function createAuthRoutes(config) {
|
|
|
4551
4524
|
const body = await c.req.json().catch(() => ({}));
|
|
4552
4525
|
const refreshToken = readRefreshToken(c, parseBody(refreshSchema, body), config.cookieAuth);
|
|
4553
4526
|
if (!refreshToken) throw ApiError.unauthenticated("No refresh token presented", "NO_SESSION");
|
|
4554
|
-
const tokenHash = hashRefreshToken(refreshToken);
|
|
4527
|
+
const tokenHash = await hashRefreshToken(refreshToken);
|
|
4555
4528
|
const storedToken = await authRepo.findRefreshTokenByHash(tokenHash);
|
|
4556
4529
|
if (!storedToken) throw ApiError.unauthorized("Invalid refresh token", "INVALID_TOKEN");
|
|
4557
4530
|
if (storedToken.revoked) {
|
|
@@ -4599,7 +4572,7 @@ function createAuthRoutes(config) {
|
|
|
4599
4572
|
};
|
|
4600
4573
|
customClaims = await ops.customizeAccessToken(defaultClaims, user);
|
|
4601
4574
|
}
|
|
4602
|
-
const newAccessToken = generateAccessToken(storedToken.uid, roleIds, sessionAal, customClaims);
|
|
4575
|
+
const newAccessToken = await generateAccessToken(storedToken.uid, roleIds, sessionAal, customClaims);
|
|
4603
4576
|
const newRefreshToken = generateRefreshToken();
|
|
4604
4577
|
const userAgent = c.req.header("user-agent") || "unknown";
|
|
4605
4578
|
const ipAddress = c.req.header("x-forwarded-for") || "unknown";
|
|
@@ -4610,7 +4583,7 @@ function createAuthRoutes(config) {
|
|
|
4610
4583
|
};
|
|
4611
4584
|
if (!supersededAt) if (authRepo.markRefreshTokenRotated) await authRepo.markRefreshTokenRotated(tokenHash);
|
|
4612
4585
|
else await authRepo.deleteRefreshToken(tokenHash);
|
|
4613
|
-
await authRepo.createRefreshToken(storedToken.uid, hashRefreshToken(newRefreshToken), getRefreshTokenExpiry(), userAgent, ipAddress, session);
|
|
4586
|
+
await authRepo.createRefreshToken(storedToken.uid, await hashRefreshToken(newRefreshToken), getRefreshTokenExpiry(), userAgent, ipAddress, session);
|
|
4614
4587
|
authRepo.pruneRefreshTokens?.(storedToken.uid, session.id, new Date(Date.now() - reuseWindowMs)).catch((err) => {
|
|
4615
4588
|
logger.warn("[Auth] Refresh token prune failed", { error: err instanceof Error ? err.message : String(err) });
|
|
4616
4589
|
});
|
|
@@ -5090,7 +5063,7 @@ function createBuiltinAuthAdapter(config) {
|
|
|
5090
5063
|
isAdmin: true,
|
|
5091
5064
|
rawToken: token
|
|
5092
5065
|
};
|
|
5093
|
-
const payload = verifyAccessToken(token);
|
|
5066
|
+
const payload = await verifyAccessToken(token);
|
|
5094
5067
|
if (!payload) return null;
|
|
5095
5068
|
if (await isAccessTokenRevoked(authRepository, payload)) {
|
|
5096
5069
|
logger.warn("[Security Audit] Refused a revoked access token", {
|
|
@@ -5126,7 +5099,7 @@ function createBuiltinAuthAdapter(config) {
|
|
|
5126
5099
|
isAdmin: true,
|
|
5127
5100
|
rawToken: token
|
|
5128
5101
|
};
|
|
5129
|
-
const payload = verifyAccessToken(token);
|
|
5102
|
+
const payload = await verifyAccessToken(token);
|
|
5130
5103
|
if (!payload) return null;
|
|
5131
5104
|
if (await isAccessTokenRevoked(authRepository, payload)) {
|
|
5132
5105
|
logger.warn("[Security Audit] Refused a revoked access token", {
|
|
@@ -7036,4 +7009,4 @@ var auth_exports = /* @__PURE__ */ __exportAll({
|
|
|
7036
7009
|
//#endregion
|
|
7037
7010
|
export { html as $, activeDevEmailSink as A, hashPassword as B, providerVerifiedEmail as C, PUBLIC_STORAGE_PREFIX as Ct, createDataRateLimiter as D, DEFAULT_FUNCTIONS_ANONYMOUS_LIMIT as E, SMTPEmailService as F, getEmailVerificationTemplate as G, verifyPassword as H, createEmailService as I, getUserInvitationTemplate as J, getMagicLinkTemplate as K, assertEmailLinkBases as L, createDevEmailSink as M, extractLinks as N, defaultAuthLimiter as O, registerDevEmailSink as P, escapeHtml as Q, resolveEmailLinkBase as R, pkceTokenParams as S, isOperationAllowed as St, createBuiltinAuthAdapter as T, generateSecurePassword as U, validatePasswordStrength as V, getEmailOtpTemplate 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, clearActiveDevEmailSink as j, MemoryRateLimitStore as k, 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, isPublicStoragePath as wt, oauthCodeFlowSchema as x, httpMethodToOperation as xt, createLinkedinProvider as y, scopeDataDriver as yt, resolveAuthHooks as z };
|
|
7038
7011
|
|
|
7039
|
-
//# sourceMappingURL=auth-
|
|
7012
|
+
//# sourceMappingURL=auth-BVPx33qB.js.map
|