aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes/(static)/register
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-01-21 12:13:33 -0800
committerAdam Soltys <[email protected]>2026-01-21 12:13:33 -0800
commit89286318b4e1094685a67fac658495fafee893de (patch)
treedfb70d7b2acaf34c0e6f18c2d51275eb036a0d4a /src/routes/(static)/register
parent4c3682b7dcc6fb77e94822756030f9aef430ee5e (diff)
downloadcoinos-ui-89286318b4e1094685a67fac658495fafee893de.tar.gz
coinos-ui-89286318b4e1094685a67fac658495fafee893de.zip
captcha
Diffstat (limited to 'src/routes/(static)/register')
-rw-r--r--src/routes/(static)/register/+page.server.ts4
-rw-r--r--src/routes/(static)/register/+page.svelte48
2 files changed, 49 insertions, 3 deletions
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 @@
<script>
- import { onMount } from "svelte";
+ import { onDestroy, onMount } from "svelte";
import { browser } from "$app/environment";
import punks from "$lib/punks";
import { upload } from "$lib/upload";
@@ -28,6 +28,7 @@
let { form, data } = $props();
let { challenge } = $derived(data);
+ let recaptchaSiteKey = "6LfCd8YkAAAAANmVJgzN3SQY3n3fv1RhiS5PgMYM";
onMount(() => {
if (browser) {
@@ -93,6 +94,17 @@
btn = $state();
let loading = $state();
+ const getRecaptchaToken = () =>
+ new Promise((resolve, reject) => {
+ if (!browser || !grecaptcha) return reject(new Error("captcha unavailable"));
+ grecaptcha.ready(() => {
+ grecaptcha
+ .execute(recaptchaSiteKey, { action: "register" })
+ .then(resolve)
+ .catch(reject);
+ });
+ });
+
async function handleSubmit(e) {
e.preventDefault();
@@ -106,6 +118,15 @@
data.set(k, user[k]);
}
+ try {
+ const recaptcha = await getRecaptchaToken();
+ data.set("recaptcha", recaptcha);
+ } catch (err) {
+ fail(err.message || "captcha failed");
+ loading = false;
+ return;
+ }
+
data.set("picture", `${$page.url.origin}/api/public/${punks[index]}.webp`);
if ($avatar) {
try {
@@ -189,10 +210,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",
@@ -210,8 +233,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
+>
+
{#if need2fa}
<Pin bind:value={token} title="Enter 2FA Code" {cancel} notify={false} />
{/if}