@spfn/auth 0.3.0-beta.15 → 0.3.0-beta.17

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/server.js CHANGED
@@ -10641,6 +10641,9 @@ async function changePasswordService(params) {
10641
10641
  import { env as env9 } from "@spfn/auth/config";
10642
10642
  import { InvalidSignupLinkError, InvalidSignupSetupSessionError } from "@spfn/auth/errors";
10643
10643
  init_repositories();
10644
+
10645
+ // src/lib/return-path.ts
10646
+ var URL_STRIPPED_CHARACTER = /[\t\n\r]/;
10644
10647
  function isSafeReturnPath(returnPath) {
10645
10648
  if (!returnPath.startsWith("/")) {
10646
10649
  return false;
@@ -10648,11 +10651,13 @@ function isSafeReturnPath(returnPath) {
10648
10651
  if (returnPath.startsWith("//") || returnPath.includes("\\")) {
10649
10652
  return false;
10650
10653
  }
10651
- if (returnPath.includes("..")) {
10654
+ if (returnPath.includes("..") || URL_STRIPPED_CHARACTER.test(returnPath)) {
10652
10655
  return false;
10653
10656
  }
10654
10657
  return !/^\/[^/?#]*:/.test(returnPath);
10655
10658
  }
10659
+
10660
+ // src/server/services/signup-link.service.ts
10656
10661
  async function requestSignupLinkService(params) {
10657
10662
  const email = params.email.trim();
10658
10663
  const returnPath = params.returnPath;
@@ -13070,7 +13075,11 @@ async function oauthCallbackService(params) {
13070
13075
  const redirectUrl = buildRedirectUrl(callbackUrl, {
13071
13076
  userId: String(userId),
13072
13077
  keyId: stateData.keyId,
13073
- returnUrl: stateData.returnUrl,
13078
+ // Defence in depth: the state is sealed, so this value was already checked
13079
+ // where it was sealed. Checking it again costs one comparison and keeps a
13080
+ // destination that leaves the app out of the callback URL no matter which
13081
+ // seam sealed it.
13082
+ returnUrl: isSafeReturnPath(stateData.returnUrl) ? stateData.returnUrl : "/",
13074
13083
  isNewUser: String(isNewUser)
13075
13084
  });
13076
13085
  const user = await usersRepository.findById(userId);
@@ -16032,7 +16041,7 @@ var userRouter = defineRouter3({
16032
16041
  // src/server/routes/oauth/index.ts
16033
16042
  init_esm();
16034
16043
 
16035
- // ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/utils/url.js
16044
+ // ../../node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/url.js
16036
16045
  var tryDecode = (str, decoder) => {
16037
16046
  try {
16038
16047
  return decoder(str);
@@ -16049,7 +16058,7 @@ var tryDecode = (str, decoder) => {
16049
16058
  var tryDecodeURIComponent = (str) => str.indexOf("%") !== -1 ? tryDecode(str, decodeURIComponent_) : str;
16050
16059
  var decodeURIComponent_ = decodeURIComponent;
16051
16060
 
16052
- // ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/utils/cookie.js
16061
+ // ../../node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/utils/cookie.js
16053
16062
  var validCookieNameRegEx = /^[\w!#$%&'*.^`|~+-]+$/;
16054
16063
  var relaxedCookieNameRegEx = /^[!#-:<>-[\]-~]+$/;
16055
16064
  var validCookieValueRegEx = /^[ !#-:<-[\]-~]*$/;
@@ -16171,7 +16180,7 @@ var serialize = (name, value, opt) => {
16171
16180
  return _serialize(name, value, opt);
16172
16181
  };
16173
16182
 
16174
- // ../../node_modules/.pnpm/hono@4.13.0/node_modules/hono/dist/helper/cookie/index.js
16183
+ // ../../node_modules/.pnpm/hono@4.13.7/node_modules/hono/dist/helper/cookie/index.js
16175
16184
  var getCookie = (c, key, prefix) => {
16176
16185
  const cookie = c.req.raw.headers.get("Cookie");
16177
16186
  if (typeof key === "string") {
@@ -16312,6 +16321,9 @@ var oauthStart = route6.post("/_auth/oauth/start").input({
16312
16321
  })
16313
16322
  }).use([rateLimitPolicy6("oauth-start", { limit: 20, windowMs: 6e4 })]).skip(["auth"]).handler(async (c) => {
16314
16323
  const { body } = await c.data();
16324
+ if (!isSafeReturnPath(body.returnUrl)) {
16325
+ throw new ValidationError13({ message: "returnUrl must be a relative path within the app" });
16326
+ }
16315
16327
  const nonce = generateOAuthNonce();
16316
16328
  setCookie(c.raw, COOKIE_NAMES.OAUTH_CSRF, nonce, {
16317
16329
  httpOnly: true,
@@ -16360,6 +16372,9 @@ var oauthFinalize = route6.post("/_auth/oauth/finalize").input({
16360
16372
  })
16361
16373
  }).use([rateLimitPolicy6("oauth-start", { limit: 20, windowMs: 6e4 })]).skip(["auth"]).handler(async (c) => {
16362
16374
  const { body } = await c.data();
16375
+ if (body.returnUrl && !isSafeReturnPath(body.returnUrl)) {
16376
+ throw new ValidationError13({ message: "returnUrl must be a relative path within the app" });
16377
+ }
16363
16378
  return {
16364
16379
  success: true,
16365
16380
  userId: body.userId,