PageSourceSearch

https://dt7.agency/static/assets/js/anti_spam.js

js dt7.agency collected 2026-10-08 20:28:51 UTC 19,785 bytes, 371 lines download raw bytes

1/**
2 * DT7 Solutions - Sequential 2-Step Anti-Spam Security Verification Script
3 * Step 1: Security Question (Math Calculation) -> Once solved...
4 * Step 2: Visual Security CAPTCHA Code -> Unlocks & verifies -> Enables Submit
5 * 
6 * Configured Rule:
7 * - 2-Step Verification UI enabled for Contact Us section, Get in Touch section (#myForm), and Enquiry Form Modal (#popresetting).
8 * - 2-Step Verification UI REMOVED from Footer newsletter forms.
9 */
10(function () {
11    function generateCaptchaCode(length) {
12        var chars = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"; // exclude easily confused characters (0, O, 1, I)
13        var code = "";
14        for (var i = 0; i < length; i++) {
15            code += chars.charAt(Math.floor(Math.random() * chars.length));
16        }
17        return code;
18    }
19
20    function resetSecurityChallenge(container) {
21        // Generate Step 1 Math
22        var num1 = Math.floor(Math.random() * 12) + 2; // 2 to 13
23        var num2 = Math.floor(Math.random() * 9) + 1;  // 1 to 9
24        var sum = num1 + num2;
25        container.setAttribute("data-expected-sum", sum);
26
27        // Generate Step 2 CAPTCHA
28        var captchaCode = generateCaptchaCode(5);
29        container.setAttribute("data-expected-captcha", captchaCode);
30
31        // Reset state
32        container.setAttribute("data-step1-passed", "false");
33        container.setAttribute("data-step2-passed", "false");
34
35        // Elements
36        var num1Input = container.querySelector('.math-num1-input');
37        var num2Input = container.querySelector('.math-num2-input');
38        var mathQuestionText = container.querySelector('.math-question-text');
39        var mathAnswerInput = container.querySelector('.math-answer-input');
40
41        var captchaCodeText = container.querySelector('.captcha-code-text');
42        var captchaInput = container.querySelector('.captcha-input-field');
43        var captchaExpectedInput = container.querySelector('.captcha-expected-input');
44
45        var step1Badge = container.querySelector('.step1-status-badge');
46        var step2Badge = container.querySelector('.step2-status-badge');
47        var step2Box = container.querySelector('.step2-box');
48        var successAlert = container.querySelector('.anti-spam-success-msg');
49        var errorMsg = container.querySelector('.anti-spam-error-msg');
50
51        if (num1Input) num1Input.value = num1;
52        if (num2Input) num2Input.value = num2;
53        if (mathQuestionText) mathQuestionText.textContent = "What is " + num1 + " + " + num2 + " = ?";
54        if (mathAnswerInput) {
55            mathAnswerInput.value = "";
56            mathAnswerInput.disabled = false;
57            mathAnswerInput.style.borderColor = "";
58        }
59
60        if (captchaCodeText) captchaCodeText.textContent = captchaCode.split('').join(' ');
61        if (captchaExpectedInput) captchaExpectedInput.value = captchaCode;
62        if (captchaInput) {
63            captchaInput.value = "";
64            captchaInput.style.borderColor = "";
65        }
66
67        // Hide Step 2 initially until Step 1 is done
68        if (step2Box) step2Box.style.display = "none";
69        if (step1Badge) {
70            step1Badge.className = "badge bg-primary me-2";
71            step1Badge.textContent = "Step 1 of 2";
72            step1Badge.style.cssText = "background:#0284c7!important; color:#ffffff;";
73        }
74        if (step2Badge) {
75            step2Badge.className = "badge bg-secondary me-2";
76            step2Badge.textContent = "Step 2 of 2";
77        }
78
79        if (successAlert) successAlert.style.display = "none";
80        if (errorMsg) errorMsg.style.display = "none";
81
82        // Lock form submit button until both steps are done
83        var form = container.closest('form');
84        if (form) {
85            var submitBtn = form.querySelector('button[type="submit"], input[type="submit"]');
86            if (submitBtn) {
87                submitBtn.disabled = true;
88                submitBtn.style.opacity = "0.5";
89                submitBtn.style.cursor = "not-allowed";
90                submitBtn.title = "Complete 2-step security verification first";
91            }
92        }
93    }
94
95    function checkStep1(container) {
96        var expectedSum = parseInt(container.getAttribute("data-expected-sum"), 10);
97        var mathAnswerInput = container.querySelector('.math-answer-input');
98        var val = mathAnswerInput ? parseInt(mathAnswerInput.value.trim(), 10) : NaN;
99
100        var step1Badge = container.querySelector('.step1-status-badge');
101        var step2Box = container.querySelector('.step2-box');
102        var captchaInput = container.querySelector('.captcha-input-field');
103        var errorMsg = container.querySelector('.anti-spam-error-msg');
104
105        if (!isNaN(val) && val === expectedSum) {
106            container.setAttribute("data-step1-passed", "true");
107            if (step1Badge) {
108                step1Badge.className = "badge bg-success me-2";
109                step1Badge.textContent = "✔ Step 1 Passed";
110                step1Badge.style.cssText = "background:#16a34a!important; color:#ffffff;";
111            }
112            if (mathAnswerInput) mathAnswerInput.style.borderColor = "#16a34a";
113            if (errorMsg) errorMsg.style.display = "none";
114
115            // Reveal Step 2 dynamically ("once done then asking second verification")
116            if (step2Box && step2Box.style.display === "none") {
117                step2Box.style.display = "block";
118                step2Box.style.opacity = "0";
119                setTimeout(function () {
120                    step2Box.style.transition = "opacity 0.3s ease-in-out";
121                    step2Box.style.opacity = "1";
122                    if (captchaInput) captchaInput.focus();
123                }, 50);
124            }
125            return true;
126        } else {
127            container.setAttribute("data-step1-passed", "false");
128            if (step1Badge) {
129                step1Badge.className = "badge bg-primary me-2";
130                step1Badge.textContent = "Step 1 of 2";
131                step1Badge.style.cssText = "background:#0284c7!important; color:#ffffff;";
132            }
133            if (step2Box) step2Box.style.display = "none";
134            return false;
135        }
136    }
137
138    function checkStep2(container) {
139        var expectedCaptcha = (container.getAttribute("data-expected-captcha") || "").toUpperCase();
140        var captchaInput = container.querySelector('.captcha-input-field');
141        var val = captchaInput ? captchaInput.value.trim().toUpperCase() : "";
142
143        var step2Badge = container.querySelector('.step2-status-badge');
144        var successAlert = container.querySelector('.anti-spam-success-msg');
145        var errorMsg = container.querySelector('.anti-spam-error-msg');
146        var form = container.closest('form');
147        var submitBtn = form ? form.querySelector('button[type="submit"], input[type="submit"]') : null;
148
149        if (val.length === 5 && val === expectedCaptcha) {
150            container.setAttribute("data-step2-passed", "true");
151            if (step2Badge) {
152                step2Badge.className = "badge bg-success me-2";
153                step2Badge.textContent = "✔ Step 2 Verified!";
154                step2Badge.style.cssText = "background:#16a34a!important; color:#ffffff;";
155            }
156            if (captchaInput) captchaInput.style.borderColor = "#16a34a";
157            if (successAlert) successAlert.style.display = "block";
158            if (errorMsg) errorMsg.style.display = "none";
159
160            // Unlock Submit Button!
161            if (submitBtn) {
162                submitBtn.disabled = false;
163                submitBtn.style.opacity = "1";
164                submitBtn.style.cursor = "pointer";
165                submitBtn.title = "Submit Form";
166            }
167            return true;
168        } else {
169            container.setAttribute("data-step2-passed", "false");
170            if (step2Badge) {
171                step2Badge.className = "badge bg-secondary me-2";
172                step2Badge.textContent = "Step 2 of 2";
173            }
174            if (successAlert) successAlert.style.display = "none";
175            if (submitBtn) {
176                submitBtn.disabled = true;
177                submitBtn.style.opacity = "0.5";
178                submitBtn.style.cursor = "not-allowed";
179            }
180            return false;
181        }
182    }
183
184    function initAntiSpamProtection() {
185        var renderTime = (Date.now() / 1000).toString();
186        var forms = document.querySelectorAll("form");
187        var currentPath = (window.location.pathname || "").toLowerCase();
188
189        forms.forEach(function (form) {
190            if (form.getAttribute("role") === "search" || form.classList.contains("search-popup__form")) return;
191
192            // 1. Inject Hidden Render Timestamp (Background Protection)
193            if (!form.querySelector('input[name="form_render_ts"]')) {
194                var tsInput = document.createElement("input");
195                tsInput.type = "hidden";
196                tsInput.name = "form_render_ts";
197                tsInput.value = renderTime;
198                form.appendChild(tsInput);
199            }
200
201            // 2. Inject Invisible Honeypot Field (Background Protection)
202            if (!form.querySelector('input[name="hp_website_url"]')) {
203                var hpInput = document.createElement("input");
204                hpInput.type = "text";
205                hpInput.name = "hp_website_url";
206                hpInput.tabIndex = -1;
207                hpInput.autocomplete = "off";
208                hpInput.setAttribute("aria-hidden", "true");
209                hpInput.style.cssText = "position:absolute!important;left:-9999px!important;top:-9999px!important;opacity:0!important;height:0!important;width:0!important;z-index:-1!important;";
210                form.appendChild(hpInput);
211            }
212
213            // 3. Determine if 2-Step Verification UI should be active for this form
214            var isFooterForm = !!(form.closest('footer') || 
215                                  form.classList.contains('mc-form') || 
216                                  form.classList.contains('footer-one__newsletter-form-box') || 
217                                  form.classList.contains('subscribe-one__form') ||
218                                  form.id === 'mc-embedded-subscribe-form');
219
220            // Enable 2-step verification for:
221            // - Contact Us Page section (#myForm, /contact/)
222            // - Get in Touch Enquiry Modal (#popresetting, .modal)
223            var isContactOrGetInTouch = (form.id === "myForm" || 
224                                         form.id === "popresetting" || 
225                                         currentPath.indexOf("/contact") !== -1 || 
226                                         form.classList.contains("form-back") || 
227                                         form.closest(".contact-page") !== null || 
228                                         form.closest(".comment-form") !== null ||
229                                         form.closest(".modal") !== null);
230
231            var shouldAddTwoStepUI = !isFooterForm && isContactOrGetInTouch;
232
233            var securityBox = form.querySelector('.anti-spam-security-container');
234
235            if (!shouldAddTwoStepUI) {
236                if (securityBox) {
237                    securityBox.style.display = "none";
238                    securityBox.remove();
239                }
240                var submitBtn = form.querySelector('button[type="submit"], input[type="submit"]');
241                if (submitBtn) {
242                    submitBtn.disabled = false;
243                    submitBtn.style.opacity = "1";
244                    submitBtn.style.cursor = "pointer";
245                }
246                return;
247            }
248
249            // 4. Inject 2-Step Security Challenge Container for Contact Us / Get in Touch / Enquiry Modal
250            if (!securityBox) {
251                var submitBtn = form.querySelector('button[type="submit"], input[type="submit"]');
252                if (submitBtn) {
253                    securityBox = document.createElement("div");
254                    securityBox.className = "anti-spam-security-container p-3 border rounded bg-light mb-3";
255                    securityBox.style.cssText = "background:#f8fafc; border:1px solid #cbd5e1; border-radius:8px; margin-bottom:15px; text-align:left;";
256                    securityBox.innerHTML = 
257                        '<div class="d-flex align-items-center justify-content-between mb-2 pb-2 border-bottom" style="border-color:#e2e8f0!important;">' +
258                            '<span class="font-weight-bold text-dark" style="font-size:13px; font-weight:700; color:#0f172a;">' +
259                                '<i class="fas fa-shield-alt text-primary me-1" style="color:#0284c7;"></i> 2-Step Security Verification' +
260                            '</span>' +
261                            '<button type="button" class="btn btn-sm btn-link text-decoration-none p-0 refresh-all-btn" title="Refresh Security Verification" style="font-size:12px; color:#64748b;">' +
262                                '<i class="fas fa-sync-alt me-1"></i> Reset' +
263                            '</button>' +
264                        '</div>' +
265
266                        '<!-- Step 1: Security Question (Math Problem) -->' +
267                        '<div class="step1-box mb-2 p-2 rounded" style="background:#ffffff; border:1px solid #e2e8f0;">' +
268                            '<div class="d-flex align-items-center mb-1">' +
269                                '<span class="step1-status-badge badge bg-primary me-2" style="background:#0284c7!important; color:#ffffff; font-size:11px; padding:4px 8px;">Step 1 of 2</span>' +
270                                '<label class="form-label mb-0 font-weight-bold" style="font-size:12px; color:#1e293b; font-weight:600;">' +
271                                    'Security Question: <span class="math-question-text text-danger font-weight-bold" style="color:#e11d48; font-weight:700;"></span>' +
272                                '</label>' +
273                            '</div>' +
274                            '<input type="number" name="math_answer" class="form-control math-answer-input mt-1" placeholder="Enter calculation answer" required autocomplete="off" style="font-size:13px; height:36px; border-radius:6px;">' +
275                            '<input type="hidden" name="math_num1" class="math-num1-input">' +
276                            '<input type="hidden" name="math_num2" class="math-num2-input">' +
277                        '</div>' +
278
279                        '<!-- Step 2: Visual Security Code CAPTCHA (Unlocked after Step 1) -->' +
280                        '<div class="step2-box mb-2 p-2 rounded" style="display:none; background:#ffffff; border:1px solid #e2e8f0;">' +
281                            '<div class="d-flex align-items-center mb-2">' +
282                                '<span class="step2-status-badge badge bg-secondary me-2" style="font-size:11px; padding:4px 8px;">Step 2 of 2</span>' +
283                                '<label class="form-label mb-0 font-weight-bold" style="font-size:12px; color:#1e293b; font-weight:600;">' +
284                                    'Enter Security Code Below:' +
285                                '</label>' +
286                            '</div>' +
287                            '<div class="d-flex align-items-center justify-content-between mb-2 p-2 rounded" style="background:#0f172a; border:1px solid #334155;">' +
288                                '<span class="captcha-code-text" style="color:#38bdf8; font-weight:800; font-family:monospace; letter-spacing:4px; font-size:18px; user-select:none;"></span>' +
289                                '<span class="text-muted" style="font-size:11px; color:#94a3b8!important;">Case-Insensitive</span>' +
290                            '</div>' +
291                            '<input type="text" name="captcha_input" class="form-control captcha-input-field" placeholder="Type 5-character code" required autocomplete="off" style="font-size:13px; height:36px; border-radius:6px; text-transform:uppercase; letter-spacing:1px;">' +
292                            '<input type="hidden" name="captcha_expected" class="captcha-expected-input">' +
293                        '</div>' +
294
295                        '<div class="anti-spam-success-msg text-success mt-2 font-weight-bold" style="display:none; font-size:12px; color:#16a34a;">' +
296                            '<i class="fas fa-check-circle me-1"></i> Both security verifications passed! Submit button unlocked.' +
297                        '</div>' +
298
299                        '<div class="anti-spam-error-msg text-danger mt-2 font-weight-bold" style="display:none; font-size:12px; color:#dc2626;">' +
300                            '<i class="fas fa-exclamation-circle me-1"></i> <span class="error-text">Verification failed.</span>' +
301                        '</div>';
302
303                    submitBtn.parentNode.insertBefore(securityBox, submitBtn);
304                }
305            }
306
307            if (securityBox) {
308                resetSecurityChallenge(securityBox);
309
310                var refreshBtn = securityBox.querySelector('.refresh-all-btn');
311                if (refreshBtn) {
312                    refreshBtn.addEventListener("click", function (e) {
313                        e.preventDefault();
314                        resetSecurityChallenge(securityBox);
315                    });
316                }
317
318                // Step 1 Input Listener -> Auto-checks & unlocks Step 2 once solved!
319                var mathAnswerInput = securityBox.querySelector('.math-answer-input');
320                if (mathAnswerInput) {
321                    mathAnswerInput.addEventListener("input", function () {
322                        checkStep1(securityBox);
323                    });
324                }
325
326                // Step 2 Input Listener -> Auto-checks & unlocks Submit once matched!
327                var captchaInput = securityBox.querySelector('.captcha-input-field');
328                if (captchaInput) {
329                    captchaInput.addEventListener("input", function () {
330                        checkStep2(securityBox);
331                    });
332                }
333
334                // Form Submit Safeguard
335                if (!form.dataset.antiSpamInitialized) {
336                    form.dataset.antiSpamInitialized = "true";
337                    form.addEventListener("submit", function (e) {
338                        var step1Passed = checkStep1(securityBox);
339                        var step2Passed = checkStep2(securityBox);
340
341                        if (!step1Passed || !step2Passed) {
342                            e.preventDefault();
343                            e.stopPropagation();
344
345                            var errorMsg = securityBox.querySelector('.anti-spam-error-msg');
346                            var errorText = securityBox.querySelector('.error-text');
347
348                            if (errorMsg && errorText) {
349                                errorMsg.style.display = "block";
350                                if (!step1Passed) {
351                                    errorText.textContent = "Please solve Step 1 (Security Question) first.";
352                                    if (mathAnswerInput) mathAnswerInput.focus();
353                                } else {
354                                    errorText.textContent = "Please enter Step 2 (Security CAPTCHA Code).";
355                                    if (captchaInput) captchaInput.focus();
356                                }
357                            }
358                            return false;
359                        }
360                    }, true);
361                }
362            }
363        });
364    }
365
366    if (document.readyState === "loading") {
367        document.addEventListener("DOMContentLoaded", initAntiSpamProtection);
368    } else {
369        initAntiSpamProtection();
370    }
371})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.