PageSourceSearch

https://cdnmediaassets.eurofins.com/eurofins-corporate/scripts/umbracoForms.js?v=13.9.8

js eurofins.com collected 2026-10-09 21:46:49 UTC 10,143 bytes, 263 lines download raw bytes

1// Client-side Validation for XSS Vulnerabilities
2document.addEventListener('DOMContentLoaded', function () {
3        // Wait for Umbraco Forms scripts to initialize
4        setTimeout(function () {
5            // Find all Umbraco forms on the page
6            var umbracoForms = document.querySelectorAll('form[id^="form"]');
7
8            umbracoForms.forEach(function (form) {
9                // Add submission validation as a fallback security measure
10                form.addEventListener('submit', function (event) {
11                    // Only validate if not navigating between pages
12                    var isNavigating = event.submitter && (event.submitter.getAttribute('data-form-navigate') === 'prev');
13                    if (!isNavigating && !validateFormAgainstXSS(form)) {
14                        event.preventDefault();
15                        showXSSWarning(form);
16                    }
17                });
18
19                // Find all text inputs and textareas in the form
20                var textInputs = form.querySelectorAll('input[type="text"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], textarea');
21
22                textInputs.forEach(function (input) {
23                    // Prevent pasting of HTML content
24                    input.addEventListener('paste', function (e) {
25                        // Get pasted content
26                        var pastedText = (e.clipboardData || window.clipboardData).getData('text');
27
28                        // Sanitize the pasted content
29                        var sanitizedText = sanitizeInput(pastedText);
30
31                        // If the content was changed (contained HTML), prevent default and insert sanitized version
32                        if (sanitizedText !== pastedText) {
33                            e.preventDefault();
34
35                            // Insert at cursor position or replace selection
36                            var startPos = this.selectionStart;
37                            var endPos = this.selectionEnd;
38
39                            this.value = this.value.substring(0, startPos) +
40                                sanitizedText +
41                                this.value.substring(endPos);
42
43                            // Set cursor position after inserted text
44                            this.selectionStart = this.selectionEnd = startPos + sanitizedText.length;
45                        }
46                    });
47
48                    // Block HTML characters as they are typed
49                    input.addEventListener('keypress', function (e) {
50                        // Block < and > characters completely
51                        if (e.key === '<' || e.key === '>') {
52                            e.preventDefault();
53                            showInputWarning(this);
54                            return false;
55                        }
56                    });
57
58                    // Check input after any change (for cases not caught by keypress)
59                    input.addEventListener('input', function () {
60                        // If HTML-like content is detected, immediately sanitize it
61                        if (containsHTMLTags(this.value)) {
62                            var cursorPos = this.selectionStart;
63                            var oldLength = this.value.length;
64
65                            // Sanitize the input
66                            this.value = sanitizeInput(this.value);
67
68                            // Adjust cursor position if content length changed
69                            var newLength = this.value.length;
70                            if (oldLength !== newLength) {
71                                this.selectionStart = this.selectionEnd = Math.max(0, cursorPos - (oldLength - newLength));
72                            }
73
74                            showInputWarning(this);
75                        }
76                    });
77                });
78            });
79        }, 500); // Small delay to ensure Umbraco Forms scripts have loaded
80});
81
82    // Check if a string contains HTML tags
83    function containsHTMLTags(text) {
84    // Basic pattern to detect HTML tags
85    var htmlPattern = /<\/?[a-z][\s\S]*>/i;
86
87    // Additional patterns to detect other potentially harmful content
88    var otherSuspiciousPatterns = [
89    /javascript\s*:/i,
90    /on\w+\s*=/i,
91    /data\s*:/i
92    ];
93
94    if (htmlPattern.test(text)) {
95        return true;
96    }
97
98    for (var i = 0; i < otherSuspiciousPatterns.length; i++) {
99        if (otherSuspiciousPatterns[i].test(text)) {
100            return true;
101        }
102    }
103
104    return false;
105}
106
107    // Function to sanitize a string by removing HTML tags and potentially harmful content
108    function sanitizeInput(text) {
109    if (typeof text !== 'string') {
110        return '';
111    }
112
113    // Remove < and > characters to prevent any HTML
114        text = text.replace(/</g, '').replace(/>/g, '');
115
116    // Remove script tags and their content (just in case)
117    text = text.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
118
119    // Remove event handlers
120    text = text.replace(/on\w+\s*=\s*["']?[^"']*["']?/gi, '');
121
122    // Remove javascript: protocol
123    text = text.replace(/javascript\s*:/gi, '');
124
125    // Remove data: URIs
126    text = text.replace(/data\s*:[^\s]*/gi, '');
127
128    return text;
129}
130
131    // Show temporary warning tooltip near input
132    function showInputWarning(input) {
133    var warningId = input.id + '_warning';
134    var existingWarning = document.getElementById(warningId);
135
136    if (!existingWarning) {
137        var warningElem = document.createElement('div');
138    warningElem.id = warningId;
139    warningElem.className = 'xss-warning-tooltip';
140    warningElem.textContent = 'HTML tags are not allowed';
141    warningElem.style.position = 'absolute';
142    warningElem.style.zIndex = '1000';
143    warningElem.style.backgroundColor = '#dc3545';
144    warningElem.style.color = 'white';
145    warningElem.style.padding = '5px 10px';
146    warningElem.style.borderRadius = '3px';
147    warningElem.style.fontSize = '15px';
148
149    // Position tooltip near the input
150    var rect = input.getBoundingClientRect();
151    var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
152    var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
153
154    warningElem.style.top = (rect.top + scrollTop - 30) + 'px';
155    warningElem.style.left = (rect.left + scrollLeft) + 'px';
156
157    document.body.appendChild(warningElem);
158
159    // Remove after 2 seconds
160    setTimeout(function() {
161            if (warningElem.parentNode) {
162        warningElem.parentNode.removeChild(warningElem);
163            }
164        }, 2000);
165    }
166}
167
168    // Fallback validation for the entire form
169    function validateFormAgainstXSS(form) {
170    var textInputs = form.querySelectorAll('input[type="text"], input[type="email"], input[type="url"], input[type="search"], input[type="tel"], textarea');
171    var isValid = true;
172
173    textInputs.forEach(function(input) {
174        // Skip validation for hidden fields or fields in hidden containers
175        if (input.closest('.umbraco-forms-hidden') ||
176    input.type === 'hidden' ||
177    input.style.display === 'none') {
178            return;
179        }
180
181    if (containsHTMLTags(input.value)) {
182        // Auto-sanitize on submission attempt
183        input.value = sanitizeInput(input.value);
184    isValid = false;
185        }
186    });
187
188    return isValid;
189}
190
191    // Show a warning message at the top of the form
192    function showXSSWarning(form) {
193    // Create validation summary if it doesn't exist
194    var summaryId = 'xss_validation_summary';
195    var existingSummary = document.getElementById(summaryId);
196
197    if (!existingSummary) {
198        var validationSummary = document.createElement('div');
199    validationSummary.id = summaryId;
200    validationSummary.className = 'validation-summary-errors alert alert-danger';
201    validationSummary.setAttribute('role', 'alert');
202
203    var message = document.createElement('p');
204    message.textContent = 'HTML tags and potentially unsafe content have been removed from your form inputs.';
205
206    validationSummary.appendChild(message);
207
208    // Insert at the top of the form
209    form.insertBefore(validationSummary, form.firstChild);
210
211    // Scroll to the validation summary
212    validationSummary.scrollIntoView({behavior: 'smooth', block: 'start' });
213
214    // Remove after 4 seconds
215    setTimeout(function() {
216            if (validationSummary.parentNode) {
217        validationSummary.parentNode.removeChild(validationSummary);
218            }
219        }, 4000);
220    }
221}
222
223//Remove 'form-control' from all Rich Text Editors
224document.addEventListener("DOMContentLoaded", function() {
225    // 1. Only run on an Umbraco Forms page
226    if (!document.querySelector('.umbraco-forms-page')) return;
227
228    // 2. Grab all richtext wrappers (may be zero)
229    var rteWrappers = document.querySelectorAll('.richtext');
230    if (rteWrappers.length === 0) return;  // nothing to do
231
232    // 3. For each wrapper, remove 'form-control' from any descendants
233    rteWrappers.forEach(function(wrapper) {
234        wrapper.querySelectorAll('.form-control').forEach(function (el) {
235            el.classList.remove('form-control');
236        });
237    });
238});
239
240document.addEventListener('DOMContentLoaded', function () {
241    // Find all select elements within custom-select containers
242    const selects = document.querySelectorAll('.custom-select .form-control');
243
244    // Only proceed if there are matching elements
245    if (selects.length > 0) {
246        selects.forEach(function (select) {
247            // Function to check if the select has a non-empty value
248            function checkSelectValue(select) {
249                if (select.value === '') {
250                    select.classList.remove('has-value');
251                } else {
252                    select.classList.add('has-value');
253                }
254            }
255            // Check initial state when page loads
256            checkSelectValue(select);
257            // Add change event listener
258            select.addEventListener('change', function () {
259                checkSelectValue(this);
260            });
261        });
262    }
263});

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.