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/(static)/login | |
| parent | 4c3682b7dcc6fb77e94822756030f9aef430ee5e (diff) | |
| download | coinos-ui-89286318b4e1094685a67fac658495fafee893de.tar.gz coinos-ui-89286318b4e1094685a67fac658495fafee893de.zip | |
captcha
Diffstat (limited to 'src/routes/(static)/login')
| -rw-r--r-- | src/routes/(static)/login/+page.server.ts | 10 | ||||
| -rw-r--r-- | src/routes/(static)/login/+page.svelte | 47 |
2 files changed, 52 insertions, 5 deletions
diff --git a/src/routes/(static)/login/+page.server.ts b/src/routes/(static)/login/+page.server.ts index dc68879a..dacb94b2 100644 --- a/src/routes/(static)/login/+page.server.ts +++ b/src/routes/(static)/login/+page.server.ts @@ -12,13 +12,15 @@ export const load = async ({ parent }) => { export const actions = { login: async ({ cookies, request }) => { const form = await fd(request); - let { username, password, token, loginRedirect, challenge } = form; + let { username, password, token, loginRedirect, challenge, recaptcha } = + form; const user = { - challenge, + challenge, username, password, token, + recaptcha, }; if (loginRedirect === "undefined") loginRedirect = undefined; @@ -35,7 +37,7 @@ export const actions = { nostr: async ({ cookies, fetch, request }) => { const form = await fd(request); - let { challenge, event, loginRedirect } = form; + let { challenge, event, loginRedirect, recaptcha } = form; if (loginRedirect === "null") loginRedirect = undefined; event = JSON.parse(event); @@ -43,7 +45,7 @@ export const actions = { const res = await fetch(`${PUBLIC_COINOS_URL}/nostrAuth`, { method: "POST", - body: JSON.stringify({ challenge, event }), + body: JSON.stringify({ challenge, event, recaptcha }), headers: { "content-type": "application/json", accept: "application/json", diff --git a/src/routes/(static)/login/+page.svelte b/src/routes/(static)/login/+page.svelte index 450425f6..08656949 100644 --- a/src/routes/(static)/login/+page.svelte +++ b/src/routes/(static)/login/+page.svelte @@ -2,7 +2,7 @@ import { browser } from "$app/environment"; import handler from "$lib/handler"; import { applyAction, deserialize } from "$app/forms"; - import { onMount, tick } from "svelte"; + import { onDestroy, onMount, tick } from "svelte"; import { fly } from "svelte/transition"; import { enhance } from "$app/forms"; import Pinpad from "$comp/Pinpad.svelte"; @@ -37,6 +37,7 @@ }); let { challenge } = $derived(data); + let recaptchaSiteKey = "6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM"; let token = $state(""); let cancel = () => (need2fa = false); @@ -53,6 +54,17 @@ let revealPassword = $state(false); + const getRecaptchaToken = () => + new Promise((resolve, reject) => { + if (!browser || !grecaptcha) return reject(new Error("captcha unavailable")); + grecaptcha.ready(() => { + grecaptcha + .execute(recaptchaSiteKey, { action: "login" }) + .then(resolve) + .catch(reject); + }); + }); + async function handleSubmit(e) { e.preventDefault(); let data = new FormData(this); @@ -62,6 +74,14 @@ data.set(k, user[k]); } + try { + const recaptcha = await getRecaptchaToken(); + data.set("recaptcha", recaptcha); + } catch (err) { + fail(err.message || "captcha failed"); + return; + } + const response = await fetch("?/login", { method: "POST", body: data, @@ -104,10 +124,12 @@ const formData = new FormData(); try { + const recaptcha = await getRecaptchaToken(); formData.append("loginRedirect", redirect); formData.append("token", token); formData.append("event", JSON.stringify(signedEvent)); formData.append("challenge", challenge); + formData.append("recaptcha", recaptcha); let response = await fetch("/login?/nostr", { method: "POST", @@ -121,8 +143,31 @@ fail(e.message); } }; + + 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="mx-auto md:shadow-xl rounded-3xl max-w-xl w-full md:w-[480px] md:p-8 mb-20 space-y-5" > |
