web: add support for cloudflare turnstile

This commit is contained in:
wukko 2024-08-16 00:08:57 +06:00
parent c1813aa33f
commit 384c6deced
No known key found for this signature in database
GPG key ID: 3E30B3F26C7B4AA2
8 changed files with 89 additions and 5 deletions

View file

@ -161,6 +161,9 @@ importers:
tslib: tslib:
specifier: ^2.4.1 specifier: ^2.4.1
version: 2.6.3 version: 2.6.3
turnstile-types:
specifier: ^1.2.2
version: 1.2.2
typescript: typescript:
specifier: ^5.4.5 specifier: ^5.4.5
version: 5.5.4 version: 5.5.4
@ -2136,6 +2139,9 @@ packages:
typescript: typescript:
optional: true optional: true
turnstile-types@1.2.2:
resolution: {integrity: sha512-FlsojSOGe7OxdC5UXVXVyNV3zdWTSaC6tG6cLPWeTSkcBuCzPP+0xUwc1l090ISDcfDEt398GLbXopcGZesY/A==}
type-check@0.4.0: type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@ -4077,6 +4083,8 @@ snapshots:
- tsx - tsx
- yaml - yaml
turnstile-types@1.2.2: {}
type-check@0.4.0: type-check@0.4.0:
dependencies: dependencies:
prelude-ls: 1.2.1 prelude-ls: 1.2.1

View file

@ -40,6 +40,7 @@
"svelte-check": "^3.6.0", "svelte-check": "^3.6.0",
"svelte-preprocess": "^6.0.2", "svelte-preprocess": "^6.0.2",
"tslib": "^2.4.1", "tslib": "^2.4.1",
"turnstile-types": "^1.2.2",
"typescript": "^5.4.5", "typescript": "^5.4.5",
"typescript-eslint": "^7.13.1", "typescript-eslint": "^7.13.1",
"vite": "^5.0.3" "vite": "^5.0.3"

View file

@ -0,0 +1,41 @@
<script lang="ts">
import env from "$lib/env";
import { onMount } from "svelte";
let turnstileElement: HTMLElement;
let turnstileScript: HTMLElement;
onMount(() => {
if (!env.TURNSTILE_KEY) return;
turnstileScript.addEventListener("load", () => {
window.turnstile?.render(turnstileElement, {
sitekey: env.TURNSTILE_KEY,
"error-callback": (error) => {
console.log("turnstile error code:", error);
return true;
},
});
});
});
</script>
<svelte:head>
<script
bind:this={turnstileScript}
src="https://challenges.cloudflare.com/turnstile/v0/api.js"
defer
></script>
</svelte:head>
<div id="turnstile-container">
<div bind:this={turnstileElement} id="turnstile-widget"></div>
</div>
<style>
#turnstile-container {
position: absolute;
z-index: 999;
right: 0;
}
</style>

View file

@ -1,8 +1,10 @@
import { get } from "svelte/store"; import { get } from "svelte/store";
import turnstile from "$lib/turnstile";
import env, { apiURL } from "$lib/env"; import env, { apiURL } from "$lib/env";
import { t } from "$lib/i18n/translations"; import { t } from "$lib/i18n/translations";
import settings, { updateSetting } from "$lib/state/settings"; import settings, { updateSetting } from "$lib/state/settings";
import { createDialog } from "$lib/dialogs"; import { createDialog } from "$lib/dialogs";
import type { CobaltAPIResponse } from "$lib/types/api"; import type { CobaltAPIResponse } from "$lib/types/api";
@ -88,16 +90,29 @@ const request = async (url: string) => {
api = env.DEFAULT_API; api = env.DEFAULT_API;
} }
let turnstileHeader = {};
if (env.TURNSTILE_KEY) {
const turnstileResponse = turnstile.getResponse();
if (turnstileResponse) {
turnstileHeader = {
"cf-turnstile-response": turnstileResponse
};
}
}
const response: Optional<CobaltAPIResponse> = await fetch(api, { const response: Optional<CobaltAPIResponse> = await fetch(api, {
method: "POST", method: "POST",
redirect: "manual", redirect: "manual",
signal: AbortSignal.timeout(10000), signal: AbortSignal.timeout(10000),
body: JSON.stringify(request), body: JSON.stringify(request),
headers: { headers: {
'Accept': 'application/json', "Accept": "application/json",
'Content-Type': 'application/json' "Content-Type": "application/json",
} ...turnstileHeader,
}).then(r => r.json()).catch((e) => { },
})
.then(r => r.json())
.catch((e) => {
if (e?.message?.includes("timed out")) { if (e?.message?.includes("timed out")) {
return { return {
status: "error", status: "error",

View file

@ -5,6 +5,7 @@ const variables = {
PLAUSIBLE_HOST: env.PUBLIC_PLAUSIBLE_HOST, PLAUSIBLE_HOST: env.PUBLIC_PLAUSIBLE_HOST,
PLAUSIBLE_ENABLED: env.PUBLIC_HOST && env.PUBLIC_PLAUSIBLE_HOST, PLAUSIBLE_ENABLED: env.PUBLIC_HOST && env.PUBLIC_PLAUSIBLE_HOST,
DEFAULT_API: env.PUBLIC_DEFAULT_API, DEFAULT_API: env.PUBLIC_DEFAULT_API,
TURNSTILE_KEY: env.PUBLIC_TURNSTILE_KEY,
} }
const contacts = { const contacts = {

13
web/src/lib/turnstile.ts Normal file
View file

@ -0,0 +1,13 @@
const getResponse = () => {
const turnstileElement = document.getElementById("turnstile-widget");
if (turnstileElement) {
return window?.turnstile?.getResponse(turnstileElement);
}
return null;
}
export default {
getResponse
}

View file

@ -13,6 +13,7 @@
import "@fontsource/ibm-plex-mono/500.css"; import "@fontsource/ibm-plex-mono/500.css";
import Sidebar from "$components/sidebar/Sidebar.svelte"; import Sidebar from "$components/sidebar/Sidebar.svelte";
import Turnstile from "$components/misc/Turnstile.svelte";
import NotchSticker from "$components/misc/NotchSticker.svelte"; import NotchSticker from "$components/misc/NotchSticker.svelte";
import DialogHolder from "$components/dialog/DialogHolder.svelte"; import DialogHolder from "$components/dialog/DialogHolder.svelte";
import UpdateNotification from "$components/misc/UpdateNotification.svelte"; import UpdateNotification from "$components/misc/UpdateNotification.svelte";
@ -61,6 +62,9 @@
<DialogHolder /> <DialogHolder />
<Sidebar /> <Sidebar />
<div id="content"> <div id="content">
{#if env.TURNSTILE_KEY}
<Turnstile />
{/if}
<slot></slot> <slot></slot>
</div> </div>
</div> </div>

View file

@ -9,7 +9,8 @@
"skipLibCheck": true, "skipLibCheck": true,
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"moduleResolution": "bundler" "moduleResolution": "bundler",
"types": ["turnstile-types"]
} }
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias // 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 // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files