@fitzzero/quickdraw-core 5.1.1 → 5.1.3

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.
Files changed (152) hide show
  1. package/README.md +1308 -219
  2. package/dist/{admin-DKwkIh5i.d.ts → admin-CS7JB_UH.d.ts} +2 -2
  3. package/dist/{adminSchemas-2DUA_hZ8.d.ts → adminSchemas-29cGgrg5.d.ts} +6 -4
  4. package/dist/{auth-BhWqdyb-.d.ts → auth-DtdYjrZ9.d.ts} +51 -21
  5. package/dist/{caller-CXTFswBO.d.ts → caller-BTwGl7vm.d.ts} +296 -33
  6. package/dist/chunk-2FDSKLBO.js +82 -0
  7. package/dist/chunk-2FDSKLBO.js.map +1 -0
  8. package/dist/{chunk-RT6OILOI.js → chunk-4D2DOGAW.js} +2 -14
  9. package/dist/chunk-4D2DOGAW.js.map +1 -0
  10. package/dist/{chunk-OECZPRPW.js → chunk-64I6MYBC.js} +162 -775
  11. package/dist/chunk-64I6MYBC.js.map +1 -0
  12. package/dist/chunk-7473HK24.js +17 -0
  13. package/dist/chunk-7473HK24.js.map +1 -0
  14. package/dist/chunk-7Y5ROPXL.js +33 -0
  15. package/dist/chunk-7Y5ROPXL.js.map +1 -0
  16. package/dist/chunk-A2RBQD66.js +7 -0
  17. package/dist/chunk-A2RBQD66.js.map +1 -0
  18. package/dist/chunk-AK23XSWD.js +16 -0
  19. package/dist/chunk-AK23XSWD.js.map +1 -0
  20. package/dist/chunk-ASAMUGHG.js +651 -0
  21. package/dist/chunk-ASAMUGHG.js.map +1 -0
  22. package/dist/{chunk-B2P7AZ25.js → chunk-CYE4UBOB.js} +6 -4
  23. package/dist/chunk-CYE4UBOB.js.map +1 -0
  24. package/dist/chunk-DKE6QO26.js +136 -0
  25. package/dist/chunk-DKE6QO26.js.map +1 -0
  26. package/dist/chunk-DNP65TD5.js +832 -0
  27. package/dist/chunk-DNP65TD5.js.map +1 -0
  28. package/dist/{chunk-H23KEFBA.js → chunk-DUBU3BB3.js} +30 -1
  29. package/dist/chunk-DUBU3BB3.js.map +1 -0
  30. package/dist/chunk-GYLWEJHW.js +19 -0
  31. package/dist/chunk-GYLWEJHW.js.map +1 -0
  32. package/dist/{chunk-SHEGLZEP.js → chunk-I3JCFS7H.js} +34 -13
  33. package/dist/chunk-I3JCFS7H.js.map +1 -0
  34. package/dist/{chunk-X5CWPX7H.js → chunk-IIQ3WMJK.js} +13 -2
  35. package/dist/chunk-IIQ3WMJK.js.map +1 -0
  36. package/dist/{chunk-RZTP4IEW.js → chunk-JVTONQFI.js} +6339 -4226
  37. package/dist/chunk-JVTONQFI.js.map +1 -0
  38. package/dist/{chunk-QEKVYG5F.js → chunk-KKQANRLG.js} +2 -2
  39. package/dist/chunk-KKQANRLG.js.map +1 -0
  40. package/dist/{chunk-CDKG4TFA.js → chunk-MPQAT55F.js} +38 -205
  41. package/dist/chunk-MPQAT55F.js.map +1 -0
  42. package/dist/chunk-NO4M6PO5.js +101 -0
  43. package/dist/chunk-NO4M6PO5.js.map +1 -0
  44. package/dist/{chunk-TBMKJ26R.js → chunk-NW6U45HX.js} +3 -1
  45. package/dist/chunk-NW6U45HX.js.map +1 -0
  46. package/dist/chunk-NX2V6SIL.js +202 -0
  47. package/dist/chunk-NX2V6SIL.js.map +1 -0
  48. package/dist/{chunk-ZIVPHYRG.js → chunk-NZHA4TZD.js} +72 -175
  49. package/dist/chunk-NZHA4TZD.js.map +1 -0
  50. package/dist/{chunk-2PWMUVC7.js → chunk-OCZJ4EYV.js} +518 -27
  51. package/dist/chunk-OCZJ4EYV.js.map +1 -0
  52. package/dist/{chunk-REX5YPHX.js → chunk-PHCURHC7.js} +76 -21
  53. package/dist/chunk-PHCURHC7.js.map +1 -0
  54. package/dist/{chunk-4YO5H5ON.js → chunk-Q4OGQM5I.js} +4 -10
  55. package/dist/chunk-Q4OGQM5I.js.map +1 -0
  56. package/dist/chunk-QSU47XEX.js +13 -0
  57. package/dist/chunk-QSU47XEX.js.map +1 -0
  58. package/dist/{chunk-DD4SKCNO.js → chunk-RZXJTDH5.js} +13 -2
  59. package/dist/chunk-RZXJTDH5.js.map +1 -0
  60. package/dist/{chunk-Z2LZ7IZ7.js → chunk-SN3OZVEQ.js} +5 -31
  61. package/dist/chunk-SN3OZVEQ.js.map +1 -0
  62. package/dist/{chunk-4DIQHASK.js → chunk-SQ5VUG77.js} +28 -8
  63. package/dist/chunk-SQ5VUG77.js.map +1 -0
  64. package/dist/chunk-STH5DLQP.js +1192 -0
  65. package/dist/chunk-STH5DLQP.js.map +1 -0
  66. package/dist/{chunk-QCHKWIRS.js → chunk-VZFJTKIW.js} +13 -13
  67. package/dist/{chunk-QCHKWIRS.js.map → chunk-VZFJTKIW.js.map} +1 -1
  68. package/dist/{chunk-VSQBHPWH.js → chunk-X4ZU4QH5.js} +54 -22
  69. package/dist/chunk-X4ZU4QH5.js.map +1 -0
  70. package/dist/chunk-XD7SRDUY.js +188 -0
  71. package/dist/chunk-XD7SRDUY.js.map +1 -0
  72. package/dist/chunk-XH2IZVLT.js +62 -0
  73. package/dist/chunk-XH2IZVLT.js.map +1 -0
  74. package/dist/chunk-Z7I6SONO.js +825 -0
  75. package/dist/chunk-Z7I6SONO.js.map +1 -0
  76. package/dist/cli/quickdraw-docs.js +132 -112
  77. package/dist/cli/quickdraw-docs.js.map +1 -1
  78. package/dist/client/core.d.ts +387 -0
  79. package/dist/client/core.js +109 -0
  80. package/dist/client/index.d.ts +52 -203
  81. package/dist/client/index.js +59 -218
  82. package/dist/client/index.js.map +1 -1
  83. package/dist/{clientTypes-Bc-G8n-U.d.ts → clientTypes-CUUNJwWs.d.ts} +3 -3
  84. package/dist/{connection-Cr1BU07W.d.ts → connection-2EeQ_Et0.d.ts} +22 -11
  85. package/dist/{createServer-CP9eDHZZ.d.ts → createServer-Bx5HOcYK.d.ts} +67 -17
  86. package/dist/{createTestApp-UKVGEmOf.d.ts → createTestApp-DAMANT79.d.ts} +46 -13
  87. package/dist/{envelope-Cp3YcVxC.d.ts → envelope-BMBaxppV.d.ts} +216 -10
  88. package/dist/{http-Djj2Inuu.d.ts → http-YzLAar3w.d.ts} +76 -60
  89. package/dist/index.d.ts +8 -7
  90. package/dist/index.js +82 -25
  91. package/dist/index.js.map +1 -1
  92. package/dist/{infer-Teo1xpsd.d.ts → infer-Br62cnyW.d.ts} +82 -11
  93. package/dist/logger-Yz93KzdV.d.ts +30 -0
  94. package/dist/{metrics-BdBu5o8G.d.ts → metrics-CTVpw0gu.d.ts} +2 -2
  95. package/dist/origins-kvpxnVcW.d.ts +8 -0
  96. package/dist/parser.js +2 -1
  97. package/dist/prisma/index.d.ts +14 -7
  98. package/dist/prisma/index.js +279 -70
  99. package/dist/prisma/index.js.map +1 -1
  100. package/dist/{rateLimit-ZMIZJUZF.js → rateLimit-5RKBFLUR.js} +2 -2
  101. package/dist/rateLimit-5RKBFLUR.js.map +1 -0
  102. package/dist/remote-N7OUAGOW.js +15 -0
  103. package/dist/remote-N7OUAGOW.js.map +1 -0
  104. package/dist/server/auth/index.d.ts +82 -33
  105. package/dist/server/auth/index.js +277 -270
  106. package/dist/server/auth/index.js.map +1 -1
  107. package/dist/server/express/index.d.ts +9 -2
  108. package/dist/server/express/index.js +1 -1
  109. package/dist/server/index.d.ts +268 -84
  110. package/dist/server/index.js +664 -418
  111. package/dist/server/index.js.map +1 -1
  112. package/dist/server/mcp/index.d.ts +89 -27
  113. package/dist/server/mcp/index.js +281 -62
  114. package/dist/server/mcp/index.js.map +1 -1
  115. package/dist/server/otel.d.ts +3 -3
  116. package/dist/{sharing-DVa8W-yR.d.ts → sharing-BrsmlDv_.d.ts} +3 -3
  117. package/dist/testing/client.d.ts +14 -14
  118. package/dist/testing/client.js +19 -10
  119. package/dist/testing/client.js.map +1 -1
  120. package/dist/testing/index.d.ts +50 -13
  121. package/dist/testing/index.js +113 -21
  122. package/dist/testing/index.js.map +1 -1
  123. package/dist/testing/mock.d.ts +5 -5
  124. package/dist/testing/mock.js +17 -9
  125. package/dist/tracked-BR5b2O-U.d.ts +43 -0
  126. package/dist/{types-Cu0vmx7c.d.ts → types-CLRCQGnO.d.ts} +4 -3
  127. package/dist/types-tMagHbjy.d.ts +151 -0
  128. package/dist/utils/index.d.ts +16 -4
  129. package/dist/utils/index.js +6 -3
  130. package/package.json +5 -1
  131. package/dist/chunk-2PWMUVC7.js.map +0 -1
  132. package/dist/chunk-4DIQHASK.js.map +0 -1
  133. package/dist/chunk-4YO5H5ON.js.map +0 -1
  134. package/dist/chunk-B2P7AZ25.js.map +0 -1
  135. package/dist/chunk-CDKG4TFA.js.map +0 -1
  136. package/dist/chunk-DD4SKCNO.js.map +0 -1
  137. package/dist/chunk-H23KEFBA.js.map +0 -1
  138. package/dist/chunk-OECZPRPW.js.map +0 -1
  139. package/dist/chunk-QEKVYG5F.js.map +0 -1
  140. package/dist/chunk-REX5YPHX.js.map +0 -1
  141. package/dist/chunk-RT6OILOI.js.map +0 -1
  142. package/dist/chunk-RZTP4IEW.js.map +0 -1
  143. package/dist/chunk-SHEGLZEP.js.map +0 -1
  144. package/dist/chunk-TBMKJ26R.js.map +0 -1
  145. package/dist/chunk-VSQBHPWH.js.map +0 -1
  146. package/dist/chunk-X5CWPX7H.js.map +0 -1
  147. package/dist/chunk-YSWH776Y.js +0 -13
  148. package/dist/chunk-YSWH776Y.js.map +0 -1
  149. package/dist/chunk-Z2LZ7IZ7.js.map +0 -1
  150. package/dist/chunk-ZIVPHYRG.js.map +0 -1
  151. package/dist/logger-BY28acW-.d.ts +0 -16
  152. /package/dist/{rateLimit-ZMIZJUZF.js.map → client/core.js.map} +0 -0
@@ -1,7 +1,15 @@
1
+ import {
2
+ OAUTH_RETURN_ORIGIN_COOKIE,
3
+ originAllowlist,
4
+ rememberRouteOrigins,
5
+ routeOriginsOf,
6
+ validateRedirectOrigin
7
+ } from "../../chunk-NO4M6PO5.js";
1
8
  import {
2
9
  HOST_SESSION_COOKIE,
3
10
  SESSION_COOKIE,
4
11
  clearSessionCookie,
12
+ clearStaleHostSession,
5
13
  cookieDomainFromEnv,
6
14
  cookieToken,
7
15
  cookiesOf,
@@ -11,25 +19,29 @@ import {
11
19
  httpCredentialOf,
12
20
  isJsonRequest,
13
21
  isSecureSessionRequest,
22
+ markSocketAuth,
14
23
  readJsonInput,
24
+ readVerifiedJWT,
15
25
  recordSocketSession,
16
26
  sessionCookieNameFor,
17
27
  sessionCookieNamesFor,
18
28
  setSessionCookie,
19
- tokenOf,
20
29
  transportCookieNaming,
21
30
  verifyJWT
22
- } from "../../chunk-REX5YPHX.js";
23
- import "../../chunk-H23KEFBA.js";
24
- import "../../chunk-Z2LZ7IZ7.js";
31
+ } from "../../chunk-PHCURHC7.js";
32
+ import "../../chunk-DUBU3BB3.js";
25
33
  import {
26
- consoleLogger
27
- } from "../../chunk-YSWH776Y.js";
34
+ consoleLogger,
35
+ errorText
36
+ } from "../../chunk-DKE6QO26.js";
37
+ import "../../chunk-SN3OZVEQ.js";
38
+ import "../../chunk-7Y5ROPXL.js";
28
39
  import {
29
40
  INTERNAL_MESSAGE,
30
41
  QuickdrawError,
31
42
  httpStatus
32
- } from "../../chunk-4YO5H5ON.js";
43
+ } from "../../chunk-Q4OGQM5I.js";
44
+ import "../../chunk-QSU47XEX.js";
33
45
 
34
46
  // src/server/auth/oauth.ts
35
47
  function createOAuthURL(provider, config, state) {
@@ -128,38 +140,15 @@ var googleProvider = {
128
140
  // src/server/auth/mock.ts
129
141
  import { randomBytes } from "crypto";
130
142
 
131
- // src/server/auth/validateOrigin.ts
132
- var OAUTH_RETURN_ORIGIN_COOKIE = "oauth_return_origin";
133
- var LOCALHOST_REGEX = /^http:\/\/localhost:\d+$/;
134
- function envExtraOrigins() {
135
- const raw = process.env.EXTRA_ALLOWED_ORIGINS;
136
- if (!raw) return [];
137
- return raw.split(",").map((s) => s.trim()).filter(Boolean);
138
- }
139
- function validateRedirectOrigin(origin, options = {}) {
140
- if (!origin) return null;
141
- const clientUrl = options.clientUrl ?? process.env.CLIENT_URL;
142
- let parsedOrigin;
143
- try {
144
- parsedOrigin = new URL(origin);
145
- } catch {
146
- return null;
147
- }
148
- const cleanOrigin = parsedOrigin.origin;
149
- if (clientUrl && cleanOrigin === clientUrl) {
150
- return cleanOrigin;
151
- }
152
- const extra = options.extraAllowedOrigins ?? envExtraOrigins();
153
- if (extra.includes(cleanOrigin)) {
154
- return cleanOrigin;
155
- }
156
- if (options.allowedPatterns?.some((pattern) => pattern.test(cleanOrigin))) {
157
- return cleanOrigin;
158
- }
159
- if ((options.allowLocalhostInDev ?? true) && process.env.NODE_ENV !== "production" && LOCALHOST_REGEX.test(cleanOrigin)) {
160
- return cleanOrigin;
161
- }
162
- return null;
143
+ // src/server/auth/devSignIns.ts
144
+ var DEVELOPMENT_ENVS = /* @__PURE__ */ new Set(["development", "test"]);
145
+ function developmentSignInsAllowed() {
146
+ const env = process.env.NODE_ENV;
147
+ return env !== void 0 && DEVELOPMENT_ENVS.has(env);
148
+ }
149
+ function nodeEnvLabel() {
150
+ const env = process.env.NODE_ENV;
151
+ return env === void 0 ? "unset" : JSON.stringify(env);
163
152
  }
164
153
 
165
154
  // src/server/auth/mock.ts
@@ -168,7 +157,7 @@ var CODE_TTL_MS = 5 * 60 * 1e3;
168
157
  var TOKEN_TTL_MS = 60 * 60 * 1e3;
169
158
  var DEV_PRIVATE_ORIGIN_REGEX = /^http:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0|10\.\d{1,3}\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}):\d+$/;
170
159
  function isMockOAuthEnabled() {
171
- return process.env.ENABLE_MOCK_OAUTH === "true" && process.env.NODE_ENV !== "production";
160
+ return process.env.ENABLE_MOCK_OAUTH === "true" && developmentSignInsAllowed();
172
161
  }
173
162
  function createMockOAuthProvider(apiBaseUrl, options = {}) {
174
163
  const prefix = options.pathPrefix ?? DEFAULT_MOCK_PATH_PREFIX;
@@ -269,7 +258,7 @@ function sweep(store) {
269
258
  }
270
259
  }
271
260
  function guard(res) {
272
- if (process.env.NODE_ENV === "production") {
261
+ if (!developmentSignInsAllowed()) {
273
262
  res.status(404).json({ error: "Not found" });
274
263
  return false;
275
264
  }
@@ -356,7 +345,9 @@ function registerMockOAuthProvider(router, options) {
356
345
  const logger = options.logger ?? consoleLogger;
357
346
  if (!isMockOAuthEnabled()) {
358
347
  if (process.env.ENABLE_MOCK_OAUTH === "true") {
359
- logger.error("Mock OAuth is enabled but NODE_ENV is production \u2014 refusing to mount routes");
348
+ logger.error(
349
+ `Mock OAuth is enabled but NODE_ENV is ${nodeEnvLabel()}: the mock runs only when NODE_ENV is development or test, so its routes are not mounted; set NODE_ENV=development to use it`
350
+ );
360
351
  }
361
352
  return false;
362
353
  }
@@ -370,7 +361,9 @@ function registerMockOAuthProvider(router, options) {
370
361
  router.get(`${endpoints.prefix}/authorize`, authorizeHandler(endpoints));
371
362
  router.post(`${endpoints.prefix}/token`, tokenHandler(endpoints));
372
363
  router.get(`${endpoints.prefix}/userinfo`, userinfoHandler(endpoints));
373
- logger.info(`Mock OAuth provider mounted at ${endpoints.prefix} (development only)`);
364
+ logger.warn(
365
+ `Mock OAuth provider mounted at ${endpoints.prefix}: anyone who reaches it signs in as any user it lists (NODE_ENV=${process.env.NODE_ENV ?? ""}; development and tests only)`
366
+ );
374
367
  return true;
375
368
  }
376
369
 
@@ -401,6 +394,14 @@ function sendJson(res, status, body) {
401
394
  function refuse(res, code, message) {
402
395
  sendJson(res, httpStatus(code), { error: code, message });
403
396
  }
397
+ function failRoute(logger, req, res, error) {
398
+ logger.error("An auth route failed", {
399
+ category: "quickdraw.auth",
400
+ path: pathOf(req),
401
+ error: errorText(error)
402
+ });
403
+ refuse(res, "INTERNAL", INTERNAL_MESSAGE);
404
+ }
404
405
  function redirect(res, location) {
405
406
  noStore(res, 302);
406
407
  res.setHeader("location", location);
@@ -411,67 +412,8 @@ function noContent(res) {
411
412
  res.end();
412
413
  }
413
414
 
414
- // src/server/auth/routes/origins.ts
415
- function exactOrigin(entry, owner) {
416
- let url;
417
- try {
418
- url = typeof entry === "string" ? new URL(entry) : void 0;
419
- } catch {
420
- url = void 0;
421
- }
422
- const bare = url !== void 0 && (url.protocol === "https:" || url.protocol === "http:") && url.username === "" && url.password === "" && url.pathname === "/" && url.search === "" && url.hash === "";
423
- if (url === void 0 || !bare) {
424
- throw new TypeError(
425
- `${owner}: allowedOrigins entries are origins such as "https://app.example.com" or anchored patterns; got ${String(entry)}`
426
- );
427
- }
428
- return url.origin;
429
- }
430
- function anchoredPattern(pattern, owner) {
431
- const { source } = pattern;
432
- const anchored = source.startsWith("^") && source.endsWith("$") && !source.endsWith("\\$");
433
- if (!anchored || pattern.global || pattern.sticky) {
434
- throw new TypeError(
435
- `${owner}: an allowedOrigins pattern must match whole origins, anchored with ^ and $ and without the g or y flag; got ${String(pattern)}`
436
- );
437
- }
438
- return new RegExp(`^(?:${source})$`, pattern.flags);
439
- }
440
- function originAllowlist(allowedOrigins, owner, allowEmpty = false) {
441
- if (!Array.isArray(allowedOrigins) || allowedOrigins.length === 0 && !allowEmpty) {
442
- throw new TypeError(`${owner}: allowedOrigins must list the web app's origins`);
443
- }
444
- const exact = [];
445
- const patterns = [];
446
- for (const entry of allowedOrigins) {
447
- if (entry instanceof RegExp) {
448
- patterns.push(anchoredPattern(entry, owner));
449
- } else {
450
- exact.push(exactOrigin(entry, owner));
451
- }
452
- }
453
- const options = {
454
- // An empty client URL, not undefined: undefined falls back to process.env.CLIENT_URL.
455
- clientUrl: "",
456
- extraAllowedOrigins: exact,
457
- allowedPatterns: patterns,
458
- allowLocalhostInDev: false
459
- };
460
- return Object.freeze({
461
- allowed: (value) => typeof value === "string" && value !== "" ? validateRedirectOrigin(value, options) : null,
462
- fallback: exact[0]
463
- });
464
- }
465
- var ROUTE_ORIGINS = /* @__PURE__ */ new WeakMap();
466
- function rememberRouteOrigins(sessions, origins) {
467
- ROUTE_ORIGINS.set(sessions, origins);
468
- }
469
- function routeOriginsOf(sessions) {
470
- return ROUTE_ORIGINS.get(sessions);
471
- }
472
-
473
415
  // src/server/auth/routes/state.ts
474
- import { randomBytes as randomBytes2, timingSafeEqual } from "crypto";
416
+ import { createHmac, randomBytes as randomBytes2, timingSafeEqual } from "crypto";
475
417
  var OAUTH_STATE_COOKIE = "qd_oauth";
476
418
  var HOST_OAUTH_STATE_COOKIE = "__Host-qd_oauth";
477
419
  var OAUTH_STATE_TTL_MS = 10 * 60 * 1e3;
@@ -479,16 +421,30 @@ var MAX_REDEEMED = 1e4;
479
421
  function newState() {
480
422
  return randomBytes2(32).toString("base64url");
481
423
  }
482
- function encodePending(pending) {
483
- return Buffer.from(JSON.stringify(pending), "utf8").toString("base64url");
424
+ function oauthStateKey(jwtSecret) {
425
+ return createHmac("sha256", jwtSecret).update("quickdraw:oauth-state").digest();
426
+ }
427
+ function macOf(payload, key) {
428
+ return createHmac("sha256", key).update(payload).digest();
429
+ }
430
+ function encodePending(pending, key) {
431
+ const payload = Buffer.from(JSON.stringify(pending), "utf8").toString("base64url");
432
+ return `${payload}.${macOf(payload, key).toString("base64url")}`;
484
433
  }
485
- function decodePending(raw) {
486
- if (raw === void 0 || raw === "") {
434
+ function decodePending(raw, key) {
435
+ const dot = raw === void 0 ? -1 : raw.lastIndexOf(".");
436
+ if (raw === void 0 || dot <= 0) {
437
+ return null;
438
+ }
439
+ const payload = raw.slice(0, dot);
440
+ const mac = Buffer.from(raw.slice(dot + 1), "base64url");
441
+ const expected = macOf(payload, key);
442
+ if (mac.length !== expected.length || !timingSafeEqual(mac, expected)) {
487
443
  return null;
488
444
  }
489
445
  let value;
490
446
  try {
491
- value = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
447
+ value = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
492
448
  } catch {
493
449
  return null;
494
450
  }
@@ -564,7 +520,7 @@ async function issueSession(keys, userId, meta, ttlMs = DEFAULT_SESSION_TTL_MS)
564
520
  }
565
521
  async function liveSession(keys, token) {
566
522
  checkSessionKeys(keys, "liveSession");
567
- const payload = await verifyJWT(token, keys.jwtSecret);
523
+ const payload = await readVerifiedJWT(token, keys.jwtSecret);
568
524
  if (payload === null || typeof payload.userId !== "string" || payload.userId === "" || payload.sid === void 0) {
569
525
  return null;
570
526
  }
@@ -641,9 +597,9 @@ function warnOnCookieDomain(cookie, logger) {
641
597
  if (cookie.name !== void 0 || cookie.domain !== void 0 === transportsSeeDomain) {
642
598
  return;
643
599
  }
644
- const why = cookie.domain === void 0 ? 'cookie.domain is "" while COOKIE_DOMAIN is set, so over HTTPS the routes set __Host-session where socketAuth and the HTTP transport read "session" first' : 'cookie.domain is set and COOKIE_DOMAIN is not, so the routes set "session" on every request, which socketAuth and the HTTP transport read over HTTPS only under that name';
600
+ const why = cookie.domain === void 0 ? 'cookie.domain is "" while COOKIE_DOMAIN is set, so over HTTPS the routes set __Host-session, but socketAuth and the HTTP transport also take a "session" cookie there, which any site under COOKIE_DOMAIN can set for a browser that holds no __Host-session. Unset COOKIE_DOMAIN' : `cookie.domain is set and COOKIE_DOMAIN is not, so the routes set "session" on every request, which socketAuth and the HTTP transport read over HTTPS only under that name. Set COOKIE_DOMAIN to the cookie's domain instead`;
645
601
  logger.warn(
646
- `${OWNER}: ${why}. Set COOKIE_DOMAIN to the cookie's domain instead, or name the cookie in all three places: cookie.name, socketAuth's cookieName and createServer's http.cookieName.`,
602
+ `${OWNER}: ${why}, or name the cookie in all three places: cookie.name, socketAuth's cookieName and createServer's http.cookieName.`,
647
603
  { category: "quickdraw.auth" }
648
604
  );
649
605
  }
@@ -704,8 +660,9 @@ function routeSettings(options) {
704
660
  const cookie = cookieOf(options.cookie);
705
661
  const logger = options.logger ?? consoleLogger;
706
662
  const publicUrl = publicUrlOf(options.publicUrl);
663
+ const keys = checkSessionKeys(options, OWNER);
707
664
  const settings = Object.freeze({
708
- keys: checkSessionKeys(options, OWNER),
665
+ keys,
709
666
  origins: originAllowlist(options.allowedOrigins, OWNER),
710
667
  publicUrl,
711
668
  basePath: basePathOf(options.basePath),
@@ -716,6 +673,7 @@ function routeSettings(options) {
716
673
  onRevoke: options.onRevoke,
717
674
  logger,
718
675
  redeemed: redeemedStates(),
676
+ stateKey: oauthStateKey(keys.jwtSecret),
719
677
  watchHost: hostWatcher(publicUrl, logger)
720
678
  });
721
679
  warnOnCookieDomain(cookie, logger);
@@ -772,16 +730,25 @@ function setSession(res, settings, req, token, pageOrigin) {
772
730
  const from = fromPage(req, pageOrigin);
773
731
  const name = sessionCookieName(settings, from);
774
732
  res.cookie(name, token, sessionCookieSettings(settings, from, name, true));
733
+ if (settings.cookie.name === void 0) {
734
+ clearStaleHostSession(res, req, name, settings.cookie.sameSite);
735
+ }
775
736
  }
776
737
  function clearSession(res, settings, req) {
777
738
  const name = sessionCookieName(settings, req);
778
739
  res.clearCookie(name, sessionCookieSettings(settings, req, name, false));
740
+ if (settings.cookie.name === void 0) {
741
+ clearStaleHostSession(res, req, name, settings.cookie.sameSite);
742
+ }
743
+ }
744
+ function stateSecure(settings, req) {
745
+ return secureFor(settings, req) || settings.publicUrl.startsWith("https:");
779
746
  }
780
747
  function stateCookieName(settings, req) {
781
- return secureFor(settings, req) ? HOST_OAUTH_STATE_COOKIE : OAUTH_STATE_COOKIE;
748
+ return stateSecure(settings, req) ? HOST_OAUTH_STATE_COOKIE : OAUTH_STATE_COOKIE;
782
749
  }
783
750
  function stateCookieOf(settings, req, live = false) {
784
- const secure = secureFor(settings, req);
751
+ const secure = stateSecure(settings, req);
785
752
  return {
786
753
  httpOnly: true,
787
754
  secure,
@@ -800,6 +767,151 @@ function issueFor(settings, userId, provider, req) {
800
767
  return issueSession(settings.keys, userId, meta, settings.cookie.ttlMs);
801
768
  }
802
769
 
770
+ // src/server/auth/routes/socketAuth.ts
771
+ function handshakeOf(request) {
772
+ const { handshake } = request.socket;
773
+ return { headers: request.headers, secure: handshake?.secure === true };
774
+ }
775
+ function credentialOf(request, naming) {
776
+ if (request.transport === "http") {
777
+ const { sessionCookie } = request;
778
+ if (typeof sessionCookie === "string" && sessionCookie !== "") {
779
+ return { token: sessionCookie, checkOrigin: true };
780
+ }
781
+ }
782
+ const { token } = request.auth;
783
+ if (typeof token === "string" && token !== "") {
784
+ return { token, checkOrigin: request.transport === "http" && request.credential === "cookie" };
785
+ }
786
+ if (request.transport === "http") {
787
+ return null;
788
+ }
789
+ const names = sessionCookieNamesFor(handshakeOf(request), naming);
790
+ const cookie = cookieToken(cookiesOf({ headers: request.headers }), names);
791
+ return cookie === null ? null : { token: cookie, checkOrigin: true };
792
+ }
793
+ function originAccepted(headers, origins, allowMissing) {
794
+ const { origin } = headers;
795
+ if (origin !== void 0) {
796
+ return origins.allowed(origin) !== null;
797
+ }
798
+ return allowMissing || headers["sec-fetch-site"] === "same-origin";
799
+ }
800
+ function httpOriginAccepted(headers, origins) {
801
+ const { origin } = headers;
802
+ if (origin !== void 0) {
803
+ return origins.allowed(origin) !== null;
804
+ }
805
+ const site = headers["sec-fetch-site"];
806
+ return site === void 0 || site === "same-origin";
807
+ }
808
+ var compiled = /* @__PURE__ */ new WeakMap();
809
+ function cookieOriginAllowed(request, allowedOrigins, options = {}) {
810
+ let origins = compiled.get(allowedOrigins);
811
+ if (origins === void 0) {
812
+ origins = originAllowlist(allowedOrigins, "cookieOriginAllowed", true);
813
+ compiled.set(allowedOrigins, origins);
814
+ }
815
+ return request.transport === "socket" ? originAccepted(request.headers, origins, options.allowMissingOrigin === true) : httpOriginAccepted(request.headers, origins);
816
+ }
817
+ function httpCookieOriginAllowed(headers, origins) {
818
+ return httpOriginAccepted(headers, origins);
819
+ }
820
+ var COOKIE_REFUSED = "This page's origin may not use the session cookie; send it from an allowed origin or use a bearer token";
821
+ function checkCookieOrigin(request, origins, allowMissing) {
822
+ if (request.transport === "http") {
823
+ if (!httpOriginAccepted(request.headers, origins)) {
824
+ throw new QuickdrawError("FORBIDDEN", COOKIE_REFUSED);
825
+ }
826
+ return;
827
+ }
828
+ if (!originAccepted(request.headers, origins, allowMissing)) {
829
+ throw refused("This page's origin may not use the session cookie on a socket");
830
+ }
831
+ }
832
+ function refused(message) {
833
+ return new QuickdrawError("UNAUTHENTICATED", message);
834
+ }
835
+ function checkDevCredentials(devCredentials) {
836
+ if (devCredentials === void 0) {
837
+ return void 0;
838
+ }
839
+ if (typeof devCredentials !== "function") {
840
+ throw new TypeError("socketAuth: devCredentials must be a function of the user id");
841
+ }
842
+ if (!developmentSignInsAllowed()) {
843
+ throw new TypeError(
844
+ `socketAuth: devCredentials signs sockets in by a user id alone, so it runs only when NODE_ENV is development or test (NODE_ENV is ${nodeEnvLabel()}); set NODE_ENV=development to use it`
845
+ );
846
+ }
847
+ return devCredentials;
848
+ }
849
+ function devUserOf(request) {
850
+ const { token, userId } = request.auth;
851
+ const tokenless = token === void 0 || token === null || token === "";
852
+ return request.transport === "socket" && tokenless && typeof userId === "string" && userId !== "" ? userId : void 0;
853
+ }
854
+ async function devPrincipal(devCredentials, userId) {
855
+ if (!developmentSignInsAllowed()) {
856
+ throw refused("Development credentials are refused unless NODE_ENV is development or test");
857
+ }
858
+ const principal = await devCredentials(userId);
859
+ if (principal === null || principal === void 0) {
860
+ throw refused("No development user has that id");
861
+ }
862
+ if (principal.userId !== userId) {
863
+ throw new TypeError("socketAuth: devCredentials must return the principal of the user named");
864
+ }
865
+ return principal;
866
+ }
867
+ async function principalOfSession(session, loadPrincipal, owner) {
868
+ if (loadPrincipal === void 0) {
869
+ return { userId: session.userId, kind: "user" };
870
+ }
871
+ const principal = await loadPrincipal(session.userId, session);
872
+ if (principal === null || principal === void 0) {
873
+ throw refused("The session's user has no principal");
874
+ }
875
+ if (principal.userId !== session.userId) {
876
+ throw new TypeError(`${owner}: loadPrincipal must return the principal of the session's user`);
877
+ }
878
+ return principal;
879
+ }
880
+ function socketAuth(options) {
881
+ const keys = checkSessionKeys(options, "socketAuth");
882
+ const origins = originAllowlist(options.allowedOrigins, "socketAuth", true);
883
+ const naming = transportCookieNaming(options.cookieName);
884
+ const allowMissing = options.allowMissingOrigin === true;
885
+ const { loadPrincipal } = options;
886
+ if (loadPrincipal !== void 0 && typeof loadPrincipal !== "function") {
887
+ throw new TypeError("socketAuth: loadPrincipal must be a function");
888
+ }
889
+ const devCredentials = checkDevCredentials(options.devCredentials);
890
+ const authenticate = async (request) => {
891
+ const devUser = devCredentials === void 0 ? void 0 : devUserOf(request);
892
+ if (devCredentials !== void 0 && devUser !== void 0) {
893
+ return await devPrincipal(devCredentials, devUser);
894
+ }
895
+ const credential = credentialOf(request, naming);
896
+ if (credential === null) {
897
+ return null;
898
+ }
899
+ if (credential.checkOrigin) {
900
+ checkCookieOrigin(request, origins, allowMissing);
901
+ }
902
+ const session = await liveSession(keys, credential.token);
903
+ if (session === null) {
904
+ throw refused("The session is not valid");
905
+ }
906
+ if (request.transport === "socket") {
907
+ recordSocketSession(request.socket, session.id, session.expiresAt);
908
+ }
909
+ return await principalOfSession(session, loadPrincipal, "socketAuth");
910
+ };
911
+ markSocketAuth(authenticate, { devCredentials: devCredentials !== void 0 });
912
+ return authenticate;
913
+ }
914
+
803
915
  // src/server/auth/routes/guest.ts
804
916
  var GUEST_MAX_BODY_BYTES = 16384;
805
917
  function guest(options) {
@@ -832,7 +944,7 @@ async function createGuest(settings, provider, req, res) {
832
944
  }
833
945
  settings.logger.error("Creating a guest user failed", {
834
946
  category: "quickdraw.auth",
835
- error: error instanceof Error ? error.message : String(error)
947
+ error: errorText(error)
836
948
  });
837
949
  refuse(res, "INTERNAL", INTERNAL_MESSAGE);
838
950
  return null;
@@ -840,6 +952,10 @@ async function createGuest(settings, provider, req, res) {
840
952
  }
841
953
  function guestRoute(settings, provider) {
842
954
  return async (req, res) => {
955
+ if (!httpCookieOriginAllowed(req.headers, settings.origins)) {
956
+ refuse(res, "FORBIDDEN", COOKIE_REFUSED);
957
+ return;
958
+ }
843
959
  const user = await createGuest(settings, provider, req, res);
844
960
  if (user === null) {
845
961
  return;
@@ -880,7 +996,7 @@ async function loadLimiters(option) {
880
996
  if (option.signIn !== void 0 && option.session !== void 0 && option.providers !== void 0) {
881
997
  return option;
882
998
  }
883
- const presets = await import("../../rateLimit-ZMIZJUZF.js");
999
+ const presets = await import("../../rateLimit-5RKBFLUR.js");
884
1000
  return {
885
1001
  signIn: option.signIn ?? presets.createAuthLimiter({ max: SIGN_IN_LIMIT }),
886
1002
  session: option.session ?? presets.createAuthStatusLimiter(),
@@ -944,9 +1060,6 @@ function mockServes() {
944
1060
 
945
1061
  // src/server/auth/routes/oauth.ts
946
1062
  var CATEGORY = "quickdraw.auth";
947
- function messageOf(error) {
948
- return error instanceof Error ? error.message : String(error);
949
- }
950
1063
  function startRoute(settings, flow) {
951
1064
  return (req, res) => {
952
1065
  if (flow.enabled?.() === false) {
@@ -961,7 +1074,10 @@ function startRoute(settings, flow) {
961
1074
  }
962
1075
  const state = newState();
963
1076
  const location = flow.authorizeUrl(state, redirectUriOf(settings, flow.id));
964
- const pending = encodePending({ state, provider: flow.id, origin, issuedAt: Date.now() });
1077
+ const pending = encodePending(
1078
+ { state, provider: flow.id, origin, issuedAt: Date.now() },
1079
+ settings.stateKey
1080
+ );
965
1081
  res.cookie(stateCookieName(settings, req), pending, stateCookieOf(settings, req, true));
966
1082
  redirect(res, location);
967
1083
  };
@@ -974,7 +1090,7 @@ async function userFor(settings, flow, code) {
974
1090
  settings.logger.warn("A sign-in's code exchange failed", {
975
1091
  category: CATEGORY,
976
1092
  provider: flow.id,
977
- error: messageOf(error)
1093
+ error: errorText(error)
978
1094
  });
979
1095
  return { error: "failed" };
980
1096
  }
@@ -989,7 +1105,7 @@ async function userFor(settings, flow, code) {
989
1105
  settings.logger.error("onLogin failed", {
990
1106
  category: CATEGORY,
991
1107
  provider: flow.id,
992
- error: messageOf(error)
1108
+ error: errorText(error)
993
1109
  });
994
1110
  return { error: "failed" };
995
1111
  }
@@ -1012,7 +1128,7 @@ async function complete(settings, flow, req, res, origin) {
1012
1128
  } catch (error) {
1013
1129
  settings.logger.error("Creating a session failed", {
1014
1130
  category: CATEGORY,
1015
- error: messageOf(error)
1131
+ error: errorText(error)
1016
1132
  });
1017
1133
  redirect(res, landingOf(settings, origin, "failed"));
1018
1134
  return;
@@ -1028,7 +1144,7 @@ function callbackRoute(settings, flow) {
1028
1144
  return;
1029
1145
  }
1030
1146
  const name = stateCookieName(settings, req);
1031
- const pending = decodePending(cookiesOf(req)[name]);
1147
+ const pending = decodePending(cookiesOf(req)[name], settings.stateKey);
1032
1148
  res.clearCookie(name, stateCookieOf(settings, req));
1033
1149
  if (pending === null) {
1034
1150
  const { fallback } = settings.origins;
@@ -1060,13 +1176,24 @@ function callbackRoute(settings, flow) {
1060
1176
 
1061
1177
  // src/server/auth/routes/session.ts
1062
1178
  var NOT_SIGNED_IN = "Not signed in";
1063
- function sessionOf(settings, req) {
1064
- const token = tokenOf(req, sessionCookieNaming(settings));
1179
+ function tokenFor(settings, req, res) {
1180
+ const credential = httpCredentialOf(req, sessionCookieNaming(settings));
1181
+ if (credential?.from === "cookie" && !httpCookieOriginAllowed(req.headers, settings.origins)) {
1182
+ refuse(res, "FORBIDDEN", COOKIE_REFUSED);
1183
+ return void 0;
1184
+ }
1185
+ return credential?.token ?? null;
1186
+ }
1187
+ function sessionOf(settings, token) {
1065
1188
  return token === null ? Promise.resolve(null) : liveSession(settings.keys, token);
1066
1189
  }
1067
1190
  function meRoute(settings) {
1068
1191
  return async (req, res) => {
1069
- const session = await sessionOf(settings, req);
1192
+ const token = tokenFor(settings, req, res);
1193
+ if (token === void 0) {
1194
+ return;
1195
+ }
1196
+ const session = await sessionOf(settings, token);
1070
1197
  if (session === null) {
1071
1198
  refuse(res, "UNAUTHENTICATED", NOT_SIGNED_IN);
1072
1199
  return;
@@ -1081,14 +1208,17 @@ async function revoked(settings, userId, sessionId) {
1081
1208
  settings.logger.error("onRevoke failed", {
1082
1209
  category: "quickdraw.auth",
1083
1210
  userId,
1084
- error: error instanceof Error ? error.message : String(error)
1211
+ error: errorText(error)
1085
1212
  });
1086
1213
  }
1087
1214
  }
1088
1215
  function logoutRoute(settings) {
1089
1216
  return async (req, res) => {
1090
- const token = tokenOf(req, sessionCookieNaming(settings));
1091
- const payload = token === null ? null : await verifyJWT(token, settings.keys.jwtSecret);
1217
+ const token = tokenFor(settings, req, res);
1218
+ if (token === void 0) {
1219
+ return;
1220
+ }
1221
+ const payload = token === null ? null : await readVerifiedJWT(token, settings.keys.jwtSecret);
1092
1222
  if (payload?.sid !== void 0) {
1093
1223
  await settings.keys.sessions.revoke(payload.sid);
1094
1224
  settings.logger.info("Signed out", { category: "quickdraw.auth", userId: payload.userId });
@@ -1100,7 +1230,11 @@ function logoutRoute(settings) {
1100
1230
  }
1101
1231
  function logoutAllRoute(settings) {
1102
1232
  return async (req, res) => {
1103
- const session = await sessionOf(settings, req);
1233
+ const token = tokenFor(settings, req, res);
1234
+ if (token === void 0) {
1235
+ return;
1236
+ }
1237
+ const session = await sessionOf(settings, token);
1104
1238
  clearSession(res, settings, req);
1105
1239
  if (session === null) {
1106
1240
  refuse(res, "UNAUTHENTICATED", NOT_SIGNED_IN);
@@ -1187,7 +1321,7 @@ function routeTable(settings, listed) {
1187
1321
  const mounted = providers.filter((provider) => addProvider(table, settings, provider));
1188
1322
  if (mounted.length === 0) {
1189
1323
  settings.logger.warn(
1190
- "createAuthRoutes: no provider can sign anyone in (the mock is mounted only while ENABLE_MOCK_OAUTH is set outside production): every sign-in route answers 404",
1324
+ "createAuthRoutes: no provider can sign anyone in (the mock is mounted only while ENABLE_MOCK_OAUTH is set and NODE_ENV is development or test): every sign-in route answers 404",
1191
1325
  { category: "quickdraw.auth" }
1192
1326
  );
1193
1327
  }
@@ -1216,12 +1350,7 @@ async function serve(route, req, res) {
1216
1350
  }
1217
1351
  function dispatch(settings, limiters, route, req, res) {
1218
1352
  const fail = (error) => {
1219
- settings.logger.error("An auth route failed", {
1220
- category: "quickdraw.auth",
1221
- path: pathOf(req),
1222
- error: error instanceof Error ? error.message : String(error)
1223
- });
1224
- refuse(res, "INTERNAL", INTERNAL_MESSAGE);
1353
+ failRoute(settings.logger, req, res, error);
1225
1354
  };
1226
1355
  if (limiters === null) {
1227
1356
  refuse(res, "INTERNAL", "The auth routes' rate limiters are unavailable");
@@ -1270,151 +1399,28 @@ function createAuthRoutes(options) {
1270
1399
  return Object.assign(routes, { providers: () => servedProviders(mounted) });
1271
1400
  }
1272
1401
 
1273
- // src/server/auth/routes/socketAuth.ts
1274
- function handshakeOf(request) {
1275
- const { handshake } = request.socket;
1276
- return { headers: request.headers, secure: handshake?.secure === true };
1277
- }
1278
- function credentialOf(request, naming) {
1279
- const { token } = request.auth;
1280
- if (typeof token === "string" && token !== "") {
1281
- return { token, checkOrigin: request.transport === "http" && request.credential === "cookie" };
1282
- }
1283
- if (request.transport === "http") {
1284
- return null;
1285
- }
1286
- const names = sessionCookieNamesFor(handshakeOf(request), naming);
1287
- const cookie = cookieToken(cookiesOf({ headers: request.headers }), names);
1288
- return cookie === null ? null : { token: cookie, checkOrigin: true };
1289
- }
1290
- function originAccepted(headers, origins, allowMissing) {
1291
- const { origin } = headers;
1292
- if (origin !== void 0) {
1293
- return origins.allowed(origin) !== null;
1294
- }
1295
- return allowMissing || headers["sec-fetch-site"] === "same-origin";
1296
- }
1297
- function httpOriginAccepted(headers, origins) {
1298
- const { origin } = headers;
1299
- if (origin !== void 0) {
1300
- return origins.allowed(origin) !== null;
1301
- }
1302
- const site = headers["sec-fetch-site"];
1303
- return site === void 0 || site === "same-origin";
1304
- }
1305
- var compiled = /* @__PURE__ */ new WeakMap();
1306
- function cookieOriginAllowed(request, allowedOrigins, options = {}) {
1307
- let origins = compiled.get(allowedOrigins);
1308
- if (origins === void 0) {
1309
- origins = originAllowlist(allowedOrigins, "cookieOriginAllowed", true);
1310
- compiled.set(allowedOrigins, origins);
1311
- }
1312
- return request.transport === "socket" ? originAccepted(request.headers, origins, options.allowMissingOrigin === true) : httpOriginAccepted(request.headers, origins);
1313
- }
1314
- function httpCookieOriginAllowed(headers, origins) {
1315
- return httpOriginAccepted(headers, origins);
1316
- }
1317
- function checkCookieOrigin(request, origins, allowMissing) {
1318
- if (request.transport === "http") {
1319
- if (!httpOriginAccepted(request.headers, origins)) {
1320
- throw new QuickdrawError(
1321
- "FORBIDDEN",
1322
- "This page's origin may not use the session cookie; send it from an allowed origin or use a bearer token"
1323
- );
1324
- }
1325
- return;
1326
- }
1327
- if (!originAccepted(request.headers, origins, allowMissing)) {
1328
- throw refused("This page's origin may not use the session cookie on a socket");
1329
- }
1330
- }
1331
- function refused(message) {
1332
- return new QuickdrawError("UNAUTHENTICATED", message);
1333
- }
1334
- function production() {
1335
- return process.env.NODE_ENV === "production";
1336
- }
1337
- function checkDevCredentials(devCredentials) {
1338
- if (devCredentials === void 0) {
1339
- return void 0;
1340
- }
1341
- if (typeof devCredentials !== "function") {
1342
- throw new TypeError("socketAuth: devCredentials must be a function of the user id");
1343
- }
1344
- if (production()) {
1345
- throw new TypeError(
1346
- "socketAuth: devCredentials signs sockets in by a user id alone, so it cannot be used when NODE_ENV is production"
1347
- );
1348
- }
1349
- return devCredentials;
1350
- }
1351
- function devUserOf(request) {
1352
- const { token, userId } = request.auth;
1353
- const tokenless = token === void 0 || token === null || token === "";
1354
- return request.transport === "socket" && tokenless && typeof userId === "string" && userId !== "" ? userId : void 0;
1355
- }
1356
- async function devPrincipal(devCredentials, userId) {
1357
- if (production()) {
1358
- throw refused("Development credentials are refused in production");
1359
- }
1360
- const principal = await devCredentials(userId);
1361
- if (principal === null || principal === void 0) {
1362
- throw refused("No development user has that id");
1363
- }
1364
- if (principal.userId !== userId) {
1365
- throw new TypeError("socketAuth: devCredentials must return the principal of the user named");
1366
- }
1367
- return principal;
1368
- }
1369
- function socketAuth(options) {
1370
- const keys = checkSessionKeys(options, "socketAuth");
1371
- const origins = originAllowlist(options.allowedOrigins, "socketAuth", true);
1372
- const naming = transportCookieNaming(options.cookieName);
1373
- const allowMissing = options.allowMissingOrigin === true;
1402
+ // src/server/auth/routes/bearerAuth.ts
1403
+ function bearerAuth(options) {
1404
+ const keys = checkSessionKeys(options, "bearerAuth");
1374
1405
  const { loadPrincipal } = options;
1375
1406
  if (loadPrincipal !== void 0 && typeof loadPrincipal !== "function") {
1376
- throw new TypeError("socketAuth: loadPrincipal must be a function");
1407
+ throw new TypeError("bearerAuth: loadPrincipal must be a function");
1377
1408
  }
1378
- const devCredentials = checkDevCredentials(options.devCredentials);
1379
- return async (request) => {
1380
- const devUser = devCredentials === void 0 ? void 0 : devUserOf(request);
1381
- if (devCredentials !== void 0 && devUser !== void 0) {
1382
- return await devPrincipal(devCredentials, devUser);
1383
- }
1384
- const credential = credentialOf(request, naming);
1385
- if (credential === null) {
1409
+ return async (token) => {
1410
+ if (typeof token !== "string" || token === "") {
1386
1411
  return null;
1387
1412
  }
1388
- if (credential.checkOrigin) {
1389
- checkCookieOrigin(request, origins, allowMissing);
1390
- }
1391
- const session = await liveSession(keys, credential.token);
1413
+ const session = await liveSession(keys, token);
1392
1414
  if (session === null) {
1393
- throw refused("The session is not valid");
1394
- }
1395
- if (request.transport === "socket") {
1396
- recordSocketSession(request.socket, session.id);
1397
- }
1398
- if (loadPrincipal === void 0) {
1399
- return { userId: session.userId, kind: "user" };
1415
+ throw new QuickdrawError("UNAUTHENTICATED", "The session is not valid");
1400
1416
  }
1401
- const principal = await loadPrincipal(session.userId, session);
1402
- if (principal === null || principal === void 0) {
1403
- throw refused("The session's user has no principal");
1404
- }
1405
- if (principal.userId !== session.userId) {
1406
- throw new TypeError(
1407
- "socketAuth: loadPrincipal must return the principal of the session's user"
1408
- );
1409
- }
1410
- return principal;
1417
+ return await principalOfSession(session, loadPrincipal, "bearerAuth");
1411
1418
  };
1412
1419
  }
1413
1420
 
1414
1421
  // src/server/auth/routes/requireSession.ts
1415
1422
  var SESSIONS = /* @__PURE__ */ new WeakMap();
1416
1423
  var NO_ORIGINS = originAllowlist([], "requireSession", true);
1417
- var COOKIE_REFUSED = "This page's origin may not use the session cookie; send it from an allowed origin or use a bearer token";
1418
1424
  var NO_LIST = "requireSession has no origin list, so no page may use the session cookie: pass it the sessions object createAuthRoutes was given (the same store object: a second store over the same table is another), or pass allowedOrigins";
1419
1425
  function requireSession(keys, options = {}) {
1420
1426
  checkSessionKeys(keys, "requireSession");
@@ -1625,6 +1631,7 @@ export {
1625
1631
  OAUTH_STATE_COOKIE,
1626
1632
  OAUTH_STATE_TTL_MS,
1627
1633
  SESSION_COOKIE,
1634
+ bearerAuth,
1628
1635
  clearSessionCookie,
1629
1636
  cookieOriginAllowed,
1630
1637
  createAuthRoutes,