{"version":3,"file":"url.mjs","names":[],"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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"}