SpyScan

发现网站上的跟踪脚本、指纹识别和监控技术。

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         SpyScan
// @namespace    https://greasyfork.org/fr/users/1451802
// @version      2.0
// @description  Uncover tracking scripts, fingerprinting, and surveillance tactics lurking on the websites you visit
// @description:de Untersuche Websites auf Tracking-Skripte, Fingerprinting und Überwachungsmethoden.
// @description:es Descubre scripts de seguimiento, técnicas de huellas digitales y tácticas de vigilancia en las páginas web que visitas.
// @description:fr Détecte les scripts de suivi, le fingerprinting et les techniques de surveillance cachées sur les sites que vous visitez.
// @description:it Scopri script di tracciamento, tecniche di fingerprinting e metodi di sorveglianza sui siti web che visiti.
// @description:ru Раскрывает трекинговые скрипты, отпечатки браузера и методы слежки на посещаемых сайтах.
// @description:zh-CN 发现网站上的跟踪脚本、指纹识别和监控技术。
// @description:zh-TW 發現網站上的追蹤腳本、指紋辨識和監控技術。
// @description:ja 訪問したサイトに潜むトラッキングスクリプト、フィンガープリント、監視技術を検出。
// @description:ko 방문한 웹사이트에서 추적 스크립트, 브라우저 지문, 감시 기술을 찾아냅니다.
// @author       NormalRandomPeople (https://github.com/NormalRandomPeople)
// @match        *://*/*
// @grant        GM_addStyle
// @license      MIT
// @icon         https://www.svgrepo.com/show/360090/analyse.svg
// @compatible      chrome
// @compatible      firefox
// @compatible      opera
// @compatible      edge
// @compatible      brave
// @run-at document-end
// @noframes
// ==/UserScript==

/* jshint esversion: 8 */

(function() {
    'use strict';

    console.log('[Privacy Audit] Script loaded successfully!');

    let detectedETags = [];
    let detectedIPGeolocationRequests = [];
    let detectedWebRTCLeaks = [];
    let detectedCanvasFingerprinting = [];
    let detectedWebGLFingerprinting = [];
    let detectedAudioFingerprinting = [];
    let detectedFontFingerprinting = [];
    let detectedScreenFingerprinting = [];
    let detectedBatteryFingerprinting = [];
    let detectedMediaDevices = [];
    let detectedSensors = [];
    let detectedServiceWorkers = [];
    let detectedCacheAPI = [];
    let detectedWebSQL = [];
    let detectedFileSystem = [];
    let detectedThirdPartyIframes = [];

    (function() {
        const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
        const originalToBlob = HTMLCanvasElement.prototype.toBlob;
        const originalGetImageData = CanvasRenderingContext2D.prototype.getImageData;

        HTMLCanvasElement.prototype.toDataURL = function(...args) {
            const stack = new Error().stack;
            detectedCanvasFingerprinting.push({
                method: 'toDataURL',
                timestamp: Date.now(),
                stack: stack
            });
            console.log('[Privacy Audit] Canvas fingerprinting detected: toDataURL() called');
            return originalToDataURL.apply(this, args);
        };

        HTMLCanvasElement.prototype.toBlob = function(...args) {
            const stack = new Error().stack;
            detectedCanvasFingerprinting.push({
                method: 'toBlob',
                timestamp: Date.now(),
                stack: stack
            });
            console.log('[Privacy Audit] Canvas fingerprinting detected: toBlob() called');
            return originalToBlob.apply(this, args);
        };

        CanvasRenderingContext2D.prototype.getImageData = function(...args) {
            const stack = new Error().stack;
            detectedCanvasFingerprinting.push({
                method: 'getImageData',
                timestamp: Date.now(),
                stack: stack
            });
            console.log('[Privacy Audit] Canvas fingerprinting detected: getImageData() called');
            return originalGetImageData.apply(this, args);
        };
    })();

    (function() {
        const originalGetParameter = WebGLRenderingContext.prototype.getParameter;
        const sensitiveParams = [
            'VENDOR', 'RENDERER', 'VERSION', 'SHADING_LANGUAGE_VERSION',
            37445, 37446, // UNMASKED_VENDOR_WEBGL, UNMASKED_RENDERER_WEBGL
        ];

        WebGLRenderingContext.prototype.getParameter = function(param) {
            const paramName = typeof param === 'number' ? param : this[param];
            if (sensitiveParams.includes(param) || sensitiveParams.includes(paramName)) {
                const stack = new Error().stack;
                detectedWebGLFingerprinting.push({
                    parameter: param,
                    timestamp: Date.now(),
                    stack: stack
                });
                console.log('[Privacy Audit] WebGL fingerprinting detected: getParameter(' + param + ') called');
            }
            return originalGetParameter.apply(this, arguments);
        };

        if (window.WebGL2RenderingContext) {
            const originalGetParameter2 = WebGL2RenderingContext.prototype.getParameter;
            WebGL2RenderingContext.prototype.getParameter = function(param) {
                const paramName = typeof param === 'number' ? param : this[param];
                if (sensitiveParams.includes(param) || sensitiveParams.includes(paramName)) {
                    const stack = new Error().stack;
                    detectedWebGLFingerprinting.push({
                        parameter: param,
                        timestamp: Date.now(),
                        stack: stack
                    });
                    console.log('[Privacy Audit] WebGL2 fingerprinting detected: getParameter(' + param + ') called');
                }
                return originalGetParameter2.apply(this, arguments);
            };
        }
    })();

    (function() {
        const OriginalAudioContext = window.AudioContext || window.webkitAudioContext;
        if (OriginalAudioContext) {
            window.AudioContext = function(...args) {
                const stack = new Error().stack;
                detectedAudioFingerprinting.push({
                    method: 'AudioContext created',
                    timestamp: Date.now(),
                    stack: stack
                });
                console.log('[Privacy Audit] AudioContext fingerprinting detected: AudioContext created');
                return new OriginalAudioContext(...args);
            };

            if (window.webkitAudioContext) {
                window.webkitAudioContext = window.AudioContext;
            }
        }
    })();

    (function() {
        const originalMeasureText = CanvasRenderingContext2D.prototype.measureText;
        let measureTextCount = 0;

        CanvasRenderingContext2D.prototype.measureText = function(...args) {
            measureTextCount++;
            if (measureTextCount > 10) {
                const stack = new Error().stack;
                detectedFontFingerprinting.push({
                    method: 'measureText',
                    count: measureTextCount,
                    timestamp: Date.now(),
                    stack: stack
                });
                console.log('[Privacy Audit] Font fingerprinting detected: measureText() called ' + measureTextCount + ' times');
                measureTextCount = 0;
            }
            return originalMeasureText.apply(this, args);
        };
    })();

    (function() {
        const screenProps = ['width', 'height', 'availWidth', 'availHeight', 'colorDepth', 'pixelDepth'];
        let screenAccessCount = 0;

        screenProps.forEach(prop => {
            const originalDescriptor = Object.getOwnPropertyDescriptor(Screen.prototype, prop) ||
                                      Object.getOwnPropertyDescriptor(window.screen, prop);
            if (originalDescriptor && originalDescriptor.get) {
                Object.defineProperty(Screen.prototype, prop, {
                    get: function() {
                        screenAccessCount++;
                        if (screenAccessCount > 5) {
                            const stack = new Error().stack;
                            detectedScreenFingerprinting.push({
                                property: prop,
                                timestamp: Date.now(),
                                stack: stack
                            });
                            console.log('[Privacy Audit] Screen fingerprinting detected: screen.' + prop + ' accessed');
                            screenAccessCount = 0;
                        }
                        return originalDescriptor.get.call(this);
                    }
                });
            }
        });
    })();

    if (navigator.getBattery) {
        const originalGetBattery = navigator.getBattery;
        navigator.getBattery = function(...args) {
            const stack = new Error().stack;
            detectedBatteryFingerprinting.push({
                method: 'getBattery',
                timestamp: Date.now(),
                stack: stack
            });
            console.log('[Privacy Audit] Battery API fingerprinting detected');
            return originalGetBattery.apply(this, args);
        };
    }

    if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
        const originalEnumerateDevices = navigator.mediaDevices.enumerateDevices;
        navigator.mediaDevices.enumerateDevices = function(...args) {
            detectedMediaDevices.push({
                method: 'enumerateDevices',
                timestamp: Date.now()
            });
            console.log('[Privacy Audit] Media devices enumeration detected');
            return originalEnumerateDevices.apply(this, args);
        };
    }

    (function() {
        const sensorTypes = ['Accelerometer', 'Gyroscope', 'Magnetometer', 'AbsoluteOrientationSensor', 'RelativeOrientationSensor'];
        sensorTypes.forEach(sensorType => {
            if (window[sensorType]) {
                const OriginalSensor = window[sensorType];
                window[sensorType] = function(...args) {
                    detectedSensors.push({
                        type: sensorType,
                        timestamp: Date.now()
                    });
                    console.log('[Privacy Audit] Sensor access detected: ' + sensorType);
                    return new OriginalSensor(...args);
                };
            }
        });

        if (window.DeviceOrientationEvent) {
            window.addEventListener('deviceorientation', function() {
                if (detectedSensors.filter(s => s.type === 'deviceorientation').length === 0) {
                    detectedSensors.push({
                        type: 'deviceorientation',
                        timestamp: Date.now()
                    });
                    console.log('[Privacy Audit] Device orientation tracking detected');
                }
            }, true);
        }

        if (window.DeviceMotionEvent) {
            window.addEventListener('devicemotion', function() {
                if (detectedSensors.filter(s => s.type === 'devicemotion').length === 0) {
                    detectedSensors.push({
                        type: 'devicemotion',
                        timestamp: Date.now()
                    });
                    console.log('[Privacy Audit] Device motion tracking detected');
                }
            }, true);
        }
    })();

    if (navigator.serviceWorker) {
        const originalRegister = navigator.serviceWorker.register;
        navigator.serviceWorker.register = function(...args) {
            detectedServiceWorkers.push({
                url: args[0],
                timestamp: Date.now()
            });
            console.log('[Privacy Audit] Service Worker registered: ' + args[0]);
            return originalRegister.apply(this, args);
        };
    }

    if (window.caches) {
        const originalCachesOpen = caches.open;
        caches.open = function(...args) {
            detectedCacheAPI.push({
                cacheName: args[0],
                timestamp: Date.now()
            });
            console.log('[Privacy Audit] Cache API usage detected: ' + args[0]);
            return originalCachesOpen.apply(this, args);
        };
    }

    if (window.openDatabase) {
        const originalOpenDatabase = window.openDatabase;
        window.openDatabase = function(...args) {
            detectedWebSQL.push({
                dbName: args[0],
                timestamp: Date.now()
            });
            console.log('[Privacy Audit] WebSQL usage detected: ' + args[0]);
            return originalOpenDatabase.apply(this, args);
        };
    }

    if (window.webkitRequestFileSystem) {
        const originalRequestFileSystem = window.webkitRequestFileSystem;
        window.webkitRequestFileSystem = function(...args) {
            detectedFileSystem.push({
                type: args[0],
                timestamp: Date.now()
            });
            console.log('[Privacy Audit] FileSystem API usage detected');
            return originalRequestFileSystem.apply(this, args);
        };
    }

    const ipGeoServices = [
        "ipinfo.io", "ip-api.com", "ipgeolocation.io", "geoip-db.com",
        "freegeoip.app", "ip2location.com", "extreme-ip-lookup.com",
        "ip-geolocation.whoisxmlapi.com", "ipligence.com", "bigdatacloud.com",
        "maxmind.com", "db-ip.com", "ipinfodb.com", "ipdata.co",
        "abstractapi.com", "ipapi.com", "ipstack.com", "geo.ipify.org",
        "ipwhois.io", "ipregistry.co", "telize.com", "geoplugin.com"
    ];

    const originalFetch = window.fetch;
    window.fetch = async function(...args) {
        let reqUrl = "";
        if (typeof args[0] === "string") {
            reqUrl = args[0];
        } else if (args[0] instanceof Request) {
            reqUrl = args[0].url;
        }
        if (ipGeoServices.some(domain => reqUrl.includes(domain))) {
            detectedIPGeolocationRequests.push({ url: reqUrl });
        }
        const response = await originalFetch.apply(this, args);
        const responseClone = response.clone();
        try {
            const etag = responseClone.headers.get("ETag");
            if (etag) {
                detectedETags.push({
                    url: responseClone.url,
                    etag: etag
                });
            }
        } catch (err) {
            console.warn("ETag header could not be read:", err);
        }
        return response;
    };

    const originalXHROpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function(...args) {
        let reqUrl = args[1];
        if (ipGeoServices.some(domain => reqUrl.includes(domain))) {
            detectedIPGeolocationRequests.push({ url: reqUrl });
        }
        this.addEventListener("readystatechange", function() {
            if (this.readyState === 4) {
                try {
                    const etag = this.getResponseHeader("ETag");
                    if (etag) {
                        detectedETags.push({
                            url: this.responseURL,
                            etag: etag
                        });
                    }
                } catch (err) {
                    console.warn("ETag header could not be read from XHR:", err);
                }
            }
        });
        return originalXHROpen.apply(this, args);
    };

    let scanButton = document.createElement("button");
    scanButton.id = "aptScanButton";
    scanButton.innerHTML = `
        <svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="display: block; margin: 0 auto;">
            <path d="M21 21L15 15M17 10C17 13.866 13.866 17 10 17C6.13401 17 3 13.866 3 10C3 6.13401 6.13401 3 10 3C13.866 3 17 6.13401 17 10Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M10 7V10L12 12" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        </svg>
    `;
    scanButton.style.cssText = "position: fixed !important; bottom: 10px !important; left: 10px !important; padding: 15px 20px !important; border: none !important; background-color: black !important; color: #fff !important; border-radius: 10px !important; cursor: pointer !important; z-index: 2147483647 !important; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3) !important; transition: background-color 0.3s, transform 0.3s !important; font-family: Arial, sans-serif !important; font-size: 18px !important; line-height: 1 !important; text-align: center !important; min-width: auto !important; min-height: auto !important; max-width: none !important; max-height: none !important; margin: 0 !important;";

    scanButton.addEventListener("mouseover", function() {
        scanButton.style.backgroundColor = "#333";
        scanButton.style.transform = "scale(1.05)";
    });
    scanButton.addEventListener("mouseout", function() {
        scanButton.style.backgroundColor = "black";
        scanButton.style.transform = "scale(1)";
    });

    document.body.appendChild(scanButton);

    let auditWindow = document.createElement("div");
    auditWindow.id = "aptAuditWindow";
    auditWindow.style.cssText = "display: none !important; position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; background-color: rgba(0, 0, 0, 0.7) !important; color: #fff !important; font-family: Arial, sans-serif !important; overflow: auto !important; padding: 20px !important; z-index: 2147483646 !important; box-sizing: border-box !important; margin: 0 !important; border: none !important;";

    let windowContent = document.createElement("div");
    windowContent.className = "aptWindowContent";
    windowContent.style.cssText = "max-width: 800px !important; margin: 50px auto !important; background-color: #333 !important; border-radius: 8px !important; padding: 20px !important; box-shadow: 0 0 20px rgba(0, 0, 0, 0.5) !important; overflow-y: auto !important; max-height: 80% !important; box-sizing: border-box !important; color: #fff !important; font-family: Arial, sans-serif !important; font-size: 16px !important; line-height: 1.5 !important;";

    auditWindow.appendChild(windowContent);
    document.body.appendChild(auditWindow);

    auditWindow.addEventListener("click", function(event) {
        if (event.target === auditWindow) {
            auditWindow.style.display = "none";
        }
    });

    GM_addStyle(`
        #aptAuditWindow * {
            box-sizing: border-box !important;
            font-family: Arial, sans-serif !important;
            color: #fff !important;
            margin: 0 !important;
            padding: 0 !important;
            border: none !important;
            background: transparent !important;
            text-decoration: none !important;
            text-transform: none !important;
            letter-spacing: normal !important;
            word-spacing: normal !important;
            line-height: 1.5 !important;
        }

        #aptAuditWindow .aptWindowContent {
            max-width: 800px !important;
            margin: 50px auto !important;
            background-color: #333 !important;
            border-radius: 8px !important;
            padding: 20px !important;
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5) !important;
            overflow-y: auto !important;
            max-height: 80% !important;
        }

        #aptAuditWindow .aptWindowContent h2 {
            text-align: center !important;
            margin-bottom: 20px !important;
            margin-top: 0 !important;
            font-size: 1.8em !important;
            font-weight: bold !important;
            padding: 0 !important;
        }

        #aptAuditWindow .aptWindowContent p {
            font-size: 1em !important;
            line-height: 1.5 !important;
            margin: 10px 0 !important;
            padding: 0 !important;
        }

        #aptAuditWindow .aptWindowContent ul {
            list-style-type: none !important;
            padding: 0 !important;
            margin: 0 !important;
        }

        #aptAuditWindow .aptWindowContent li {
            background-color: #444 !important;
            padding: 10px !important;
            margin: 5px 0 !important;
            border-radius: 5px !important;
            word-wrap: break-word !important;
            position: relative !important;
            display: block !important;
        }

        #aptAuditWindow .aptTitle {
            font-weight: bold !important;
            font-family: Arial, sans-serif !important;
            color: #fff !important;
        }

        #aptAuditWindow .aptSectionTitle {
            font-size: 1.3em !important;
            font-weight: bold !important;
            margin-bottom: 10px !important;
            margin-top: 20px !important;
            padding-bottom: 5px !important;
            padding-top: 0 !important;
            padding-left: 0 !important;
            padding-right: 0 !important;
            border-bottom: 2px solid #666 !important;
            color: #fff !important;
            display: block !important;
        }

        #aptAuditWindow .aptDangerLevel {
            font-weight: bold !important;
            font-size: 1.1em !important;
        }

        #aptAuditWindow .aptDangerLevelLow {
            color: #28A745 !important;
        }

        #aptAuditWindow .aptDangerLevelMedium {
            color: #FFA500 !important;
        }

        #aptAuditWindow .aptDangerLevelHigh {
            color: #FF4C4C !important;
        }

        #aptAuditWindow .aptloading-spinner {
            border: 4px solid rgba(255, 255, 255, 0.3) !important;
            border-top: 4px solid #fff !important;
            border-radius: 50% !important;
            width: 40px !important;
            height: 40px !important;
            animation: spin 1s linear infinite !important;
            margin: 20px auto !important;
            display: block !important;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    `);

    function getCookies() {
        return document.cookie.split(';').map(cookie => cookie.trim()).filter(cookie => cookie);
    }

    async function detectWebRTCLeak() {
        return new Promise(resolve => {
            const rtcPeerConnection = new RTCPeerConnection({
                iceServers: [{ urls: "stun:stun.l.google.com:19302" }]
            });

            rtcPeerConnection.createDataChannel("");
            rtcPeerConnection.createOffer().then(offer => rtcPeerConnection.setLocalDescription(offer));

            rtcPeerConnection.onicecandidate = event => {
                if (event.candidate) {
                    const ipRegex = /([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/;
                    const match = ipRegex.exec(event.candidate.candidate);
                    if (match && !match[1].startsWith("192.168") && !match[1].startsWith("10.") && !match[1].startsWith("172.")) {
                        detectedWebRTCLeaks.push({
                            name: "WebRTC Leak",
                            danger: "high",
                            description: `Your real IP is exposed via WebRTC: ${match[1]}`
                        });
                    }
                }
            };

            setTimeout(() => {
                rtcPeerConnection.close();
                resolve(detectedWebRTCLeaks);
            }, 5000);
        });
    }

    function detectWebBeacons() {
        let beacons = [];
        let images = document.getElementsByTagName("img");
        for (let img of images) {
            let width = img.getAttribute("width") || img.width;
            let height = img.getAttribute("height") || img.height;
            let computedStyle = window.getComputedStyle(img);
            if ((parseInt(width) === 1 && parseInt(height) === 1) ||
                (img.naturalWidth === 1 && img.naturalHeight === 1) ||
                (computedStyle.width === "1px" && computedStyle.height === "1px")) {
                beacons.push({
                    name: "Web Beacon",
                    src: img.src,
                    danger: "medium",
                    description: "Detected a 1x1 pixel image that could be used as a web beacon."
                });
            }
        }
        return beacons;
    }

    function detectEtagTracking() {
        let etagTrackers = [];
        detectedETags.forEach(item => {
            etagTrackers.push({
                name: "Etag Tracking",
                danger: "medium",
                description: `ETag detected from ${item.url} with value ${item.etag}`
            });
        });
        return etagTrackers;
    }

    function detectIPGeolocation() {
        let ipGeoTrackers = [];
        detectedIPGeolocationRequests.forEach(item => {
            ipGeoTrackers.push({
                name: "IP Geolocation",
                danger: "high",
                description: `IP Geolocation request detected to ${item.url}`
            });
        });
        return ipGeoTrackers;
    }

    function detectTrackersSync() {
        const trackers = [];
        const knownTrackers = [
            // Google
            { name: 'Google Analytics (Universal)', regex: /google-analytics\.com\/analytics\.js|google-analytics\.com\/ga\.js/, danger: 'high', description: 'Tracks user behavior for analytics and advertising purposes.' },
            { name: 'Google Analytics 4', regex: /googletagmanager\.com\/gtag\/js/, danger: 'high', description: 'Next generation Google Analytics tracking.' },
            { name: 'Google Tag Manager', regex: /googletagmanager\.com\/gtm\.js/, danger: 'high', description: 'Manages JavaScript and HTML tags for tracking purposes.' },
            { name: 'Google AdSense', regex: /pagead2\.googlesyndication\.com/, danger: 'medium', description: 'Google\'s ad network, tracks user activity for ads.' },
            { name: 'Google DoubleClick', regex: /doubleclick\.net/, danger: 'high', description: 'Google\'s ad serving and tracking platform.' },
            { name: 'Google Ads Conversion', regex: /googleadservices\.com/, danger: 'medium', description: 'Tracks ad conversions for Google Ads.' },
            { name: 'Google reCAPTCHA', regex: /recaptcha\/api\.js/, danger: 'low', description: 'Google CAPTCHA service that may track user behavior.' },

            // Meta/Facebook
            { name: 'Facebook Pixel', regex: /connect\.facebook\.net\/.*\/fbevents\.js/, danger: 'high', description: 'Tracks user activity for targeted ads on Facebook.' },
            { name: 'Facebook SDK', regex: /connect\.facebook\.net\/.*\/sdk\.js/, danger: 'medium', description: 'Facebook social features and tracking.' },

            // Analytics & Heatmaps
            { name: 'Hotjar', regex: /static\.hotjar\.com\//, danger: 'high', description: 'Records user behavior including clicks, scrolling, and heatmaps.' },
            { name: 'Mixpanel', regex: /cdn\.mxpnl\.com/, danger: 'high', description: 'Advanced analytics tracking user events and behaviors.' },
            { name: 'Adobe Analytics', regex: /omtrdc\.net|2o7\.net/, danger: 'high', description: 'Enterprise analytics and marketing tracking.' },
            { name: 'Segment', regex: /cdn\.segment\.com/, danger: 'high', description: 'Customer data platform that tracks user interactions.' },
            { name: 'Heap Analytics', regex: /heapanalytics\.com/, danger: 'high', description: 'Automatically captures all user interactions.' },
            { name: 'Amplitude', regex: /cdn\.amplitude\.com/, danger: 'medium', description: 'Product analytics tracking user behavior.' },
            { name: 'Crazy Egg', regex: /script\.crazyegg\.com/, danger: 'medium', description: 'Heatmap and user behavior tracking.' },
            { name: 'FullStory', regex: /fullstory\.com/, danger: 'high', description: 'Session replay and user behavior recording.' },
            { name: 'Mouseflow', regex: /cdn\.mouseflow\.com/, danger: 'high', description: 'Session replay and heatmap tracking.' },
            { name: 'Lucky Orange', regex: /luckyorange\.com/, danger: 'high', description: 'Live chat and session recording.' },

            // Advertising
            { name: 'Criteo', regex: /static\.criteo\.net/, danger: 'high', description: 'Retargeting and personalized advertising.' },
            { name: 'Taboola', regex: /cdn\.taboola\.com/, danger: 'medium', description: 'Content recommendation and advertising.' },
            { name: 'Outbrain', regex: /outbrain\.com/, danger: 'medium', description: 'Content discovery and advertising platform.' },
            { name: 'AdRoll', regex: /d\.adroll\.com/, danger: 'high', description: 'Retargeting and display advertising.' },
            { name: 'Amazon Ads', regex: /amazon-adsystem\.com/, danger: 'medium', description: 'Amazon advertising and tracking.' },
            { name: 'Bing Ads', regex: /bat\.bing\.com/, danger: 'medium', description: 'Microsoft Bing advertising tracking.' },
            { name: 'Twitter Ads', regex: /static\.ads-twitter\.com/, danger: 'medium', description: 'Twitter advertising pixel.' },
            { name: 'LinkedIn Insight', regex: /snap\.licdn\.com/, danger: 'medium', description: 'LinkedIn conversion tracking.' },
            { name: 'Pinterest Tag', regex: /ct\.pinterest\.com/, danger: 'medium', description: 'Pinterest advertising tracking.' },
            { name: 'TikTok Pixel', regex: /analytics\.tiktok\.com/, danger: 'medium', description: 'TikTok advertising and conversion tracking.' },
            { name: 'Snapchat Pixel', regex: /sc-static\.net/, danger: 'medium', description: 'Snapchat advertising tracking.' },

            // Social Media Widgets
            { name: 'Twitter Widget', regex: /platform\.twitter\.com/, danger: 'low', description: 'Twitter social widgets and buttons.' },
            { name: 'LinkedIn Widget', regex: /platform\.linkedin\.com/, danger: 'low', description: 'LinkedIn social features.' },
            { name: 'Instagram Embed', regex: /instagram\.com\/embed\.js/, danger: 'low', description: 'Instagram content embedding.' },

            // Marketing Automation
            { name: 'HubSpot', regex: /js\.hs-scripts\.com/, danger: 'high', description: 'Marketing automation and CRM tracking.' },
            { name: 'Marketo', regex: /munchkin\.marketo\.net/, danger: 'high', description: 'Marketing automation platform.' },
            { name: 'Pardot', regex: /pi\.pardot\.com/, danger: 'high', description: 'Salesforce B2B marketing automation.' },
            { name: 'Mailchimp', regex: /chimpstatic\.com/, danger: 'medium', description: 'Email marketing and audience tracking.' },
            { name: 'ActiveCampaign', regex: /trackcmp\.net/, danger: 'medium', description: 'Email marketing automation.' },

            // Customer Support & Chat
            { name: 'Intercom', regex: /widget\.intercom\.io/, danger: 'medium', description: 'Customer messaging and behavior tracking.' },
            { name: 'Drift', regex: /js\.driftt\.com/, danger: 'medium', description: 'Conversational marketing and chat.' },
            { name: 'LiveChat', regex: /cdn\.livechatinc\.com/, danger: 'medium', description: 'Live chat and visitor tracking.' },
            { name: 'Zendesk', regex: /static\.zdassets\.com/, danger: 'low', description: 'Customer support platform.' },
            { name: 'Olark', regex: /static\.olark\.com/, danger: 'medium', description: 'Live chat with visitor monitoring.' },

            // A/B Testing & Optimization
            { name: 'Optimizely', regex: /cdn\.optimizely\.com/, danger: 'medium', description: 'A/B testing and experimentation platform.' },
            { name: 'VWO', regex: /dev\.visualwebsiteoptimizer\.com/, danger: 'medium', description: 'A/B testing and conversion optimization.' },
            { name: 'Google Optimize', regex: /www\.googleoptimize\.com/, danger: 'medium', description: 'Google A/B testing platform.' },

            // CDN & Performance (with tracking)
            { name: 'Cloudflare Insights', regex: /static\.cloudflareinsights\.com/, danger: 'low', description: 'Cloudflare analytics and performance monitoring.' },
            { name: 'New Relic', regex: /js-agent\.newrelic\.com/, danger: 'low', description: 'Application performance monitoring.' },

            // Payment Tracking
            { name: 'Stripe.js', regex: /js\.stripe\.com/, danger: 'low', description: 'Payment processing with user tracking.' },
            { name: 'PayPal Analytics', regex: /paypal\.com\/tagmanager/, danger: 'low', description: 'PayPal conversion tracking.' },

            // Other Trackers
            { name: 'Quantcast', regex: /quantserve\.com/, danger: 'high', description: 'Audience measurement and targeting.' },
            { name: 'Chartbeat', regex: /static\.chartbeat\.com/, danger: 'medium', description: 'Real-time web analytics.' },
            { name: 'Kissmetrics', regex: /i\.kissmetrics\.com/, danger: 'high', description: 'Person-based analytics tracking.' },
            { name: 'Piwik/Matomo', regex: /matomo\.js|piwik\.js/, danger: 'medium', description: 'Open-source analytics platform.' },
            { name: 'Yandex Metrica', regex: /mc\.yandex\.ru/, danger: 'high', description: 'Russian analytics and tracking service.' },
            { name: 'Baidu Analytics', regex: /hm\.baidu\.com/, danger: 'high', description: 'Chinese analytics service.' },

            // Browser Storage APIs
            { name: 'Local Storage Usage', regex: /localStorage\.setItem|localStorage\[/, danger: 'medium', description: 'Stores data in browser for persistent tracking.' },
            { name: 'Session Storage Usage', regex: /sessionStorage\.setItem|sessionStorage\[/, danger: 'low', description: 'Stores data temporarily during browser session.' },
            { name: 'IndexedDB Usage', regex: /indexedDB\.open/, danger: 'medium', description: 'Advanced browser database for data storage.' },
        ];

        knownTrackers.forEach(tracker => {
            if (document.body.innerHTML.match(tracker.regex)) {
                trackers.push({ name: tracker.name, danger: tracker.danger, description: tracker.description });
            }
        });

        let webBeacons = detectWebBeacons();
        webBeacons.forEach(beacon => trackers.push(beacon));

        let etagTrackers = detectEtagTracking();
        etagTrackers.forEach(etag => trackers.push(etag));

        let ipGeoTrackers = detectIPGeolocation();
        ipGeoTrackers.forEach(ipgeo => trackers.push(ipgeo));

        return trackers;
    }

    function detectZombieCookies() {
        return new Promise(resolve => {
            const testName = "aptZombieTest";
            document.cookie = `${testName}=test; path=/;`;
            document.cookie = `${testName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
            setTimeout(() => {
                if (document.cookie.includes(testName + "=")) {
                    resolve([{
                        name: "Zombie Cookies",
                        danger: "high",
                        description: "Test cookie was recreated, indicating persistent zombie cookie behavior."
                    }]);
                } else {
                    resolve([]);
                }
            }, 1000);
        });
    }

    async function detectAllTrackers() {
        const trackersSync = detectTrackersSync();
        const zombieTrackers = await detectZombieCookies();
        const webrtcLeaks = await detectWebRTCLeak();
        const iframes = document.querySelectorAll('iframe');
        const currentDomain = window.location.hostname;
        iframes.forEach(iframe => {
            try {
                const iframeSrc = iframe.src;
                if (iframeSrc) {
                    const iframeUrl = new URL(iframeSrc);
                    const iframeDomain = iframeUrl.hostname;
                    if (iframeDomain && iframeDomain !== currentDomain && !iframeDomain.includes(currentDomain)) {
                        detectedThirdPartyIframes.push({
                            domain: iframeDomain,
                            src: iframeSrc,
                            timestamp: Date.now()
                        });
                        console.log('[Privacy Audit] Third-party iframe detected: ' + iframeDomain);
                    }
                }
            } catch (e) {
                // Ignore invalid URLs
            }
        });

        return trackersSync.concat(zombieTrackers, webrtcLeaks);
    }

    async function detectFingerprinting() {
        let fingerprintingMethods = [];

        console.log('[Privacy Audit] ========== STARTING FINGERPRINTING DETECTION ==========');
        console.log('[Privacy Audit] detectedSensors array:', detectedSensors);
        console.log('[Privacy Audit] detectedCanvasFingerprinting array:', detectedCanvasFingerprinting);
        console.log('[Privacy Audit] detectedThirdPartyIframes array:', detectedThirdPartyIframes);
        console.log('[Privacy Audit] Checking Canvas... length:', detectedCanvasFingerprinting.length);
        if (detectedCanvasFingerprinting.length > 0) {
            const uniqueMethods = [...new Set(detectedCanvasFingerprinting.map(d => d.method))];
            const item = {
                name: 'Canvas Fingerprinting',
                danger: 'high',
                description: `Website is actively using Canvas API for fingerprinting. Methods: ${uniqueMethods.join(', ')}. Detected ${detectedCanvasFingerprinting.length} call(s).`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Canvas fingerprinting ADDED:', item);
        }

        console.log('[Privacy Audit] Checking WebGL... length:', detectedWebGLFingerprinting.length);
        if (detectedWebGLFingerprinting.length > 0) {
            const item = {
                name: 'WebGL Fingerprinting',
                danger: 'high',
                description: `Website is querying WebGL parameters for fingerprinting. Detected ${detectedWebGLFingerprinting.length} suspicious parameter request(s).`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ WebGL fingerprinting ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Font... length:', detectedFontFingerprinting.length);
        if (detectedFontFingerprinting.length > 0) {
            const item = {
                name: 'Font Fingerprinting',
                danger: 'high',
                description: `Website is measuring text extensively to detect installed fonts. This is a common fingerprinting technique.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Font fingerprinting ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Audio... length:', detectedAudioFingerprinting.length);
        if (detectedAudioFingerprinting.length > 0) {
            const item = {
                name: 'AudioContext Fingerprinting',
                danger: 'high',
                description: `Website created ${detectedAudioFingerprinting.length} AudioContext(s), potentially for audio fingerprinting.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ AudioContext fingerprinting ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Screen... length:', detectedScreenFingerprinting.length);
        if (detectedScreenFingerprinting.length > 0) {
            const props = [...new Set(detectedScreenFingerprinting.map(s => s.property))];
            const item = {
                name: 'Screen Fingerprinting',
                danger: 'medium',
                description: `Website is extensively querying screen properties for device identification: ${props.join(', ')}.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Screen fingerprinting ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Battery... length:', detectedBatteryFingerprinting.length);
        if (detectedBatteryFingerprinting.length > 0) {
            const item = {
                name: 'Battery API Fingerprinting',
                danger: 'medium',
                description: `Website is accessing Battery API, which can be used for fingerprinting.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Battery API fingerprinting ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Media Devices... length:', detectedMediaDevices.length);
        if (detectedMediaDevices.length > 0) {
            const item = {
                name: 'Media Devices Enumeration',
                danger: 'high',
                description: `Website is enumerating cameras, microphones, and speakers. Device lists are unique identifiers. Detected ${detectedMediaDevices.length} enumeration(s).`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Media devices enumeration ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Sensors... length:', detectedSensors.length);
        if (detectedSensors.length > 0) {
            const sensorTypes = [...new Set(detectedSensors.map(s => s.type))];
            const item = {
                name: 'Device Sensors Access',
                danger: 'high',
                description: `Website is accessing device sensors: ${sensorTypes.join(', ')}. Sensor data can fingerprint devices.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Sensor access ADDED:', item);
        } else {
            console.log('[Privacy Audit] ❌ Sensors: array is empty, skipping');
        }

        console.log('[Privacy Audit] Checking Service Workers... length:', detectedServiceWorkers.length);
        if (detectedServiceWorkers.length > 0) {
            const urls = detectedServiceWorkers.map(sw => sw.url).slice(0, 2);
            const item = {
                name: 'Service Worker Storage',
                danger: 'medium',
                description: `Website registered ${detectedServiceWorkers.length} Service Worker(s): ${urls.join(', ')}${detectedServiceWorkers.length > 2 ? '...' : ''}. These can store persistent identifiers.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Service Workers ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Cache API... length:', detectedCacheAPI.length);
        if (detectedCacheAPI.length > 0) {
            const cacheNames = [...new Set(detectedCacheAPI.map(c => c.cacheName))];
            const item = {
                name: 'Cache API Storage',
                danger: 'medium',
                description: `Website is using Cache API for storage (${cacheNames.length} cache(s)). Can be used for persistent tracking.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Cache API usage ADDED:', item);
        }

        console.log('[Privacy Audit] Checking WebSQL... length:', detectedWebSQL.length);
        if (detectedWebSQL.length > 0) {
            const dbNames = [...new Set(detectedWebSQL.map(db => db.dbName))];
            const item = {
                name: 'WebSQL Database',
                danger: 'medium',
                description: `Website is using deprecated WebSQL for storage: ${dbNames.join(', ')}. Often used for supercookies.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ WebSQL usage ADDED:', item);
        }

        console.log('[Privacy Audit] Checking FileSystem... length:', detectedFileSystem.length);
        if (detectedFileSystem.length > 0) {
            const item = {
                name: 'FileSystem API',
                danger: 'high',
                description: `Website is using FileSystem API (${detectedFileSystem.length} request(s)). Can store large amounts of tracking data.`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ FileSystem API ADDED:', item);
        }

        console.log('[Privacy Audit] Checking Third-party iframes... length:', detectedThirdPartyIframes.length);
        if (detectedThirdPartyIframes.length > 0) {
            const uniqueDomains = [...new Set(detectedThirdPartyIframes.map(i => i.domain))];
            const item = {
                name: 'Third-Party Iframes',
                danger: 'high',
                description: `Detected ${detectedThirdPartyIframes.length} third-party iframe(s) from: ${uniqueDomains.slice(0, 3).join(', ')}${uniqueDomains.length > 3 ? ` and ${uniqueDomains.length - 3} more` : ''}`
            };
            fingerprintingMethods.push(item);
            console.log('[Privacy Audit] ✅ Third-party iframes ADDED:', item);
        }

        console.log('[Privacy Audit] ========== FINGERPRINTING DETECTION COMPLETE ==========');
        console.log('[Privacy Audit] Total items in fingerprintingMethods array:', fingerprintingMethods.length);
        console.log('[Privacy Audit] Full fingerprintingMethods array:', fingerprintingMethods);

        return fingerprintingMethods;
    }

    async function showAuditResults() {
        console.log('[Privacy Audit] Starting privacy audit...');
        console.log('[Privacy Audit] Current detections before reset:');
        console.log('  - Canvas:', detectedCanvasFingerprinting.length);
        console.log('  - WebGL:', detectedWebGLFingerprinting.length);
        console.log('  - Audio:', detectedAudioFingerprinting.length);
        console.log('  - Font:', detectedFontFingerprinting.length);
        console.log('  - Screen:', detectedScreenFingerprinting.length);
        console.log('  - Battery:', detectedBatteryFingerprinting.length);
        console.log('  - Media Devices:', detectedMediaDevices.length);
        console.log('  - Sensors:', detectedSensors.length);
        console.log('  - Service Workers:', detectedServiceWorkers.length);
        console.log('  - Cache API:', detectedCacheAPI.length);
        console.log('  - WebSQL:', detectedWebSQL.length);
        console.log('  - FileSystem:', detectedFileSystem.length);
        console.log('  - Third-party iframes:', detectedThirdPartyIframes.length);

        windowContent.innerHTML = '<div class="aptloading-spinner"></div><p style="text-align: center !important;">Scanning...</p>';
        auditWindow.style.display = "block";

        const trackers = await detectAllTrackers();
        console.log('[Privacy Audit] Trackers detected:', trackers.length);
      
        await new Promise(resolve => setTimeout(resolve, 3000));

        console.log('[Privacy Audit] After trackers + 3s delay - detections update:');
        console.log('  - Canvas:', detectedCanvasFingerprinting.length);
        console.log('  - Audio:', detectedAudioFingerprinting.length);
        console.log('  - Sensors:', detectedSensors.length);

        const fingerprinting = await detectFingerprinting();
        console.log('[Privacy Audit] Fingerprinting methods detected:', fingerprinting.length);

        const cookies = getCookies();
        console.log('[Privacy Audit] Cookies found:', cookies.length);

        const allThreats = [...trackers, ...fingerprinting];
        console.log('[Privacy Audit] Total threats detected:', allThreats.length);
        console.log('[Privacy Audit] All threats array:', allThreats);

        windowContent.innerHTML = `
            <h2 class="aptTitle">Privacy Audit Results</h2>
            <div class="aptSectionTitle">Trackers & Fingerprinting (${allThreats.length})</div>
            <ul>
                ${allThreats.length > 0 ? allThreats.map(threat => `
                    <li>${threat.name} <span class="aptDangerLevel aptDangerLevel${capitalizeFirstLetter(threat.danger)}">${capitalizeFirstLetter(threat.danger)}</span> - ${threat.description}</li>`).join('') : '<li>No trackers or fingerprinting detected.</li>'}
            </ul>
            <div class="aptSectionTitle">Cookies (${cookies.length})</div>
            <ul>
                ${cookies.length > 0 ? cookies.map(cookie => `<li>${cookie}</li>`).join('') : '<li>No cookies found.</li>'}
            </ul>
        `;
        auditWindow.style.display = "block";
        console.log('[Privacy Audit] Audit complete!');

        detectedWebRTCLeaks = [];
        detectedCanvasFingerprinting = [];
        detectedWebGLFingerprinting = [];
        detectedAudioFingerprinting = [];
        detectedFontFingerprinting = [];
        detectedScreenFingerprinting = [];
        detectedBatteryFingerprinting = [];
        detectedMediaDevices = [];
        detectedSensors = [];
        detectedServiceWorkers = [];
        detectedCacheAPI = [];
        detectedWebSQL = [];
        detectedFileSystem = [];
        detectedThirdPartyIframes = [];
    }

    function capitalizeFirstLetter(string) {
        return string.charAt(0).toUpperCase() + string.slice(1);
    }

    scanButton.addEventListener("click", async function() {
        await showAuditResults();
    });

})();