From 89286318b4e1094685a67fac658495fafee893de Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 21 Jan 2026 12:13:33 -0800 Subject: captcha --- src/lib/utils.ts | 8 +++- src/routes/(app)/reset/[code]/+page.server.ts | 3 +- src/routes/(app)/reset/[code]/+page.svelte | 55 ++++++++++++++++++++++++++- src/routes/(static)/login/+page.server.ts | 10 +++-- src/routes/(static)/login/+page.svelte | 47 ++++++++++++++++++++++- src/routes/(static)/register/+page.server.ts | 4 +- src/routes/(static)/register/+page.svelte | 48 ++++++++++++++++++++++- 7 files changed, 164 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 28a219e1..a3d9cd49 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -148,7 +148,13 @@ export const info = (m: string) => { }; export const login = async ( - user: { username: string; password: string }, + user: { + username: string; + password: string; + token?: string; + challenge?: string; + recaptcha?: string; + }, cookies, ip: string, ) => { 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 @@ + +
{/if} -
+ + { 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(); + } + }); + +
diff --git a/src/routes/(static)/register/+page.server.ts b/src/routes/(static)/register/+page.server.ts index 47ff8d27..d2dbe299 100644 --- a/src/routes/(static)/register/+page.server.ts +++ b/src/routes/(static)/register/+page.server.ts @@ -15,11 +15,11 @@ export const actions = { default: async ({ cookies, request }) => { const ip = request.headers.get("cf-connecting-ip"); const form = await fd(request); - const { picture, username, password, challenge } = form; + const { picture, username, password, challenge, recaptcha } = form; let { loginRedirect } = form; if (loginRedirect === "undefined") loginRedirect = undefined; - const user = { picture, username, password, challenge }; + const user = { picture, username, password, challenge, recaptcha }; return register(user, ip, cookies, loginRedirect); }, }; diff --git a/src/routes/(static)/register/+page.svelte b/src/routes/(static)/register/+page.svelte index 9e255b8e..f1ac582b 100644 --- a/src/routes/(static)/register/+page.svelte +++ b/src/routes/(static)/register/+page.svelte @@ -1,5 +1,5 @@ + + {#if need2fa} {/if} -- cgit v1.2.3