diff options
| author | Adam Soltys <[email protected]> | 2026-01-21 12:13:33 -0800 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-01-21 12:13:33 -0800 |
| commit | 89286318b4e1094685a67fac658495fafee893de (patch) | |
| tree | dfb70d7b2acaf34c0e6f18c2d51275eb036a0d4a /src/routes/(app) | |
| parent | 4c3682b7dcc6fb77e94822756030f9aef430ee5e (diff) | |
| download | coinos-ui-89286318b4e1094685a67fac658495fafee893de.tar.gz coinos-ui-89286318b4e1094685a67fac658495fafee893de.zip | |
captcha
Diffstat (limited to 'src/routes/(app)')
| -rw-r--r-- | src/routes/(app)/reset/[code]/+page.server.ts | 3 | ||||
| -rw-r--r-- | src/routes/(app)/reset/[code]/+page.svelte | 55 |
2 files changed, 56 insertions, 2 deletions
diff --git a/src/routes/(app)/reset/[code]/+page.server.ts b/src/routes/(app)/reset/[code]/+page.server.ts index 533e21f5..35d49be9 100644 --- a/src/routes/(app)/reset/[code]/+page.server.ts +++ b/src/routes/(app)/reset/[code]/+page.server.ts @@ -7,11 +7,12 @@ export const actions = { let error; const { code } = params; - const { password } = await fd(request); + const { password, recaptcha } = await fd(request); try { const user = await post("/reset", { code, password }); user.password = password; + user.recaptcha = recaptcha; try { await login(user, cookies, ip); diff --git a/src/routes/(app)/reset/[code]/+page.svelte b/src/routes/(app)/reset/[code]/+page.svelte index df9d1144..227d0106 100644 --- a/src/routes/(app)/reset/[code]/+page.svelte +++ b/src/routes/(app)/reset/[code]/+page.svelte @@ -1,16 +1,68 @@ <script> + import { browser } from "$app/environment"; + import { onDestroy, tick } from "svelte"; import { t } from "$lib/translations"; import PasswordInput from "$comp/PasswordInput.svelte"; import Icon from "$comp/Icon.svelte"; import Spinner from "$comp/Spinner.svelte"; import { fly } from "svelte/transition"; import { password } from "$lib/store"; + import { fail } from "$lib/utils"; let { form } = $props(); let email; let loading; + let recaptchaToken = ""; + let recaptchaSiteKey = "6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM"; + + const getRecaptchaToken = () => + new Promise((resolve, reject) => { + if (!browser || !grecaptcha) return reject(new Error("captcha unavailable")); + grecaptcha.ready(() => { + grecaptcha + .execute(recaptchaSiteKey, { action: "reset" }) + .then(resolve) + .catch(reject); + }); + }); + + const handleSubmit = async (e) => { + e.preventDefault(); + loading = true; + try { + recaptchaToken = await getRecaptchaToken(); + await tick(); + e.currentTarget.submit(); + } catch (err) { + fail(err.message || "captcha failed"); + loading = false; + } + }; + + onDestroy(() => { + if (!browser) return; + const nodeBadge = document.querySelector(".grecaptcha-badge"); + if (nodeBadge) { + document.body.removeChild(nodeBadge.parentNode); + } + + const scriptSelector = + "script[src='https://www.google.com/recaptcha/api.js?render=" + + recaptchaSiteKey + + "']"; + const script = document.querySelector(scriptSelector); + if (script) { + script.remove(); + } + }); </script> +<svelte:head + ><script + src="https://www.google.com/recaptcha/api.js?render=6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM" + ></script></svelte:head +> + <div class="pt-10"> <div class="w-[243px] mx-auto mb-10"> <a href="/"> @@ -30,7 +82,8 @@ </div> {/if} - <form class="space-y-5" method="POST"> + <form class="space-y-5" method="POST" onsubmit={handleSubmit}> + <input type="hidden" name="recaptcha" value={recaptchaToken} /> <PasswordInput bind:value={$password} placeholder={$t("login.password")} |
