// Configuration and Messages const debugEnabled = false const mouseDebugEnabled = false const zsrCheckEnabled = false const interactionThreshold = 15 // Time in seconds const interactionCountThreshold = 5 // Number of interactions let botDetected = false const messages = { de: { required: 'Bitte füllen Sie dieses Feld aus', email: 'Bitte geben Sie eine gültige E-Mail-Adresse ein', success: 'Die Bestellung wurde erfolgreich übermittelt!', thankyou: 'Vielen Dank für Ihre Bestellung!', zsrTooltip: 'Bitte geben Sie eine gültige ZSR-Nummer, oder "beantragt" ein.', captcha: 'Geben Sie den angezeigten Captcha-Code ein', captchaButton: 'Überprüfen', }, fr: { required: 'Veuillez remplir ce champ', email: 'Veuillez saisir une adresse email valide', success: 'La commande a bien été envoyée!', thankyou: 'Merci de votre commande!', zsrTooltip: 'Veuillez saisir une ZSR-Nummer valide, ou indiquer "demandé".', captcha: 'Entrez le code Captcha affiché', captchaButton: 'Vérifier', }, } // DOM Selectors const debugLabel = document.createElement('div') const submitButton = document.getElementById('bestellformular-btn') const form = document.querySelector('form#bestellformular') const notification = document.getElementById('notification') const zsrTooltip = document.getElementById('zsr-tooltip') const honeypotInput1 = document.getElementById('age') const honeypotInput2 = document.getElementById('hobbies') const verifyEmailInput = document.getElementById('verify_email') const emailInput = document.getElementById('email') const textInputs = document.querySelectorAll('input[type="text"]') const captcha = document.querySelectorAll('.captcha') const captchaInput = document.querySelectorAll('.captcha-input') const captchaVerifyButton = document.querySelectorAll('.captcha-verify') const botBadge = document.createElement('div') if (debugEnabled) { botBadge.className = 'bot-badge' document.body.appendChild(botBadge) botBadge.setAttribute( 'style', 'position: fixed; top: 0; right: 0; z-index: 9999; background-color: red; color: white; font-weight: bold; height:20px; width:20px' ) } // Utility variables let startTime = Date.now() let interactionCount = 0 let userInteracted = false let lastInteractionTime = null const mousePositions = [] const interactionTimes = [] let isStraightLine = true // Utility functions function log(thing) { console.log(thing) } function getCurrentLangMessages() { log(messages[document.documentElement.lang.split('-')[0]]) return messages[document.documentElement.lang.split('-')[0]] } function setUserInteracted() { const currentTime = Date.now() if (lastInteractionTime) { const timeDiff = (currentTime - lastInteractionTime) / 1000 // time in seconds interactionTimes.push(timeDiff) log('Time since last interaction: ' + timeDiff + ' seconds') } lastInteractionTime = currentTime userInteracted = true interactionCount++ checkForBotBehavior() } function handleMouseMove(event) { mousePositions.push({ x: event.clientX, y: event.clientY }) if (debugEnabled && mouseDebugEnabled) log('Mouse Position:', { x: event.clientX, y: event.clientY }) if (mousePositions.length > 2) { const len = mousePositions.length const { x: x1, y: y1 } = mousePositions[len - 3] const { x: x2, y: y2 } = mousePositions[len - 2] const { x: x3, y: y3 } = mousePositions[len - 1] // Calculate the area of the triangle formed by three consecutive points const area = 0.5 * Math.abs(x1 * y2 + x2 * y3 + x3 * y1 - y1 * x2 - y2 * x3 - y3 * x1) if (debugEnabled && mouseDebugEnabled) log('Triangle Area:', area) if (area > 0.5) { // Threshold for detecting non-straight line, adjust as needed isStraightLine = false if (debugEnabled && mouseDebugEnabled) log('Detected non-straight line movement.') } } } function validateZSRNumber(form) { const zsrNumber = form.elements['zsr_nummer'].value return /^\d+$|^beantragt$/i.test(zsrNumber) } function checkForBotBehavior() { let timeSpent = (Date.now() - startTime) / 1000 botDetected = !userInteracted || interactionCount === 0 || timeSpent < interactionThreshold || (isStraightLine && mousePositions.length > 0) || honeypotInput1.value !== '' || honeypotInput2.value !== '' || verifyEmailInput.value !== '' if (debugEnabled) if (!botDetected) { botBadge.style.backgroundColor = 'green' } else { botBadge.style.backgroundColor = 'red' } console.log( 'Bot Detected: ' + botDetected + ' userInteracted:' + userInteracted + ' interactionCount:' + interactionCount + ' timeSpent:' + timeSpent + ' isStraightLine:' + isStraightLine + ' mousePositions:' + mousePositions.length + ' honeypotInput1:' + honeypotInput1.value + ' honeypotInput2:' + honeypotInput2.value + ' verifyEmailInput:' + verifyEmailInput.value ) } function handleSubmit(e) { e.preventDefault() const currentMessages = getCurrentLangMessages() if (zsrCheckEnabled && !validateZSRNumber(form)) { zsrTooltip.className = 'input-tooltip visible' zsrTooltip.setAttribute('data-tooltip', currentMessages.zsrTooltip) zsrTooltip.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest', }) return } checkForBotBehavior() const data = new FormData(form) data.append('tra', botDetected) fetch(form.action, { method: 'POST', mode: 'cors', body: data, }) .then((response) => { if (!response.ok) throw new Error('Network response was not ok') return response.json() }) .then((data) => { submitButton.disabled = true submitButton.innerHTML = ` ` setTimeout(() => { // if data.success is true, show a success message if (data.success) { submitButton.style.display = 'none' notification.innerHTML = `${currentMessages.thankyou}` notification.className = 'bg-green-500 text-white px-4 py-2 rounded block' } else { submitButton.style.display = 'none' notification.textContent = data.message notification.className = 'bg-blue-500 text-white px-4 py-2 rounded block' } }, 3000) }) .catch((error) => { submitButton.style.display = 'none' notification.textContent = 'Fehler beim Senden der Nachricht.' notification.className = 'bg-blue-500 text-white px-4 py-2 rounded block' console.error(error) }) } function init() { // Event Listeners document.addEventListener('mousedown', setUserInteracted) document.addEventListener('touchstart', setUserInteracted) document.addEventListener('keydown', setUserInteracted) document.addEventListener('mousemove', handleMouseMove) form.addEventListener('submit', handleSubmit) emailInput.addEventListener('invalid', () => { const currentMessages = getCurrentLangMessages() emailInput.setCustomValidity(currentMessages.email) }) textInputs.forEach((input) => { input.addEventListener('invalid', () => { const currentMessages = getCurrentLangMessages() input.setCustomValidity(currentMessages.required) }) }) log('captchaInput', captchaInput) captchaInput?.forEach((input) => { input.setAttribute('placeholder', getCurrentLangMessages().captcha) }) captchaVerifyButton?.forEach((button) => { button.textContent = getCurrentLangMessages().captchaButton }) } document.addEventListener('DOMContentLoaded', function () { init() })