From 35cbdf956f32a2de0e84b301c64a13d2b52533b8 Mon Sep 17 00:00:00 2001 From: George Desipris Date: Fri, 28 Apr 2023 14:46:02 +0300 Subject: [PATCH 1/6] feat(clerk-js,shared): Validate query param redirect urls with allowedRedirectOrigins --- package-lock.json | 18 ++++++++++++++ packages/clerk-js/src/core/clerk.ts | 13 ++++++++++ .../clerk-js/src/utils/authPropHelpers.ts | 21 ++++++++++++---- packages/clerk-js/src/utils/url.ts | 24 +++++++++++++++++++ packages/shared/package.json | 4 ++++ packages/shared/src/utils/index.ts | 1 + packages/shared/src/utils/testGlob.ts | 6 +++++ packages/types/src/clerk.ts | 4 ++++ 8 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 packages/shared/src/utils/testGlob.ts diff --git a/package-lock.json b/package-lock.json index 332314e27eb..59408942329 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9165,6 +9165,12 @@ "@types/node": "*" } }, + "node_modules/@types/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-S0mIukll6fbF0tvrKic/jj+jI8SHoSvGU+Cs95b/jzZEnBYCbj+7aJtQ9yeABuK3xP1okwA3jEH9qIRayijnvQ==", + "dev": true + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -37880,12 +37886,16 @@ "name": "@clerk/shared", "version": "0.16.0-staging.0", "license": "ISC", + "dependencies": { + "glob-to-regexp": "^0.4.1" + }, "devDependencies": { "@clerk/types": "^3.37.0-staging.0", "@testing-library/dom": "8.19.0", "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "13.4.0", "@testing-library/user-event": "14.4.3", + "@types/glob-to-regexp": "^0.4.1", "@types/js-cookie": "3.0.2", "jest": "*", "jest-environment-jsdom": "*", @@ -42400,7 +42410,9 @@ "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "13.4.0", "@testing-library/user-event": "14.4.3", + "@types/glob-to-regexp": "^0.4.1", "@types/js-cookie": "3.0.2", + "glob-to-regexp": "^0.4.1", "jest": "*", "jest-environment-jsdom": "*", "js-cookie": "3.0.1", @@ -47638,6 +47650,12 @@ "@types/node": "*" } }, + "@types/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-S0mIukll6fbF0tvrKic/jj+jI8SHoSvGU+Cs95b/jzZEnBYCbj+7aJtQ9yeABuK3xP1okwA3jEH9qIRayijnvQ==", + "dev": true + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 52548d945ab..23a4e1bad69 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -168,6 +168,19 @@ export default class Clerk implements ClerkInterface { return false; } + get allowedRedirectOrigins(): string[] | undefined { + if (!this.#options.allowedRedirectOrigins) { + return undefined; + } + + const origins = [...(this.#options.allowedRedirectOrigins || [])]; + if (inBrowser()) { + //TODO: also push http(s)://*.etld+1 + origins.push(window.location.origin); + } + return origins; + } + get domain(): string { if (inBrowser()) { const strippedDomainString = stripScheme(handleValueOrFn(this.#domain, new URL(window.location.href))); diff --git a/packages/clerk-js/src/utils/authPropHelpers.ts b/packages/clerk-js/src/utils/authPropHelpers.ts index 10883c6dc8a..70cb4dbfaa2 100644 --- a/packages/clerk-js/src/utils/authPropHelpers.ts +++ b/packages/clerk-js/src/utils/authPropHelpers.ts @@ -3,7 +3,7 @@ import type { ClerkOptions, DisplayConfigResource } from '@clerk/types'; import type { ParsedQs } from 'qs'; import qs from 'qs'; -import { hasBannedProtocol, isValidUrl } from './index'; +import { getFirstAllowedRedirectAndWarn, hasBannedProtocol, isValidUrl } from './index'; type PickRedirectionUrlKey = 'afterSignUpUrl' | 'afterSignInUrl' | 'signInUrl' | 'signUpUrl'; @@ -12,6 +12,7 @@ type PickRedirectionOptions = { displayConfig?: DisplayConfigResource; options?: ClerkOptions; ctx?: any; + allowedRedirectOrigins?: string[]; }; /** @@ -29,15 +30,27 @@ type PickRedirectionOptions = { */ export const pickRedirectionProp = ( key: PickRedirectionUrlKey, - { ctx, queryParams, displayConfig, options }: PickRedirectionOptions, + { ctx, queryParams, displayConfig, options, allowedRedirectOrigins }: PickRedirectionOptions, accessRedirectUrl = true, ): string => { const snakeCaseField = camelToSnake(key); const queryParamValue = queryParams?.[snakeCaseField]; + const primaryQueryParamRedirectUrl = typeof queryParamValue === 'string' ? queryParamValue : null; + const secondaryQueryParamRedirectUrl = + accessRedirectUrl && typeof queryParams?.redirect_url === 'string' ? queryParams.redirect_url : null; + + let queryParamUrl: string | null | undefined = primaryQueryParamRedirectUrl || secondaryQueryParamRedirectUrl; + + if (allowedRedirectOrigins) { + queryParamUrl = getFirstAllowedRedirectAndWarn( + [primaryQueryParamRedirectUrl, secondaryQueryParamRedirectUrl].filter(i => i !== null) as string[], + allowedRedirectOrigins, + ); + } + const url = - (typeof queryParamValue === 'string' ? queryParamValue : null) || - (accessRedirectUrl && typeof queryParams?.redirect_url === 'string' ? queryParams?.redirect_url : null) || + queryParamUrl || ctx?.[key] || (accessRedirectUrl ? ctx?.redirectUrl : null) || options?.[key] || diff --git a/packages/clerk-js/src/utils/url.ts b/packages/clerk-js/src/utils/url.ts index 7ea00530d8b..7e2f0017128 100644 --- a/packages/clerk-js/src/utils/url.ts +++ b/packages/clerk-js/src/utils/url.ts @@ -1,3 +1,4 @@ +import { testGlob } from '@clerk/shared'; import { camelToSnake, createDevOrStagingUrlCache, isIPV4Address } from '@clerk/shared'; import type { SignUpResource } from '@clerk/types'; @@ -375,3 +376,26 @@ export function isRedirectForFAPIInitiatedFlow(frontendApi: string, redirectUrl: return frontendApi === url.host && frontendApiRedirectPaths.includes(path); } + +const isAllowedRedirect = (_url: string, allowedRedirectOrigins: string[]) => { + const url = new URL(_url, DUMMY_URL_BASE); + + //is relative url + if (url.origin === DUMMY_URL_BASE) { + return true; + } + + return allowedRedirectOrigins.some(allowedOrigin => testGlob(allowedOrigin, url.href)); +}; + +export const getFirstAllowedRedirectAndWarn = (urls: string[], allowedRedirectOrigins: string[]) => { + return urls.find(url => { + if (!isAllowedRedirect(url, allowedRedirectOrigins)) { + console.warn( + `Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`, + ); + return false; + } + return true; + }); +}; diff --git a/packages/shared/package.json b/packages/shared/package.json index 5da7a630c48..c2b57355eaf 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -24,6 +24,7 @@ "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "13.4.0", "@testing-library/user-event": "14.4.3", + "@types/glob-to-regexp": "^0.4.1", "@types/js-cookie": "3.0.2", "jest": "*", "jest-environment-jsdom": "*", @@ -41,5 +42,8 @@ "gitHead": "1b19a43b61f712756ab4d8c9ccbee6e8bddbe4ce", "publishConfig": { "access": "public" + }, + "dependencies": { + "glob-to-regexp": "^0.4.1" } } diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts index a6701783591..b0a7230025c 100644 --- a/packages/shared/src/utils/index.ts +++ b/packages/shared/src/utils/index.ts @@ -22,3 +22,4 @@ export * from './url'; export * from './workerTimers'; export * from './runWithExponentialBackOff'; export * from './isomorphicAtob'; +export * from './testGlob'; diff --git a/packages/shared/src/utils/testGlob.ts b/packages/shared/src/utils/testGlob.ts new file mode 100644 index 00000000000..c63b288dc69 --- /dev/null +++ b/packages/shared/src/utils/testGlob.ts @@ -0,0 +1,6 @@ +import globToRegexp from 'glob-to-regexp'; + +export const testGlob = (pattern: string, input: string) => { + const re = globToRegexp(pattern); + return re.test(input); +}; diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index 2342631c816..ff43b4476d6 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -75,6 +75,9 @@ export interface Clerk { /** Clerk Flag for satellite apps. */ isSatellite: boolean; + /** Allowed Redirect Origins */ + allowedRedirectOrigins: string[] | undefined; + instanceType?: InstanceType; /** Client handling most Clerk operations. */ @@ -494,6 +497,7 @@ export interface ClerkOptions { * @experimental */ experimental_enableClerkImages?: boolean; + allowedRedirectOrigins?: string[]; } export interface Resources { From db4afe8f922f42b491ff5a34f83d74edfb1c7680 Mon Sep 17 00:00:00 2001 From: George Desipris Date: Fri, 28 Apr 2023 15:07:26 +0300 Subject: [PATCH 2/6] feat(clerk-js): Add https://*.eltd+1 to the allowedRedirectOrigins default list fix(clerk-js): Fix allowedRedirectOrigins default patterns --- packages/clerk-js/src/core/clerk.ts | 5 ++- .../clerk-js/src/utils/__tests__/url.test.ts | 13 ++++++++ packages/clerk-js/src/utils/url.ts | 32 ++----------------- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 23a4e1bad69..12827be0a05 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -60,6 +60,7 @@ import { createPageLifecycle, errorThrower, getClerkQueryParam, + getETLDPlusOneFromFrontendApi, hasExternalAccountSignUpError, ignoreEventValue, inActiveBrowserTab, @@ -175,9 +176,11 @@ export default class Clerk implements ClerkInterface { const origins = [...(this.#options.allowedRedirectOrigins || [])]; if (inBrowser()) { - //TODO: also push http(s)://*.etld+1 origins.push(window.location.origin); + origins.push(window.location.origin + '/*'); } + origins.push(`https://*.${getETLDPlusOneFromFrontendApi(this.frontendApi)}`); + origins.push(`https://*.${getETLDPlusOneFromFrontendApi(this.frontendApi)}/*`); return origins; } diff --git a/packages/clerk-js/src/utils/__tests__/url.test.ts b/packages/clerk-js/src/utils/__tests__/url.test.ts index b64ace4c96f..d63cd2e6a3c 100644 --- a/packages/clerk-js/src/utils/__tests__/url.test.ts +++ b/packages/clerk-js/src/utils/__tests__/url.test.ts @@ -4,6 +4,7 @@ import { appendAsQueryParams, buildURL, getAllETLDs, + getETLDPlusOneFromFrontendApi, getSearchParameterFromHash, hasBannedProtocol, hasExternalAccountSignUpError, @@ -383,3 +384,15 @@ describe('isRedirectForFAPIInitiatedFlow(frontendAp: string, redirectUrl: string }, ); }); + +describe('getETLDPlusOneFromFrontendApi(frontendAp: string)', () => { + const testCases: Array<[string, string]> = [ + ['clerk.foo.bar-53.lcl.dev', 'foo.bar-53.lcl.dev'], + ['clerk.clerk.com', 'clerk.com'], + ['clerk.foo.bar.co.uk', 'foo.bar.co.uk'], + ]; + + test.each(testCases)('frontendApi=(%s), expected value=(%s)', (frontendApi, expectedValue) => { + expect(getETLDPlusOneFromFrontendApi(frontendApi)).toEqual(expectedValue); + }); +}); diff --git a/packages/clerk-js/src/utils/url.ts b/packages/clerk-js/src/utils/url.ts index 7e2f0017128..824f55dc0ef 100644 --- a/packages/clerk-js/src/utils/url.ts +++ b/packages/clerk-js/src/utils/url.ts @@ -1,8 +1,7 @@ import { testGlob } from '@clerk/shared'; -import { camelToSnake, createDevOrStagingUrlCache, isIPV4Address } from '@clerk/shared'; +import { camelToSnake, createDevOrStagingUrlCache } from '@clerk/shared'; import type { SignUpResource } from '@clerk/types'; -import { loadScript } from '../utils'; import { joinPaths } from './path'; import { getQueryParams } from './querystring'; @@ -55,33 +54,8 @@ export function isAccountsHostedPages(url: string | URL = window.location.hostna return res; } -export async function getETLDPlusOne(hostname: string = window.location.hostname): Promise { - if (isIPV4Address(hostname)) { - return hostname; - } - - const parts = hostname.split('.'); - - // Reuse dynamic loading of TLDParse library as in useTLDParser - if (parts.length >= 3) { - try { - await loadScript('https://cdn.jsdelivr.net/npm/tldts@5/dist/index.umd.min.js', { - globalObject: window.tldts, - }); - - return window.tldts.getDomain(hostname, { - allowPrivateDomains: true, - }); - } catch (err) { - console.error('Failed to load tldts: ', err); - } - - // Poor mans domain splitting if dynamic loading of tldts fails - const [, ...domain] = parts; - return domain.join('.'); - } - - return hostname; +export function getETLDPlusOneFromFrontendApi(frontendApi: string): string { + return frontendApi.replace('clerk.', ''); } export function getAllETLDs(hostname: string = window.location.hostname): string[] { From c6807f4558f22b54036c84fb62e2a646f167e58e Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Tue, 9 May 2023 14:44:50 +0300 Subject: [PATCH 3/6] fix(shared): Refactor shared globs helpers --- packages/shared/package.json | 3 +-- packages/shared/src/utils/globs.ts | 13 +++++++++++++ packages/shared/src/utils/index.ts | 2 +- packages/shared/src/utils/testGlob.ts | 6 ------ 4 files changed, 15 insertions(+), 9 deletions(-) create mode 100644 packages/shared/src/utils/globs.ts delete mode 100644 packages/shared/src/utils/testGlob.ts diff --git a/packages/shared/package.json b/packages/shared/package.json index c2b57355eaf..f57077d5834 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -39,11 +39,10 @@ }, "author": "", "license": "ISC", - "gitHead": "1b19a43b61f712756ab4d8c9ccbee6e8bddbe4ce", "publishConfig": { "access": "public" }, "dependencies": { - "glob-to-regexp": "^0.4.1" + "glob-to-regexp": "0.4.1" } } diff --git a/packages/shared/src/utils/globs.ts b/packages/shared/src/utils/globs.ts new file mode 100644 index 00000000000..674daf026a2 --- /dev/null +++ b/packages/shared/src/utils/globs.ts @@ -0,0 +1,13 @@ +import globToRegexp from 'glob-to-regexp'; + +export const globs = { + toRegexp: (pattern: string) => { + try { + return globToRegexp(pattern) as RegExp; + } catch (e: any) { + throw new Error( + `Invalid pattern: ${pattern}.\nConsult the documentation of glob-to-regexp here: https://www.npmjs.com/package/glob-to-regexp.\n${e.message}`, + ); + } + }, +}; diff --git a/packages/shared/src/utils/index.ts b/packages/shared/src/utils/index.ts index b0a7230025c..becca91c8fa 100644 --- a/packages/shared/src/utils/index.ts +++ b/packages/shared/src/utils/index.ts @@ -22,4 +22,4 @@ export * from './url'; export * from './workerTimers'; export * from './runWithExponentialBackOff'; export * from './isomorphicAtob'; -export * from './testGlob'; +export * from './globs'; diff --git a/packages/shared/src/utils/testGlob.ts b/packages/shared/src/utils/testGlob.ts deleted file mode 100644 index c63b288dc69..00000000000 --- a/packages/shared/src/utils/testGlob.ts +++ /dev/null @@ -1,6 +0,0 @@ -import globToRegexp from 'glob-to-regexp'; - -export const testGlob = (pattern: string, input: string) => { - const re = globToRegexp(pattern); - return re.test(input); -}; From 9fd0a938b89e0ddaedf3a57a474ba8f4b2ba3edc Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Tue, 9 May 2023 14:45:14 +0300 Subject: [PATCH 4/6] fix(shared): Refactor and test isAllowedRedirectOrigin --- .../clerk-js/src/utils/__tests__/url.test.ts | 29 ++++++++++++++++ .../clerk-js/src/utils/authPropHelpers.ts | 31 +++++++++-------- packages/clerk-js/src/utils/url.ts | 34 ++++++++----------- 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/packages/clerk-js/src/utils/__tests__/url.test.ts b/packages/clerk-js/src/utils/__tests__/url.test.ts index d63cd2e6a3c..271cf7e5cb3 100644 --- a/packages/clerk-js/src/utils/__tests__/url.test.ts +++ b/packages/clerk-js/src/utils/__tests__/url.test.ts @@ -9,6 +9,7 @@ import { hasBannedProtocol, hasExternalAccountSignUpError, isAccountsHostedPages, + isAllowedRedirectOrigin, isDataUri, isRedirectForFAPIInitiatedFlow, isValidUrl, @@ -396,3 +397,31 @@ describe('getETLDPlusOneFromFrontendApi(frontendAp: string)', () => { expect(getETLDPlusOneFromFrontendApi(frontendApi)).toEqual(expectedValue); }); }); + +fdescribe('isAllowedRedirectOrigin', () => { + const cases: [string, string[], boolean][] = [ + // base cases + ['https://clerk.com', ['https://www.clerk.com'], false], + ['https://www.clerk.com', ['https://www.clerk.com'], true], + // glob patterns + ['https://clerk.com', ['https://*.clerk.com'], false], + ['https://www.clerk.com', ['https://*.clerk.com'], true], + ['https://www.clerk.com/test', ['https://www.clerk.com/*'], true], + ['https://www.clerk.com/hello/test', ['https://www.clerk.com/*/test'], true], + ['https://www.clerk.com/hello/hello', ['https://www.clerk.com/*/test'], false], + // trailing slashes + ['https://www.clerk.com/', ['https://www.clerk.com'], true], + ['https://www.clerk.com', ['https://www.clerk.com'], true], + ['https://www.clerk.com/test', ['https://www.clerk.com'], false], + // multiple origins + ['https://www.clerk.com', ['https://www.test.dev', 'https://www.clerk.com'], true], + // relative urls + ['/relative', ['https://www.clerk.com'], true], + ['/relative/test', ['https://www.clerk.com'], true], + ['/', ['https://www.clerk.com'], true], + ]; + + test.each(cases)('isAllowedRedirectOrigin("%s","%s") === %s', (url, allowedOrigins, expected) => { + expect(isAllowedRedirectOrigin(url, allowedOrigins)).toEqual(expected); + }); +}); diff --git a/packages/clerk-js/src/utils/authPropHelpers.ts b/packages/clerk-js/src/utils/authPropHelpers.ts index 70cb4dbfaa2..145275d856d 100644 --- a/packages/clerk-js/src/utils/authPropHelpers.ts +++ b/packages/clerk-js/src/utils/authPropHelpers.ts @@ -3,7 +3,7 @@ import type { ClerkOptions, DisplayConfigResource } from '@clerk/types'; import type { ParsedQs } from 'qs'; import qs from 'qs'; -import { getFirstAllowedRedirectAndWarn, hasBannedProtocol, isValidUrl } from './index'; +import { hasBannedProtocol, isAllowedRedirectOrigin, isValidUrl } from './url'; type PickRedirectionUrlKey = 'afterSignUpUrl' | 'afterSignInUrl' | 'signInUrl' | 'signUpUrl'; @@ -12,7 +12,6 @@ type PickRedirectionOptions = { displayConfig?: DisplayConfigResource; options?: ClerkOptions; ctx?: any; - allowedRedirectOrigins?: string[]; }; /** @@ -30,29 +29,33 @@ type PickRedirectionOptions = { */ export const pickRedirectionProp = ( key: PickRedirectionUrlKey, - { ctx, queryParams, displayConfig, options, allowedRedirectOrigins }: PickRedirectionOptions, + { ctx, queryParams, displayConfig, options }: PickRedirectionOptions, accessRedirectUrl = true, ): string => { const snakeCaseField = camelToSnake(key); const queryParamValue = queryParams?.[snakeCaseField]; - const primaryQueryParamRedirectUrl = typeof queryParamValue === 'string' ? queryParamValue : null; + const primaryQueryParamRedirectUrl = typeof queryParamValue === 'string' ? queryParamValue : undefined; const secondaryQueryParamRedirectUrl = - accessRedirectUrl && typeof queryParams?.redirect_url === 'string' ? queryParams.redirect_url : null; - - let queryParamUrl: string | null | undefined = primaryQueryParamRedirectUrl || secondaryQueryParamRedirectUrl; - - if (allowedRedirectOrigins) { - queryParamUrl = getFirstAllowedRedirectAndWarn( - [primaryQueryParamRedirectUrl, secondaryQueryParamRedirectUrl].filter(i => i !== null) as string[], - allowedRedirectOrigins, - ); + accessRedirectUrl && typeof queryParams?.redirect_url === 'string' ? queryParams.redirect_url : undefined; + + let queryParamUrl: string | undefined; + if ( + primaryQueryParamRedirectUrl && + isAllowedRedirectOrigin(primaryQueryParamRedirectUrl, options?.allowedRedirectOrigins) + ) { + queryParamUrl = primaryQueryParamRedirectUrl; + } else if ( + secondaryQueryParamRedirectUrl && + isAllowedRedirectOrigin(secondaryQueryParamRedirectUrl, options?.allowedRedirectOrigins) + ) { + queryParamUrl = secondaryQueryParamRedirectUrl; } const url = queryParamUrl || ctx?.[key] || - (accessRedirectUrl ? ctx?.redirectUrl : null) || + (accessRedirectUrl ? ctx?.redirectUrl : undefined) || options?.[key] || displayConfig?.[key]; diff --git a/packages/clerk-js/src/utils/url.ts b/packages/clerk-js/src/utils/url.ts index 824f55dc0ef..1e081fd3662 100644 --- a/packages/clerk-js/src/utils/url.ts +++ b/packages/clerk-js/src/utils/url.ts @@ -1,5 +1,4 @@ -import { testGlob } from '@clerk/shared'; -import { camelToSnake, createDevOrStagingUrlCache } from '@clerk/shared'; +import { camelToSnake, createDevOrStagingUrlCache, globs } from '@clerk/shared'; import type { SignUpResource } from '@clerk/types'; import { joinPaths } from './path'; @@ -351,25 +350,22 @@ export function isRedirectForFAPIInitiatedFlow(frontendApi: string, redirectUrl: return frontendApi === url.host && frontendApiRedirectPaths.includes(path); } -const isAllowedRedirect = (_url: string, allowedRedirectOrigins: string[]) => { - const url = new URL(_url, DUMMY_URL_BASE); - - //is relative url - if (url.origin === DUMMY_URL_BASE) { +export const isAllowedRedirectOrigin = (_url: string, allowedRedirectOrigins: string[] | undefined) => { + if (!allowedRedirectOrigins) { return true; } - return allowedRedirectOrigins.some(allowedOrigin => testGlob(allowedOrigin, url.href)); -}; - -export const getFirstAllowedRedirectAndWarn = (urls: string[], allowedRedirectOrigins: string[]) => { - return urls.find(url => { - if (!isAllowedRedirect(url, allowedRedirectOrigins)) { - console.warn( - `Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`, - ); - return false; - } + const url = new URL(_url, DUMMY_URL_BASE); + const isRelativeUrl = url.origin === DUMMY_URL_BASE; + if (isRelativeUrl) { return true; - }); + } + + const isAllowed = allowedRedirectOrigins.some(origin => globs.toRegexp(origin).test(trimTrailingSlash(url.href))); + if (!isAllowed) { + console.warn( + `Clerk: Redirect URL ${url} is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.`, + ); + } + return isAllowed; }; From fcc9f29796d821d1fc001d6817f2e706325987cb Mon Sep 17 00:00:00 2001 From: Nikos Douvlis Date: Tue, 9 May 2023 14:52:33 +0300 Subject: [PATCH 5/6] fix(clerk-js): Drop allowRedirectOrigins getter from the Clerk singleton --- packages/clerk-js/src/core/clerk.ts | 16 ---------------- packages/types/src/clerk.ts | 3 --- 2 files changed, 19 deletions(-) diff --git a/packages/clerk-js/src/core/clerk.ts b/packages/clerk-js/src/core/clerk.ts index 12827be0a05..52548d945ab 100644 --- a/packages/clerk-js/src/core/clerk.ts +++ b/packages/clerk-js/src/core/clerk.ts @@ -60,7 +60,6 @@ import { createPageLifecycle, errorThrower, getClerkQueryParam, - getETLDPlusOneFromFrontendApi, hasExternalAccountSignUpError, ignoreEventValue, inActiveBrowserTab, @@ -169,21 +168,6 @@ export default class Clerk implements ClerkInterface { return false; } - get allowedRedirectOrigins(): string[] | undefined { - if (!this.#options.allowedRedirectOrigins) { - return undefined; - } - - const origins = [...(this.#options.allowedRedirectOrigins || [])]; - if (inBrowser()) { - origins.push(window.location.origin); - origins.push(window.location.origin + '/*'); - } - origins.push(`https://*.${getETLDPlusOneFromFrontendApi(this.frontendApi)}`); - origins.push(`https://*.${getETLDPlusOneFromFrontendApi(this.frontendApi)}/*`); - return origins; - } - get domain(): string { if (inBrowser()) { const strippedDomainString = stripScheme(handleValueOrFn(this.#domain, new URL(window.location.href))); diff --git a/packages/types/src/clerk.ts b/packages/types/src/clerk.ts index ff43b4476d6..794bb2f33d9 100644 --- a/packages/types/src/clerk.ts +++ b/packages/types/src/clerk.ts @@ -75,9 +75,6 @@ export interface Clerk { /** Clerk Flag for satellite apps. */ isSatellite: boolean; - /** Allowed Redirect Origins */ - allowedRedirectOrigins: string[] | undefined; - instanceType?: InstanceType; /** Client handling most Clerk operations. */ From c0c7a988769d23f47cac8175af2dbd65e168589a Mon Sep 17 00:00:00 2001 From: George Desipris Date: Thu, 11 May 2023 14:17:23 +0300 Subject: [PATCH 6/6] fix(shared): Pin glob-to-regexp version --- packages/shared/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/package.json b/packages/shared/package.json index 66afa7ebe6d..40f3803a3db 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -24,7 +24,7 @@ "@testing-library/jest-dom": "5.16.5", "@testing-library/react": "13.4.0", "@testing-library/user-event": "14.4.3", - "@types/glob-to-regexp": "^0.4.1", + "@types/glob-to-regexp": "0.4.1", "@types/js-cookie": "3.0.2", "jest": "*", "jest-environment-jsdom": "*",