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.