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