Skip to content

Commit d10a2ab

Browse files
committed
Captcha implementado con Cloudflare
1 parent a023fa3 commit d10a2ab

1 file changed

Lines changed: 185 additions & 15 deletions

File tree

src/components/SubscribeBox.svelte

Lines changed: 185 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,205 @@
11
<script>
2+
import { onMount } from 'svelte';
3+
24
export let color;
35
export let text;
46
export let subscribeForm;
57
6-
let breveo_url = "https://e84a0152.sibforms.com/serve/MUIFABjdnMHTbxQ2khl6ph4PImtHS0y057KeTtnZ8ST-53106GteNUOJUzjhpVFibL3A_kN8NSvM-dHnI4U0Eu2CLfsvr_sm9db1VdgsqQvtFJFiM9KySFp7o3hZxzON2vLkcj-ioBELpTPFkCBfA2M2lg0fRjsXNlo99Mynwc6T2rYL4mDx6KHLxCXgwauF_DuSGhxf_l71MVh9"
8+
let breveo_url =
9+
'https://e84a0152.sibforms.com/serve/MUIFABjdnMHTbxQ2khl6ph4PImtHS0y057KeTtnZ8ST-53106GteNUOJUzjhpVFibL3A_kN8NSvM-dHnI4U0Eu2CLfsvr_sm9db1VdgsqQvtFJFiM9KySFp7o3hZxzON2vLkcj-ioBELpTPFkCBfA2M2lg0fRjsXNlo99Mynwc6T2rYL4mDx6KHLxCXgwauF_DuSGhxf_l71MVh9';
710
// todo: Este regex testeado no deja pasar un dominio sin TLD (ej. a@a) pero implementado aquí, sí lo permite. hay que modificarlo
8-
let regex = "(?:[a-z0-9!#$%&*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&*+/=?^_`{|}~-]+)*|(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*)@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])"
11+
let regex =
12+
'(?:[a-z0-9!#$%&*+/=?^_`{|}~-]+(?:.[a-z0-9!#$%&*+/=?^_`{|}~-]+)*|(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*)@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])).){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)])';
13+
14+
// Spam prevention variables
15+
let formStartTime = Date.now();
16+
let turnstileResponse = '';
17+
let turnstileWidgetId = null;
18+
let isTurnstileLoaded = false;
19+
20+
onMount(() => {
21+
if (!window.turnstile) {
22+
console.log('Cargando script de Turnstile...');
23+
const script = document.createElement('script');
24+
script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js';
25+
script.async = true;
26+
script.defer = true;
27+
script.onload = () => {
28+
console.log('Script de Turnstile cargado exitosamente');
29+
isTurnstileLoaded = true;
30+
setTimeout(() => {
31+
initTurnstile();
32+
}, 500);
33+
};
34+
script.onerror = () => {
35+
console.error('Error al cargar el script de Turnstile');
36+
};
37+
document.head.appendChild(script);
38+
} else {
39+
console.log('Turnstile ya está cargado');
40+
isTurnstileLoaded = true;
41+
initTurnstile();
42+
}
43+
});
44+
45+
// Widget para el Captcha de Cloudflare Turnstile
46+
function initTurnstile() {
47+
console.log('Intentando inicializar Turnstile...');
48+
console.log('window.turnstile:', window.turnstile);
49+
console.log('isTurnstileLoaded:', isTurnstileLoaded);
50+
51+
if (window.turnstile && isTurnstileLoaded) {
52+
try {
53+
console.log('Renderizando widget de Turnstile...');
54+
turnstileWidgetId = window.turnstile.render('#turnstile-container', {
55+
sitekey: '0x4AAAAAAB6c7nCtT4Pnd6ZP',
56+
callback: function (token) {
57+
console.log('Callback de Turnstile recibido:', token);
58+
turnstileResponse = token;
59+
},
60+
'expired-callback': function () {
61+
console.log('Turnstile caducado');
62+
turnstileResponse = '';
63+
},
64+
'error-callback': function (error) {
65+
console.error('Error de Turnstile:', error);
66+
turnstileResponse = '';
67+
}
68+
});
69+
console.log('ID del widget de Turnstile:', turnstileWidgetId);
70+
} catch (error) {
71+
console.error('Error al inicializar Turnstile:', error);
72+
}
73+
} else {
74+
console.log('Turnstile aún no está listo');
75+
}
76+
}
77+
78+
// Check if form was filled too quickly (likely bot)
79+
function isFormTooFast() {
80+
const timeElapsed = Date.now() - formStartTime;
81+
return timeElapsed < 3000; // Less than 3 seconds is suspicious
82+
}
83+
84+
// Validate form submission
85+
function validateForm(event) {
86+
const target = event.target;
87+
88+
// Check honeypot field
89+
const honeypot = target.querySelector('input[name="website"]');
90+
if (honeypot && honeypot.value !== '') {
91+
event.preventDefault();
92+
console.log('Bot detectado: campo honeypot llenado');
93+
alert('Solicitud bloqueada por seguridad.');
94+
return false;
95+
}
96+
97+
// Check if form was submitted too quickly
98+
if (isFormTooFast()) {
99+
event.preventDefault();
100+
console.log('Bot detectado: formulario enviado muy rápido');
101+
alert('Por favor, espera unos segundos antes de enviar el formulario.');
102+
return false;
103+
}
104+
105+
// Check Turnstile (if enabled)
106+
console.log('Verificando respuesta de Turnstile:', turnstileResponse);
107+
console.log('ID del widget de Turnstile:', turnstileWidgetId);
108+
console.log('isTurnstileLoaded:', isTurnstileLoaded);
109+
110+
if (!turnstileResponse) {
111+
event.preventDefault();
112+
alert('Por favor, completa la verificación de seguridad.');
113+
return false;
114+
}
115+
116+
// If validation passes, allow form submission to Brevo
117+
console.log('Validación del formulario pasada, enviando a Brevo');
118+
return true;
119+
}
120+
121+
// Initialize Turnstile when component becomes visible
122+
function handleFormFocus() {
123+
if (isTurnstileLoaded && !turnstileWidgetId) {
124+
setTimeout(initTurnstile, 100);
125+
}
126+
}
127+
128+
// For localhost testing - bypass Turnstile
129+
function bypassTurnstileForTesting() {
130+
console.log('Saltando Turnstile para pruebas en localhost');
131+
turnstileResponse = 'test-token-for-localhost';
132+
}
9133
</script>
10134

11-
<div class="bg-[url('/grid-bg.png')] min-h-[350px] p-2 md:p-10 h-auto w-full container m-auto flex items-center drop-shadow-full" style="background-color: {color};">
135+
<div
136+
class="bg-[url('/grid-bg.png')] min-h-[350px] p-2 md:p-10 h-auto w-full container m-auto flex items-center drop-shadow-full"
137+
style="background-color: {color};"
138+
>
12139
<div class="Frame52 w-full flex-col justify-center items-center md:p-5">
13-
<div class="text-center text-black text-2xl md:text-5xl font-bold font-['Albert Sans'] md:leading-[63.44px] md:p-5 text-wrap">
140+
<div
141+
class="text-center text-black text-2xl md:text-5xl font-bold font-['Albert Sans'] md:leading-[63.44px] md:p-5 text-wrap"
142+
>
14143
<p>
15144
{@html text}
16145
</p>
17146
</div>
18-
{#if subscribeForm }
147+
{#if subscribeForm}
19148
<div class="flex justify-center mx-auto my-3">
20-
<form class="w-full max-w-sm validate" action={breveo_url} method="post" id="newsletter-form" target="_blank" >
21-
<div class="flex items-center">
22-
<input class="appearance-none border-none w-full text-gray-700 px-4 py-3 rounded-tl-3xl rounded-bl-3xl border-zinc-300 leading-tight focus:outline-none" placeholder="correo@ejemplo.org" aria-label="Full name" type="email" name="EMAIL" required="true" value="" pattern={regex}>
149+
<form
150+
class="w-full max-w-sm validate"
151+
action={breveo_url}
152+
method="post"
153+
id="newsletter-form"
154+
target="_blank"
155+
on:submit={validateForm}
156+
on:focus={handleFormFocus}
157+
>
158+
<div class="flex flex-col items-center space-y-3">
159+
<div class="flex items-center w-full">
160+
<input
161+
class="appearance-none border-none w-full text-gray-700 px-4 py-3 rounded-tl-3xl rounded-bl-3xl border-zinc-300 leading-tight focus:outline-none"
162+
placeholder="correo@ejemplo.org"
163+
aria-label="Email address"
164+
type="email"
165+
name="EMAIL"
166+
required={true}
167+
value=""
168+
pattern={regex}
169+
/>
170+
<button
171+
class="flex-shrink-0 px-5 py-2 bg-black rounded-tr-3xl h-11 rounded-br-3xl text-sm border border-black text-white rounded text-base font-bold font-['Albert Sans'] uppercase leading-normal"
172+
type="submit"
173+
>
174+
<input
175+
type="submit"
176+
name="subscribe"
177+
class="button uppercase"
178+
value="Suscribirme"
179+
/>
180+
</button>
181+
</div>
182+
183+
<!-- Cloudflare Turnstile Container -->
184+
<div id="turnstile-container" class="flex justify-center"></div>
185+
186+
<!-- Honeypot fields for spam prevention -->
23187
<div style="position: absolute; left: -5000px;" aria-hidden="true">
24-
/* real people should not fill this in and expect good things - do not remove this or risk form bot signups */
25-
<input type="text" name="b_6a37b9b668c1da15bcc718fa4_203574be23" tabindex="-1" value="">
188+
<!-- Original honeypot -->
189+
<input
190+
type="text"
191+
name="b_6a37b9b668c1da15bcc718fa4_203574be23"
192+
tabindex="-1"
193+
value=""
194+
/>
195+
<!-- Additional honeypot field -->
196+
<input type="text" name="website" tabindex="-1" value="" autocomplete="off" />
197+
<!-- Time-based validation field -->
198+
<input type="hidden" name="form_time" value={formStartTime} />
26199
</div>
27-
<button class="flex-shrink-0 px-5 py-2 bg-black rounded-tr-3xl h-11 rounded-br-3xl text-sm border border-black text-white rounded text-base font-bold font-['Albert Sans'] uppercase leading-normal" type="button">
28-
<input type="submit" name="subscribe" class="button uppercase" value="Suscribirme">
29-
</button>
30200
</div>
31201
</form>
32202
</div>
33-
{/if }
203+
{/if}
34204
</div>
35-
</div>
205+
</div>

0 commit comments

Comments
 (0)