diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 84a135e4..9d316277 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -161,6 +161,9 @@ importers:
tslib:
specifier: ^2.4.1
version: 2.6.3
+ turnstile-types:
+ specifier: ^1.2.2
+ version: 1.2.2
typescript:
specifier: ^5.4.5
version: 5.5.4
@@ -2136,6 +2139,9 @@ packages:
typescript:
optional: true
+ turnstile-types@1.2.2:
+ resolution: {integrity: sha512-FlsojSOGe7OxdC5UXVXVyNV3zdWTSaC6tG6cLPWeTSkcBuCzPP+0xUwc1l090ISDcfDEt398GLbXopcGZesY/A==}
+
type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -4077,6 +4083,8 @@ snapshots:
- tsx
- yaml
+ turnstile-types@1.2.2: {}
+
type-check@0.4.0:
dependencies:
prelude-ls: 1.2.1
diff --git a/web/package.json b/web/package.json
index c9454818..25c7fb3e 100644
--- a/web/package.json
+++ b/web/package.json
@@ -40,6 +40,7 @@
"svelte-check": "^3.6.0",
"svelte-preprocess": "^6.0.2",
"tslib": "^2.4.1",
+ "turnstile-types": "^1.2.2",
"typescript": "^5.4.5",
"typescript-eslint": "^7.13.1",
"vite": "^5.0.3"
diff --git a/web/src/components/misc/Turnstile.svelte b/web/src/components/misc/Turnstile.svelte
new file mode 100644
index 00000000..4cf5e112
--- /dev/null
+++ b/web/src/components/misc/Turnstile.svelte
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts
index ad0b58e2..083a3e06 100644
--- a/web/src/lib/api.ts
+++ b/web/src/lib/api.ts
@@ -1,8 +1,10 @@
import { get } from "svelte/store";
+import turnstile from "$lib/turnstile";
import env, { apiURL } from "$lib/env";
import { t } from "$lib/i18n/translations";
import settings, { updateSetting } from "$lib/state/settings";
+
import { createDialog } from "$lib/dialogs";
import type { CobaltAPIResponse } from "$lib/types/api";
@@ -88,16 +90,29 @@ const request = async (url: string) => {
api = env.DEFAULT_API;
}
+ let turnstileHeader = {};
+ if (env.TURNSTILE_KEY) {
+ const turnstileResponse = turnstile.getResponse();
+ if (turnstileResponse) {
+ turnstileHeader = {
+ "cf-turnstile-response": turnstileResponse
+ };
+ }
+ }
+
const response: Optional = await fetch(api, {
method: "POST",
redirect: "manual",
signal: AbortSignal.timeout(10000),
body: JSON.stringify(request),
headers: {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- }
- }).then(r => r.json()).catch((e) => {
+ "Accept": "application/json",
+ "Content-Type": "application/json",
+ ...turnstileHeader,
+ },
+ })
+ .then(r => r.json())
+ .catch((e) => {
if (e?.message?.includes("timed out")) {
return {
status: "error",
diff --git a/web/src/lib/env.ts b/web/src/lib/env.ts
index 26cc1fff..04391303 100644
--- a/web/src/lib/env.ts
+++ b/web/src/lib/env.ts
@@ -5,6 +5,7 @@ const variables = {
PLAUSIBLE_HOST: env.PUBLIC_PLAUSIBLE_HOST,
PLAUSIBLE_ENABLED: env.PUBLIC_HOST && env.PUBLIC_PLAUSIBLE_HOST,
DEFAULT_API: env.PUBLIC_DEFAULT_API,
+ TURNSTILE_KEY: env.PUBLIC_TURNSTILE_KEY,
}
const contacts = {
diff --git a/web/src/lib/turnstile.ts b/web/src/lib/turnstile.ts
new file mode 100644
index 00000000..63191385
--- /dev/null
+++ b/web/src/lib/turnstile.ts
@@ -0,0 +1,13 @@
+const getResponse = () => {
+ const turnstileElement = document.getElementById("turnstile-widget");
+
+ if (turnstileElement) {
+ return window?.turnstile?.getResponse(turnstileElement);
+ }
+
+ return null;
+}
+
+export default {
+ getResponse
+}
diff --git a/web/src/routes/+layout.svelte b/web/src/routes/+layout.svelte
index fe31e753..855b99a4 100644
--- a/web/src/routes/+layout.svelte
+++ b/web/src/routes/+layout.svelte
@@ -13,6 +13,7 @@
import "@fontsource/ibm-plex-mono/500.css";
import Sidebar from "$components/sidebar/Sidebar.svelte";
+ import Turnstile from "$components/misc/Turnstile.svelte";
import NotchSticker from "$components/misc/NotchSticker.svelte";
import DialogHolder from "$components/dialog/DialogHolder.svelte";
import UpdateNotification from "$components/misc/UpdateNotification.svelte";
@@ -61,6 +62,9 @@
+ {#if env.TURNSTILE_KEY}
+
+ {/if}
diff --git a/web/tsconfig.json b/web/tsconfig.json
index 471ad319..52b33f5e 100644
--- a/web/tsconfig.json
+++ b/web/tsconfig.json
@@ -9,7 +9,8 @@
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
- "moduleResolution": "bundler"
+ "moduleResolution": "bundler",
+ "types": ["turnstile-types"]
}
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files