From 186f26578319af40fa772e0aeafe8550444eb540 Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Mon, 14 Oct 2024 14:28:41 +0300 Subject: [PATCH 1/3] fix(clerk-js): Add support for loading Turnstile from Cloudflare host This commit adds support for loading the Turnstile CAPTCHA script from the Cloudflare host. If the script fails to load from the Cloudflare URL, it falls back to a FAPI-proxied URL. --- .changeset/odd-squids-dress.md | 5 +++ .../clerk-js/src/utils/captcha/turnstile.ts | 33 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 .changeset/odd-squids-dress.md diff --git a/.changeset/odd-squids-dress.md b/.changeset/odd-squids-dress.md new file mode 100644 index 00000000000..031ac85139c --- /dev/null +++ b/.changeset/odd-squids-dress.md @@ -0,0 +1,5 @@ +--- +"@clerk/clerk-js": patch +--- + +Try loading Turnstile from Cloudflare host. diff --git a/packages/clerk-js/src/utils/captcha/turnstile.ts b/packages/clerk-js/src/utils/captcha/turnstile.ts index c286638e8ce..6e43e50b073 100644 --- a/packages/clerk-js/src/utils/captcha/turnstile.ts +++ b/packages/clerk-js/src/utils/captcha/turnstile.ts @@ -3,6 +3,8 @@ import type { CaptchaWidgetType } from '@clerk/types'; import { CAPTCHA_ELEMENT_ID, CAPTCHA_INVISIBLE_CLASSNAME } from './constants'; +const CLOUDFLARE_TURSTILE_ORIGINAL_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js'; + interface RenderOptions { /** * Every widget has a sitekey. This sitekey is associated with the corresponding widget configuration and is created upon the widget creation. @@ -69,21 +71,38 @@ export const shouldRetryTurnstileErrorCode = (errorCode: string) => { return !!codesWithRetries.find(w => errorCode.startsWith(w)); }; -async function loadCaptcha(url: string) { +async function loadCaptcha(fallbackUrl: string) { if (!window.turnstile) { try { - await loadScript(url, { defer: true }); + await loadCaptchaFromCloudflareURL(); } catch { - // Rethrow with specific message - console.error('Clerk: Failed to load the CAPTCHA script from the URL: ', url); - throw { - captchaError: 'captcha_script_failed_to_load', - }; + await loadCaptchaFromFAPIProxiedURL(fallbackUrl); } } return window.turnstile; } +async function loadCaptchaFromCloudflareURL() { + try { + await loadScript(CLOUDFLARE_TURSTILE_ORIGINAL_URL, { defer: true }); + } catch (err) { + console.error('Clerk: Failed to load the CAPTCHA script from the original Cloudflare URL.'); + throw err; + } +} + +async function loadCaptchaFromFAPIProxiedURL(fallbackUrl: string) { + try { + await loadScript(fallbackUrl, { defer: true }); + } catch { + // Rethrow with specific message + console.error('Clerk: Failed to load the CAPTCHA script from the URL: ', fallbackUrl); + throw { + captchaError: 'captcha_script_failed_to_load', + }; + } +} + /* * How this function works: * The widgetType is either 'invisible' or 'smart'. From 6a09d25d1ba64da5405e0834d7b6e98d61caaee6 Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Mon, 14 Oct 2024 14:30:45 +0300 Subject: [PATCH 2/3] fix typo --- packages/clerk-js/src/utils/captcha/turnstile.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/clerk-js/src/utils/captcha/turnstile.ts b/packages/clerk-js/src/utils/captcha/turnstile.ts index 6e43e50b073..ae13c919368 100644 --- a/packages/clerk-js/src/utils/captcha/turnstile.ts +++ b/packages/clerk-js/src/utils/captcha/turnstile.ts @@ -3,7 +3,7 @@ import type { CaptchaWidgetType } from '@clerk/types'; import { CAPTCHA_ELEMENT_ID, CAPTCHA_INVISIBLE_CLASSNAME } from './constants'; -const CLOUDFLARE_TURSTILE_ORIGINAL_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js'; +const CLOUDFLARE_TURNSTILE_ORIGINAL_URL = 'https://challenges.cloudflare.com/turnstile/v0/api.js'; interface RenderOptions { /** @@ -84,7 +84,7 @@ async function loadCaptcha(fallbackUrl: string) { async function loadCaptchaFromCloudflareURL() { try { - await loadScript(CLOUDFLARE_TURSTILE_ORIGINAL_URL, { defer: true }); + await loadScript(CLOUDFLARE_TURNSTILE_ORIGINAL_URL, { defer: true }); } catch (err) { console.error('Clerk: Failed to load the CAPTCHA script from the original Cloudflare URL.'); throw err; From 80f34d70294b8c4f868225003b0b4a79c776bd28 Mon Sep 17 00:00:00 2001 From: Stefanos Anagnostou Date: Mon, 14 Oct 2024 17:07:31 +0300 Subject: [PATCH 3/3] Resolve comments --- .changeset/odd-squids-dress.md | 4 ++- .../clerk-js/src/utils/captcha/turnstile.ts | 25 +++++++------------ 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/.changeset/odd-squids-dress.md b/.changeset/odd-squids-dress.md index 031ac85139c..04e8745bdee 100644 --- a/.changeset/odd-squids-dress.md +++ b/.changeset/odd-squids-dress.md @@ -2,4 +2,6 @@ "@clerk/clerk-js": patch --- -Try loading Turnstile from Cloudflare host. +Improve bot detection by loading the Turnstile SDK directly from CloudFlare. + +If loading fails due to CSP rules, load it through FAPI instead. diff --git a/packages/clerk-js/src/utils/captcha/turnstile.ts b/packages/clerk-js/src/utils/captcha/turnstile.ts index ae13c919368..78e8229a4d4 100644 --- a/packages/clerk-js/src/utils/captcha/turnstile.ts +++ b/packages/clerk-js/src/utils/captcha/turnstile.ts @@ -73,33 +73,26 @@ export const shouldRetryTurnstileErrorCode = (errorCode: string) => { async function loadCaptcha(fallbackUrl: string) { if (!window.turnstile) { - try { - await loadCaptchaFromCloudflareURL(); - } catch { - await loadCaptchaFromFAPIProxiedURL(fallbackUrl); - } + await loadCaptchaFromCloudflareURL() + .catch(() => loadCaptchaFromFAPIProxiedURL(fallbackUrl)) + .catch(() => { + throw { captchaError: 'captcha_script_failed_to_load' }; + }); } return window.turnstile; } async function loadCaptchaFromCloudflareURL() { - try { - await loadScript(CLOUDFLARE_TURNSTILE_ORIGINAL_URL, { defer: true }); - } catch (err) { - console.error('Clerk: Failed to load the CAPTCHA script from the original Cloudflare URL.'); - throw err; - } + return await loadScript(CLOUDFLARE_TURNSTILE_ORIGINAL_URL, { defer: true }); } async function loadCaptchaFromFAPIProxiedURL(fallbackUrl: string) { try { - await loadScript(fallbackUrl, { defer: true }); - } catch { + return await loadScript(fallbackUrl, { defer: true }); + } catch (err) { // Rethrow with specific message console.error('Clerk: Failed to load the CAPTCHA script from the URL: ', fallbackUrl); - throw { - captchaError: 'captcha_script_failed_to_load', - }; + throw err; } }