{"version":3,"file":"url-DaPDWryr.mjs","names":["frontendApiRedirectPathsWithUserInput: string[]","frontendApiRedirectPathsNoUserInput: string[]","origins: string[]"],"sources":["../../src/internal/clerk-js/url.ts"],"sourcesContent":["import { globs } from '../../globs';\nimport { createDevOrStagingUrlCache } from '../../keys';\nimport { logger } from '../../logger';\nimport type { SignUpResource } from '../../types';\nimport { camelToSnake } from '../../underscore';\nimport { isCurrentDevAccountPortalOrigin, isLegacyDevAccountPortalOrigin } from '../../url';\nimport { joinPaths } from './path';\nimport { getQueryParams } from './querystring';\n\ndeclare global {\n  export interface Window {\n    tldts: {\n      getDomain(hostname: string, { allowPrivateDomains }: { allowPrivateDomains: boolean }): string;\n    };\n  }\n}\n\n// This is used as a dummy base when we need to invoke \"new URL()\" but we don't care about the URL origin.\nconst DUMMY_URL_BASE = 'http://clerk-dummy';\n\nconst BANNED_URI_PROTOCOLS = ['javascript:'] as const;\n\n// Protocols that are dangerous specifically for href attributes in links\nconst BANNED_HREF_PROTOCOLS = ['javascript:', 'data:', 'vbscript:', 'blob:'] as const;\n\nconst { isDevOrStagingUrl } = createDevOrStagingUrlCache();\nexport { isDevOrStagingUrl };\nconst accountPortalCache = new Map<string, boolean>();\n\nexport function isDevAccountPortalOrigin(hostname: string = window.location.hostname): boolean {\n  if (!hostname) {\n    return false;\n  }\n\n  let res = accountPortalCache.get(hostname);\n\n  if (res === undefined) {\n    res = isLegacyDevAccountPortalOrigin(hostname) || isCurrentDevAccountPortalOrigin(hostname);\n    accountPortalCache.set(hostname, res);\n  }\n\n  return res;\n}\n\nexport function getETLDPlusOneFromFrontendApi(frontendApi: string): string {\n  return frontendApi.replace('clerk.', '');\n}\n\ninterface BuildURLParams extends Partial<URL> {\n  base?: string;\n  hashPath?: string;\n  hashSearch?: string;\n  hashSearchParams?: URLSearchParams | Record<string, string> | Array<URLSearchParams | Record<string, string>>;\n}\n\ninterface BuildURLOptions<T> {\n  skipOrigin?: boolean;\n  stringify?: T;\n}\n\n/**\n *\n * buildURL(params: URLParams, options: BuildURLOptions): string\n *\n * Builds a URL safely by using the native URL() constructor. It can\n * also build a secondary path and search URL that lives inside the hash\n * of the main URL. For example:\n *\n * https://foo.com/bar?qux=42#/hash-bar?hash-qux=42\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param params\n * @param options\n * @returns Returns the URL href\n */\nexport function buildURL<B extends boolean>(\n  params: BuildURLParams,\n  options?: BuildURLOptions<B>,\n): B extends true ? string : URL;\n\nexport function buildURL(params: BuildURLParams, options: BuildURLOptions<boolean> = {}): URL | string {\n  const { base, hashPath, hashSearch, searchParams, hashSearchParams, ...rest } = params;\n\n  let fallbackBase = '';\n  // This check is necessary for React native environments where window is undefined.\n  // TODO: Refactor all window and document usages in clerk-js and import them from\n  // a single file that will be mocked easily in React native environments.\n  if (typeof window !== 'undefined' && !!window.location) {\n    fallbackBase = window.location.href;\n  } else {\n    fallbackBase = 'http://react-native-fake-base-url';\n  }\n\n  const url = new URL(base || '', fallbackBase);\n\n  // Properly copy URLSearchParams\n  if (searchParams instanceof URLSearchParams) {\n    searchParams.forEach((value, key) => {\n      if (value !== null && value !== undefined) {\n        url.searchParams.set(camelToSnake(key), value);\n      }\n    });\n  }\n\n  Object.assign(url, rest);\n\n  // Treat that hash part of the main URL as if it's another URL with a pathname and a search.\n  // Another nested hash inside the top level hash (e.g. #my-hash#my-second-hash) is currently\n  // not supported as there is no use case for it yet.\n  if (hashPath || hashSearch || hashSearchParams) {\n    // Parse the hash to a URL object\n    const dummyUrlForHash = new URL(DUMMY_URL_BASE + url.hash.substring(1));\n\n    // Join the current hash path and with the provided one\n    dummyUrlForHash.pathname = joinPaths(dummyUrlForHash.pathname, hashPath || '');\n\n    // Merge search params from hashSearch string\n    const searchParamsFromHashSearchString = getQueryParams(hashSearch || '');\n    for (const [key, val] of Object.entries(searchParamsFromHashSearchString)) {\n      dummyUrlForHash.searchParams.append(key, val);\n    }\n\n    // Merge search params from the hashSearchParams object\n    if (hashSearchParams) {\n      const paramsArr = Array.isArray(hashSearchParams) ? hashSearchParams : [hashSearchParams];\n      for (const _params of paramsArr) {\n        if (!(_params instanceof URLSearchParams) && typeof _params !== 'object') {\n          continue;\n        }\n        const params = new URLSearchParams(_params);\n        params.forEach((value, key) => {\n          if (value !== null && value !== undefined) {\n            dummyUrlForHash.searchParams.set(camelToSnake(key), value);\n          }\n        });\n      }\n    }\n\n    // Keep just the pathname and the  search\n    const newHash = dummyUrlForHash.href.replace(DUMMY_URL_BASE, '');\n\n    // if the hash is `/`, it means that nothing new was added to the hash\n    // so we can skip assigning it to the hash of the main url\n    if (newHash !== '/') {\n      // Assign them to the hash of the main url\n      url.hash = newHash;\n    }\n  }\n\n  const { stringify, skipOrigin } = options;\n  if (stringify) {\n    return skipOrigin ? url.href.replace(url.origin, '') : url.href;\n  }\n  return url;\n}\n\nexport function toURL(url: string | URL): URL {\n  return new URL(url.toString(), window.location.origin);\n}\n\n/**\n *\n * stripOrigin(url: URL | string): string\n *\n * Strips the origin part of a URL and preserves path, search and hash is applicable\n *\n * References:\n * https://developer.mozilla.org/en-US/docs/Web/API/URL\n *\n * @param url\n * @returns Returns the URL href without the origin\n */\nexport function stripOrigin(url: URL | string): string {\n  // In non-browser environments `window.location.origin` might not be available\n  // if not polyfilled, so we can't construct a URL object with the `url` string\n  // note: in that case, we can't easily strip the origin, so we return the original string\n  if (typeof window.location === 'undefined' && typeof url === 'string') {\n    return url;\n  }\n\n  url = toURL(url);\n  return url.href.replace(url.origin, '');\n}\n\n/**\n * trimTrailingSlash(path: string): string\n *\n * Strips the trailing slashes from a string\n *\n * @returns Returns the string without trailing slashes\n *\n * @param path\n */\nexport const trimTrailingSlash = (path: string): string => {\n  return (path || '').replace(/\\/+$/, '');\n};\n\n/**\n * trimLeadingSlash(path: string): string\n *\n * Strips the leading slashes from a string\n *\n * @returns Returns the string without leading slashes\n *\n * @param path\n */\nexport const trimLeadingSlash = (path: string): string => {\n  return (path || '').replace(/^\\/+/, '');\n};\n\nexport const hasExternalAccountSignUpError = (signUp: SignUpResource): boolean => {\n  const { externalAccount } = signUp.verifications;\n  return !!externalAccount.error;\n};\n\nexport function getSearchParameterFromHash({\n  hash = window.location.hash,\n  paramName,\n}: {\n  hash?: string;\n  paramName: string;\n}) {\n  const h = hash.startsWith('#') ? hash.substring(1) : hash;\n  const dummyUrlForHash = new URL(h, DUMMY_URL_BASE);\n  return dummyUrlForHash.searchParams.get(paramName);\n}\n\nexport function isValidUrl(val: string | URL | undefined | null): boolean {\n  if (!val) {\n    return false;\n  }\n\n  try {\n    new URL(val as string);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nexport function relativeToAbsoluteUrl(url: string, origin: string | URL): URL {\n  try {\n    return new URL(url);\n  } catch {\n    return new URL(url, origin);\n  }\n}\n\n// Regular expression to detect disallowed patterns\nconst disallowedPatterns = [\n  /\\0/, // Null bytes\n  /^\\/\\//, // Protocol-relative\n  // eslint-disable-next-line no-control-regex\n  /[\\x00-\\x1F]/, // Control characters\n];\n\n/**\n * Check for potentially problematic URLs that could have been crafted to intentionally bypass the origin check. Note that the URLs passed to this\n * function are assumed to be from an \"allowed origin\", so we are not executing origin-specific checks here.\n */\nexport function isProblematicUrl(url: URL): boolean {\n  if (hasBannedProtocol(url)) {\n    return true;\n  }\n  // Check against disallowed patterns\n  for (const pattern of disallowedPatterns) {\n    if (pattern.test(url.pathname)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\nexport function isDataUri(val?: string): val is string {\n  if (!val || !isValidUrl(val)) {\n    return false;\n  }\n\n  return new URL(val).protocol === 'data:';\n}\n\n/**\n * Checks if a URL uses javascript: protocol.\n * This prevents some XSS attacks through javascript: URLs.\n *\n * IMPORTANT: This does not check for `data:` or other protocols which\n * are dangerous if used for links or setting the window location.\n *\n * @param val - The URL to check\n * @returns True if the URL contains a banned protocol, false otherwise\n */\nexport function hasBannedProtocol(val: string | URL) {\n  if (!isValidUrl(val)) {\n    return false;\n  }\n  const protocol = new URL(val).protocol;\n  return BANNED_URI_PROTOCOLS.some(bp => bp === protocol);\n}\n\n/**\n * Checks if a URL contains a banned protocol for href attributes in links.\n * This prevents some XSS attacks through javascript:, data:, vbscript:, and blob: URLs.\n *\n * @param val - The URL to check\n * @returns True if the URL contains a banned protocol, false otherwise\n */\nexport function hasBannedHrefProtocol(val: string | URL): boolean {\n  if (!isValidUrl(val)) {\n    return false;\n  }\n  const protocol = new URL(val).protocol;\n  return BANNED_HREF_PROTOCOLS.some(bp => bp === protocol);\n}\n\n/**\n * Sanitizes an href value by checking for dangerous protocols.\n * Returns null if the href contains a dangerous protocol, otherwise returns the original href.\n * This prevents some XSS attacks through javascript:, data:, vbscript:, and blob: URLs.\n *\n * @param href - The href value to sanitize\n * @returns The sanitized href or null if dangerous\n */\nexport function sanitizeHref(href: string | undefined | null): string | null {\n  if (!href || href.trim() === '') {\n    return null;\n  }\n\n  // For relative URLs (starting with / or # or ?), allow them through\n  if (href.startsWith('/') || href.startsWith('#') || href.startsWith('?')) {\n    return href;\n  }\n\n  // For relative URLs without leading slash, allow them through\n  if (!href.includes(':')) {\n    return href;\n  }\n\n  // Check if it's a valid URL with a dangerous protocol\n  try {\n    const url = new URL(href);\n    if (hasBannedHrefProtocol(url)) {\n      return null;\n    }\n    return href;\n  } catch {\n    // If URL parsing fails, it's likely a relative URL or malformed\n    // Allow relative URLs through, but be cautious with malformed ones\n    return href;\n  }\n}\n\nexport const hasUrlInFragment = (_url: URL | string) => {\n  return new URL(_url, DUMMY_URL_BASE).hash.startsWith('#/');\n};\n\n/**\n * Creates a new URL by merging a fragment-based URL, if found.\n * The result URL has the original and the fragment pathnames appended\n * and also includes all search params from both places.\n *\n * @example\n * ```ts\n * mergeFragmentIntoUrl('https://accounts.clerk.com/sign-in?user_param=hello#/verify/factor-one?redirect_url=/protected')\n * // Returns: 'https://accounts.clerk.com/sign-in/verify/factor-one?user_param=hello&redirect_url=/protected'\n * ```\n */\nexport const mergeFragmentIntoUrl = (_url: string | URL): URL => {\n  const url = new URL(_url);\n\n  if (!hasUrlInFragment(url)) {\n    return url;\n  }\n\n  const fragmentUrl = new URL(url.hash.replace('#/', '/'), url.href);\n  const mergedPathname = [url.pathname, fragmentUrl.pathname]\n    .map(s => s.split('/'))\n    .flat()\n    .filter(Boolean)\n    .join('/');\n\n  const mergedUrl = new URL(mergedPathname, url.origin);\n\n  url.searchParams.forEach((val, key) => {\n    mergedUrl.searchParams.set(key, val);\n  });\n\n  fragmentUrl.searchParams.forEach((val, key) => {\n    mergedUrl.searchParams.set(key, val);\n  });\n\n  return mergedUrl;\n};\n\nexport const pathFromFullPath = (fullPath: string) => {\n  return fullPath.replace(/CLERK-ROUTER\\/(.*?)\\//, '');\n};\n\nconst frontendApiRedirectPathsWithUserInput: string[] = [\n  '/oauth/authorize', // OAuth2 identify provider flow\n];\n\nconst frontendApiRedirectPathsNoUserInput: string[] = [\n  '/v1/verify', // magic links\n  '/v1/tickets/accept', // ticket flow\n  '/oauth/authorize-with-immediate-redirect', // OAuth 2 identity provider\n  '/oauth/end_session', // OIDC logout\n];\n\nexport function isRedirectForFAPIInitiatedFlow(frontendApi: string, redirectUrl: string): boolean {\n  const url = new URL(redirectUrl, DUMMY_URL_BASE);\n  const path = url.pathname;\n\n  const isValidFrontendRedirectPath =\n    frontendApiRedirectPathsWithUserInput.includes(path) || frontendApiRedirectPathsNoUserInput.includes(path);\n  return frontendApi === url.host && isValidFrontendRedirectPath;\n}\n\nexport function requiresUserInput(redirectUrl: string): boolean {\n  const url = new URL(redirectUrl, DUMMY_URL_BASE);\n  return frontendApiRedirectPathsWithUserInput.includes(url.pathname);\n}\n\nexport const isAllowedRedirect =\n  (allowedRedirectOrigins: Array<string | RegExp> | undefined, currentOrigin: string) => (_url: URL | string) => {\n    let url = _url;\n    if (typeof url === 'string') {\n      url = relativeToAbsoluteUrl(url, currentOrigin);\n    }\n\n    if (!allowedRedirectOrigins) {\n      return true;\n    }\n\n    const isSameOrigin = currentOrigin === url.origin;\n\n    const isAllowed =\n      !isProblematicUrl(url) &&\n      (isSameOrigin ||\n        allowedRedirectOrigins\n          .map(origin => (typeof origin === 'string' ? globs.toRegexp(trimTrailingSlash(origin)) : origin))\n          .some(origin => origin.test(trimTrailingSlash(url.origin))));\n\n    if (!isAllowed) {\n      logger.warnOnce(\n        `Clerk: Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`,\n      );\n    }\n    return isAllowed;\n  };\n\nexport function createAllowedRedirectOrigins(\n  allowedRedirectOrigins: Array<string | RegExp> | undefined,\n  frontendApi: string,\n  instanceType?: string,\n): (string | RegExp)[] | undefined {\n  if (Array.isArray(allowedRedirectOrigins) && !!allowedRedirectOrigins.length) {\n    return allowedRedirectOrigins;\n  }\n\n  const origins: string[] = [];\n  if (typeof window !== 'undefined' && !!window.location) {\n    origins.push(window.location.origin);\n  }\n\n  origins.push(`https://${getETLDPlusOneFromFrontendApi(frontendApi)}`);\n  origins.push(`https://*.${getETLDPlusOneFromFrontendApi(frontendApi)}`);\n\n  if (instanceType === 'development') {\n    origins.push(`https://${frontendApi}`);\n  }\n\n  return origins;\n}\n"],"mappings":"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"}