// Hero Proof function detectBrowserOS() { const ua = navigator.userAgent; let browser = "Unknown", os = "Unknown"; if (/firefox/i.test(ua)) browser = "Firefox"; else if (/edg/i.test(ua)) browser = "Edge"; else if (/chrome|crios/i.test(ua) && !/edg/i.test(ua)) browser = "Chrome"; else if (/safari/i.test(ua) && !/chrome|crios|edg/i.test(ua)) browser = "Safari"; if (/windows nt 11/i.test(ua)) os = "Windows 11"; else if (/windows nt 10/i.test(ua)) os = "Windows 10"; else if (/mac os x/i.test(ua)) os = "macOS"; else if (/android/i.test(ua)) os = "Android"; else if (/iphone|ipad|ipod/i.test(ua)) os = "iOS"; else if (/linux/i.test(ua)) os = "Linux"; const resolution = `${window.screen.width}×${window.screen.height}`; return { browser, os, resolution }; } function maskIp(ip) { // IPv4 93.104.15.201 -> 93.104.15.x | IPv6: kürzen if (ip.includes(".")) { const parts = ip.split("."); parts[3] = "x"; return parts.join("."); } return ip.split(":").slice(0, 4).join(":") + ":…"; } async function setHeroProof() { const heroEl = document.getElementById('hero-proof'); try { const res = await fetch('/geoip.php'); if (!res.ok) throw new Error('API error'); const data = await res.json(); const { browser, os, resolution } = detectBrowserOS(); const city = data.city || "your city"; const country = data.country_name || "your country"; const ipMasked = data.ip ? maskIp(data.ip) : "—"; heroEl.innerHTML = ` You are currently located approximately in ${city}, ${country} (IP: ${data.ip}).
You are using the browser ${browser} under ${os}. Even your screen resolution of ${resolution} pixels is visible to us. `; } catch { const { browser, os, resolution } = detectBrowserOS(); heroEl.innerHTML = ` We couldn't load your location just now.
Your browser: ${browser} under ${os}, resolution ${resolution} pixels. `; } } // ==== IP & Location ==== async function fetchIPInfo() { const resultEl = document.getElementById('ip-result'); try { const res = await fetch('/geoip.php'); if (!res.ok) throw new Error('API error'); const data = await res.json(); // const hint = `Note: This location display is based on your IP address and is usually only accurate to within a few kilometres. // With GPS-enabled devices and location sharing, it may be accurate to within a few metres.`; resultEl.innerHTML = `

IP: ${data.ip}

Country: ${data.country_name} (${data.country})

Region: ${data.region || '—'}

City: ${data.city || '—'}

${data.org ? `

ISP: ${data.org}

` : ''}

Coordinates: ${data.latitude}, ${data.longitude}

`; renderIpMap(data.latitude, data.longitude, data.city); } catch (err) { resultEl.innerHTML = `Error: ${err.message}`; } } // RENDER IP MAP let ipMap; function renderIpMap(lat, lon, label) { const el = document.getElementById('ip-map'); if (!el || lat == null || lon == null) return; const latNum = Number(lat), lonNum = Number(lon); if (!isFinite(latNum) || !isFinite(lonNum)) return; if (!window.L) return; // Leaflet noch nicht geladen const center = [latNum, lonNum]; if (ipMap) { ipMap.setView(center, 10); if (ipMap._marker) { ipMap._marker.setLatLng(center).setPopupContent(label || "Approximately here"); } else { ipMap._marker = L.marker(center).addTo(ipMap).bindPopup(label || "Approximately here"); } return; } ipMap = L.map('ip-map', { zoomControl: false, attributionControl: true }).setView(center, 8); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap-Mitwirkende' }).addTo(ipMap); ipMap._marker = L.marker(center).addTo(ipMap).bindPopup(label || "Approximately here"); } // ==== Fingerprint ==== function generateFingerprint() { const fpEl = document.getElementById('fp-result'); const fingerprintData = [ { label: 'Browser', value: navigator.userAgent }, { label: 'Language', value: navigator.language }, { label: 'Operating System', value: navigator.platform }, { label: 'Screen', value: `${window.screen.width}×${window.screen.height} (DPR ${window.devicePixelRatio})` }, { label: 'Timezone', value: Intl.DateTimeFormat().resolvedOptions().timeZone }, { label: 'Cookies enabled?', value: navigator.cookieEnabled ? 'Ja' : 'Nein' }, { label: 'Do Not Track', value: navigator.doNotTrack === '1' ? 'Enabled' : 'Disabled' } ]; // Canvas Fingerprint (vereinfachtes Beispiel) const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); ctx.textBaseline = 'top'; ctx.font = "14px 'Arial'"; ctx.textBaseline = 'alphabetic'; ctx.fillStyle = '#f60'; ctx.fillRect(125,1,62,20); ctx.fillStyle = '#069'; ctx.fillText('privacy-check', 2, 15); ctx.fillStyle = 'rgba(102, 204, 0, 0.7)'; ctx.fillText('privacy-check', 4, 17); const canvasHash = hashCode(canvas.toDataURL()); fingerprintData.push({ label: 'Canvas Fingerprint', value: `${canvasHash} (Unique device identifier)` }); // Anzeige als Liste fpEl.innerHTML = ` `; } // Hilfsfunktion: String -> einfacher Hash function hashCode(str) { let hash = 0, i, chr; if (str.length === 0) return hash; for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); hash = ((hash << 5) - hash) + chr; hash |= 0; // 32bit int } return hash; } // ==== INIT ==== fetchIPInfo(); generateFingerprint(); setHeroProof(); let trackerData = {}; // 1. Tracker-Daten laden fetch('trackers_light.json') .then(res => res.json()) .then(data => { trackerData = data; // console.log(`✅ Tracker data loaded: ${Object.keys(trackerData).length} Domains`); }) .catch(err => { console.error("Error loading tracker data:", err); }); // 2. Button-Event document.getElementById('checkEmailBtn').addEventListener('click', () => { const resultEl = document.getElementById('emailResult'); resultEl.innerHTML = ''; const fileInput = document.getElementById('emailFile'); const textInput = document.getElementById('emailText').value.trim(); if (fileInput.files.length > 0) { const reader = new FileReader(); reader.onload = e => analyzeEmailHTML(e.target.result, resultEl); reader.readAsText(fileInput.files[0]); } else if (textInput) { analyzeEmailHTML(textInput, resultEl); } else { resultEl.innerHTML = `Please insert HTML or upload a file.`; } }); // 3. Analyse-Funktion function analyzeEmailHTML(html, outputEl) { if (!Object.keys(trackerData).length) { outputEl.innerHTML = `Tracker data not yet loaded.`; return; } const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); const found = new Set(); const trackers = []; // Bilder doc.querySelectorAll('img').forEach(img => { const src = cleanURL(img.src); if (src && isValidURL(src)) { const domain = extractDomain(src); if (trackerData[domain] && !found.has(domain)) { trackers.push({ type: 'Image', src, domain }); found.add(domain); } } }); // Links doc.querySelectorAll('a[href]').forEach(a => { const href = cleanURL(a.href); if (href && isValidURL(href)) { const domain = extractDomain(href); if (trackerData[domain] && !found.has(domain)) { trackers.push({ type: 'Link', src: href, domain }); found.add(domain); } } }); // Ergebnis if (trackers.length === 0) { outputEl.innerHTML = `No tracker domain found 🎉`; } else { outputEl.innerHTML = `

🔍 Tracker domains found:

${trackers.map((t, i) => { const info = trackerData[t.domain] || {}; const owner = info.owner || "Unknown"; const categories = (info.categories || []).join(", ") || "(not specified)"; const rowId = `trk-details-${i}`; return ` `; }).join('')}
Type Domain Owner Category Details
${t.type} ${t.domain} ${owner} ${categories}
`; } } // 4. Hilfsfunktionen function cleanURL(raw) { const match = raw?.match(/https?:\/\/[^\s"'<>]+/i); return match ? match[0] : ''; } function isValidURL(url) { try { const parsed = new URL(url); return /^https?:$/.test(parsed.protocol) && parsed.hostname.includes('.'); } catch { return false; } } function extractDomain(url) { try { const hostname = new URL(url).hostname.toLowerCase(); const parts = hostname.split('.'); return parts.slice(-2).join('.'); // z.B. sub.domain.com → domain.com } catch { return ''; } } // mobile (function () { const btn = document.getElementById('nav-toggle'); const menu = document.getElementById('nav-menu'); const iconOpen = document.getElementById('nav-icon-open'); const iconClose = document.getElementById('nav-icon-close'); if (!btn || !menu) return; btn.addEventListener('click', () => { const isOpen = !menu.classList.contains('hidden'); menu.classList.toggle('hidden'); btn.setAttribute('aria-expanded', String(!isOpen)); iconOpen.classList.toggle('hidden'); iconClose.classList.toggle('hidden'); }); // optional: Menü schließen, wenn Link geklickt wurde menu.querySelectorAll('a').forEach(a => { a.addEventListener('click', () => { if (!menu.classList.contains('hidden')) { menu.classList.add('hidden'); btn.setAttribute('aria-expanded', 'false'); iconOpen.classList.remove('hidden'); iconClose.classList.add('hidden'); } }); }); })();