Greasy Fork is available in English.

ip-checker

显示当前使用的公网IP地址,并带有折叠展开功能和刷新功能,以及IP风险查询功能

// ==UserScript==
// @name         ip-checker
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  显示当前使用的公网IP地址,并带有折叠展开功能和刷新功能,以及IP风险查询功能
// @author       https://linux.do/u/snaily
// @match        http://*/*
// @match        https://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      api.ipify.org
// @connect      api64.ipify.org
// @connect      ip-api.com
// @connect      scamalytics.com
// @connect      ping0.cc
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 检查是否为顶级窗口
    if (window !== top) {
        console.log('Not in top window, exiting script.');
        return;
    }
    function fetchCurrentIP() {
        console.log('Fetching current IP...');
        const refreshButton = document.getElementById('refreshIpInfo');
        if (refreshButton) {
            refreshButton.disabled = true;
            refreshButton.innerHTML = '正在刷新...';
        }

        let ipv6 = null;
        // Fetch IPv6
        GM_xmlhttpRequest({
            method: "GET",
            url: "https://api64.ipify.org?format=json",
            onload: function(response) {
                console.log('IPv6 fetched:', response.responseText);
                const ipInfo = JSON.parse(response.responseText);
                ipv6 = isIPv6(ipInfo.ip)? ipInfo.ip: null;
                console.log(ipv6);
            },
            onerror: function(error) {
                console.log('Error fetching IPv6:', error);
                if (refreshButton) {
                    refreshButton.disabled = false;
                    refreshButton.innerHTML = '刷新IP信息';
                }
            }
        });

        // Fetch IPv4
        GM_xmlhttpRequest({
            method: "GET",
            url: "https://api.ipify.org?format=json",
            onload: function(response) {
                console.log('IPv4 fetched:', response.responseText);
                const ipInfo = JSON.parse(response.responseText);
                fetchIPDetails(ipInfo.ip,ipv6);
            },
            onerror: function(error) {
                console.log('Error fetching IPv4:', error);
                if (refreshButton) {
                    refreshButton.disabled = false;
                    refreshButton.innerHTML = '刷新IP信息';
                }
            }
        });
    }

    function isIPv6(ip) {
        // IPv6正则表达式
        const ipv6Pattern = new RegExp('^([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:)$|^([0-9a-fA-F]{1,4}:){1,7}:$|^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$|^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$|^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$|^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$|^:((:[0-9a-fA-F]{1,4}){1,7}|:)$|^fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}$|^::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])$|^([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])$');
        return ipv6Pattern.test(ip);
    }
    function fetchIPDetails(ip,ipv6, callback) {
        console.log('Fetching IP details for:', ip);
        console.log(ipv6);
        GM_xmlhttpRequest({
            method: "GET",
            url: "http://ip-api.com/json/" + ip,
            onload: function(response) {
                console.log('IP details fetched:', response.responseText);
                const ipDetails = JSON.parse(response.responseText);
                fetchIPRisk(ip,ipv6,ipDetails, callback);
            },
            onerror: function(error) {
                console.log('Error fetching IP details:', error);
                const refreshButton = document.getElementById('refreshIpInfo');
                if (refreshButton) {
                    refreshButton.disabled = false;
                    refreshButton.innerHTML = '刷新IP信息';
                }
                if (callback) {
                    callback(); // 查询失败后恢复按钮状态
                }
            }
        });
    }

    function fetchIPRisk(ip,ipv6,details,callback) {
        console.log('Fetching IP risk for:', ip);
        console.log(ipv6);
        GM_xmlhttpRequest({
            method: "GET",
            url: `https://scamalytics.com/ip/${ip}`,
            onload: function(response) {
                console.log('IP risk fetched:', response.responseText);
                const riskData = parseIPRisk(response.responseText);
                fetchPing0Risk(ip,ipv6,details, riskData);
                if (callback) {
                    callback(); // 查询成功后恢复按钮状态
                }
            },
            onerror: function(error) {
                console.log('Error fetching IP risk:', error);
                displayIPDetails(ipv6,details, null, null);
                const refreshButton = document.getElementById('refreshIpInfo');
                if (refreshButton) {
                    refreshButton.disabled = false;
                    refreshButton.innerHTML = '刷新IP信息';
                }
            }
        });
    }

    function fetchPing0Risk(ip,ipv6, details, riskData) {
        console.log('Fetching Ping0 risk for:', ip);
        console.log(ipv6);
        GM_xmlhttpRequest({
            method: "GET",
            url: `https://ping0.cc/ip/${ip}`,
            headers: {
                "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36"
            },
            onload: function(response) {
                console.log('Initial Ping0 response:', response.responseText);
                const windowX = parseWindowX(response.responseText);
                if (windowX) {
                    console.log('Parsed window.x value:', windowX);
                    GM_xmlhttpRequest({
                        method: "GET",
                        url: `https://ping0.cc/ip/${ip}`,
                        headers: {
                            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
                            "Cookie": `jskey=${windowX}`
                        },
                        onload: function(response) {
                            console.log('Final Ping0 response:', response.responseText);
                            const ping0Data = parsePing0Risk(response.responseText);
                            displayIPDetails(ipv6,details, riskData, ping0Data);
                            const refreshButton = document.getElementById('refreshIpInfo');
                            if (refreshButton) {
                                refreshButton.disabled = false;
                                refreshButton.innerHTML = '刷新IP信息';
                            }
                        },
                        onerror: function(error) {
                            console.log('Error fetching final Ping0 risk:', error);
                            displayIPDetails(ipv6,details, riskData, null);
                            const refreshButton = document.getElementById('refreshIpInfo');
                            if (refreshButton) {
                                refreshButton.disabled = false;
                                refreshButton.innerHTML = '刷新IP信息';
                            }
                        }
                    });
                } else {
                    console.log('Failed to retrieve window.x value.');
                    displayIPDetails(ipv6,details, riskData, null);
                    const refreshButton = document.getElementById('refreshIpInfo');
                    if (refreshButton) {
                        refreshButton.disabled = false;
                        refreshButton.innerHTML = '刷新IP信息';
                    }
                }
            },
            onerror: function(error) {
                console.log('Error fetching initial Ping0 page:', error);
                displayIPDetails(ipv6,details, riskData, null);
                const refreshButton = document.getElementById('refreshIpInfo');
                if (refreshButton) {
                    refreshButton.disabled = false;
                    refreshButton.innerHTML = '刷新IP信息';
                }
            }
        });
    }

    function parseIPRisk(html) {
        console.log('Parsing IP risk data...');
        const scoreMatch = html.match(/"score":"(.*?)"/);
        const riskMatch = html.match(/"risk":"(.*?)"/);
        if (riskMatch) {
            const riskData = {
                score: scoreMatch[1],
                risk: riskMatch[1]
            };
            console.log('Parsed risk data:', riskData);
            return riskData;
        }
        console.log('Failed to parse risk data.');
        return null;
    }

    function parseWindowX(html) {
        console.log('Parsing window.x value...');
        const match = html.match(/window\.x\s*=\s*'([^']+)'/);
        const windowX = match ? match[1] : null;
        console.log('Parsed window.x:', windowX);
        return windowX;
    }

    function parsePing0Risk(html) {
        console.log('Parsing Ping0 risk data...');
        const parser = new DOMParser();
        const doc = parser.parseFromString(html, 'text/html');

        const riskValue = doc.evaluate('/html/body/div[2]/div[2]/div[1]/div[2]/div[9]/div[2]/span', doc, null, XPathResult.STRING_TYPE, null).stringValue;
        const ipType = doc.evaluate('/html/body/div[2]/div[2]/div[1]/div[2]/div[8]/div[2]/span', doc, null, XPathResult.STRING_TYPE, null).stringValue;
        const nativeIP = doc.evaluate('/html/body/div[2]/div[2]/div[1]/div[2]/div[11]/div[2]/span', doc, null, XPathResult.STRING_TYPE, null).stringValue;

        const ping0Data = {
            riskValue: riskValue.trim(),
            ipType: ipType.trim(),
            nativeIP: nativeIP.trim()
        };
        console.log('Parsed Ping0 data:', ping0Data);
        return ping0Data;
    }

    function displayIPDetails(ipv6,details, riskData, ping0Data) {
        console.log('Displaying IP details...');
        var ipElement = document.getElementById('ipInfo');
        if (!ipElement) {
            ipElement = document.createElement('div');
            ipElement.id = 'ipInfo';
            ipElement.style.position = 'fixed';
            ipElement.style.top = GM_getValue('ipInfoTop', '10px');
            ipElement.style.right = '-500px';
            ipElement.style.backgroundColor = '#fff';
            ipElement.style.padding = '10px';
            ipElement.style.borderRadius = '5px 0 0 5px'; // 仅左侧有圆角
            ipElement.style.boxShadow = '0 0 10px rgba(0,0,0,0.1)';
            ipElement.style.fontSize = '14px';
            ipElement.style.color = '#333';
            ipElement.style.zIndex = '9999';
            ipElement.style.transition = 'right 0.3s ease'; // 添加平滑过渡效果

            const title = document.createElement('div');
            title.style.fontWeight = 'bold';
            title.style.marginBottom = '5px';
            title.innerText = 'IP检测信息';

            const refreshButton = document.createElement('button');
            refreshButton.id = 'refreshIpInfo';
            refreshButton.style.display = 'inline-block';
            refreshButton.style.width = 'auto';
            refreshButton.style.marginLeft = '10px';
            refreshButton.style.backgroundColor = '#007bff';
            refreshButton.style.color = '#fff';
            refreshButton.style.border = 'none';
            refreshButton.style.borderRadius = '3px';
            refreshButton.style.padding = '2px 5px';
            refreshButton.style.cursor = 'pointer';
            refreshButton.style.fontSize = '12px';
            refreshButton.innerHTML = '刷新IP信息';
            refreshButton.onclick = fetchCurrentIP;

            const toggleButton = document.createElement('button');
            toggleButton.id = 'toggleIpInfo';
            toggleButton.style.display = 'none';
            toggleButton.style.width = 'auto';
            toggleButton.style.marginLeft = '10px';
            toggleButton.style.backgroundColor = '#007bff';
            toggleButton.style.color = '#fff';
            toggleButton.style.border = 'none';
            toggleButton.style.borderRadius = '3px';
            toggleButton.style.padding = '2px 5px';
            toggleButton.style.cursor = 'pointer';
            toggleButton.style.fontSize = '12px';
            toggleButton.innerHTML = '展开信息';
            toggleButton.onclick = toggleIpInfo;

            const inputContainer = document.createElement('div');
            inputContainer.style.marginTop = '10px';

            const ipInput = document.createElement('input');
            ipInput.type = 'text';
            ipInput.placeholder = '输入IP地址';
            ipInput.style.marginRight = '5px';
            ipInput.id = 'queryIpInput';

            const queryButton = document.createElement('button');
            queryButton.id = 'queryIpButton';
            queryButton.innerHTML = '查询IP';
            queryButton.style.width = 'auto';
            queryButton.style.backgroundColor = '#007bff';
            queryButton.style.color = '#fff';
            queryButton.style.border = 'none';
            queryButton.style.borderRadius = '3px';
            queryButton.style.padding = '2px 5px';
            queryButton.style.cursor = 'pointer';
            queryButton.style.fontSize = '12px';
            queryButton.onclick = queryIpInfo;


            const dragHandle = document.createElement('div');
            dragHandle.style.width = '100%';
            dragHandle.style.height = '10px';
            dragHandle.style.backgroundColor = '#ccc';
            dragHandle.style.cursor = 'move';
            dragHandle.style.marginBottom = '10px';
            dragHandle.onmousedown = startDragging;

            const content = document.createElement('div');
            content.id = 'ipInfoContent';

            title.appendChild(refreshButton);
            title.appendChild(toggleButton);
            inputContainer.appendChild(ipInput);
            inputContainer.appendChild(queryButton);
            title.appendChild(inputContainer);
            ipElement.appendChild(title);
            ipElement.appendChild(dragHandle);
            ipElement.appendChild(content);
            document.body.appendChild(ipElement);

            // 创建展开按钮
            const expandButton = document.createElement('button');
            expandButton.id = 'expandIpInfo';
            expandButton.style.position = 'fixed';
            expandButton.style.top = GM_getValue('ipInfoTop', '10px');
            expandButton.style.width = 'auto';
            expandButton.style.right = '0';
            expandButton.style.backgroundColor = '#007bff';
            expandButton.style.color = '#fff';
            expandButton.style.border = 'none';
            expandButton.style.borderRadius = '3px 0 0 3px';
            expandButton.style.padding = '2px 5px';
            expandButton.style.cursor = 'pointer';
            expandButton.style.fontSize = '12px';
            expandButton.style.zIndex = '9999';
            expandButton.innerHTML = '展开信息';
            expandButton.onclick = toggleIpInfo;
            expandButton.style.display = 'block'; // 默认隐藏
            document.body.appendChild(expandButton);
        }

        var contentElement = document.getElementById('ipInfoContent');
        if (!contentElement) {
            contentElement = document.createElement('div');
            contentElement.id = 'ipInfoContent';
            ipElement.appendChild(contentElement);
        }

        const content = `
            <div>
                <strong>IPv4:</strong> ${details.query} <span id="copyButtonContainer1"></span>
            </div>
            <div>
                <strong>IPv6:</strong> ${ipv6 ? ipv6 : 'N/A'} <span id="copyButtonContainer2"></span>
            </div>
            <div>
                <strong>城市:</strong> ${details.city}, ${details.regionName}
            </div>
            <div>
                <strong>zip:</strong> ${details.zip ? details.zip : 'N/A'}
            </div>
            <div>
                <strong>国家:</strong> ${details.country}
            </div>
            <div>
                <strong>ISP:</strong> ${details.isp}
            </div>
            <div>
                <strong>AS:</strong> ${details.as}
            </div>
            <div>
                <strong>风险评分:</strong> ${riskData ? riskData.score : 'N/A'}
            </div>
            <div>
                <strong>风险类型:</strong> ${riskData ? riskData.risk : 'N/A'}
            </div>
            <div>
                <strong>Ping0风险值:</strong> ${ping0Data ? ping0Data.riskValue : 'N/A'}
            </div>
            <div>
                <strong>IP类型:</strong> ${ping0Data ? ping0Data.ipType : 'N/A'}
            </div>
            <div>
                <strong>原生IP:</strong> ${ping0Data ? ping0Data.nativeIP : 'N/A'}
            </div>
            <hr>
        `;
        contentElement.innerHTML = content; // Use innerHTML instead of insertAdjacentHTML to replace old content
        // 添加复制按钮到 copyButtonContainer
        const copyButtonContainer1 = document.getElementById('copyButtonContainer1');
        copyButtonContainer1.appendChild(createCopyButton(details.query));
        const copyButtonContainer2 = document.getElementById('copyButtonContainer2');
        copyButtonContainer2.appendChild(createCopyButton(ipv6));
    }
    function isValidIPv4(ip) {
        const ipv4Pattern = /^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}$/;
        return ipv4Pattern.test(ip);
    }
    function queryIpInfo() {
        const queryIp = document.getElementById('queryIpInput').value.trim();
        const queryButton = document.getElementById('queryIpButton');

        if (!queryIp) {
            alert('请输入一个有效的IP地址');
            return;
        }

        if (!isValidIPv4(queryIp)) {
            alert('请输入一个有效的IPv4地址');
            return;
        }

        console.log('Querying IP info for:', queryIp);

        // 禁用查询按钮并显示“正在查询”
        queryButton.disabled = true;
        queryButton.innerHTML = '正在查询...';

        // 调用 fetchIPDetails 并传递回调函数以恢复按钮状态
        fetchIPDetails(queryIp, null, function() {
            // 查询完成后恢复按钮状态
            queryButton.disabled = false;
            queryButton.innerHTML = '查询IP';
        });
    }

    function createCopyButton(text) {
        const button = document.createElement('button');
        button.innerHTML = '复制';
        button.style.width = 'auto';
        button.style.marginLeft = '5px';
        button.style.cursor = 'pointer';
        //button.style.backgroundColor = '#007bff';
        //button.style.color = '#fff';
        button.style.border = 'none';
        button.style.padding = '2px 5px';
        button.style.borderRadius = '3px';
        button.onclick = (event) => {
            event.stopPropagation(); // 阻止事件冒泡
            navigator.clipboard.writeText(text).then(() => {
                button.innerHTML = '已复制';
                setTimeout(() => {
                    button.innerHTML = '复制';
                }, 500);
            }).catch(err => {
                console.error('复制失败: ', err);
            });
        };
        return button;
    }

    // 添加选择文本和显示查询按钮的功能
    document.addEventListener('mouseup', handleTextSelection);

    function handleTextSelection(event) {
        // 检查点击是否发生在 IP 信息面板内
        const ipElement = document.getElementById('ipInfo');
        const expandIpButton = document.getElementById('expandIpInfo');
        if (ipElement && ipElement.contains(event.target) || expandIpButton && expandIpButton.contains(event.target)) {
            return; // 如果点击在 IP 信息面板内,不执行后续操作
        }

        const selectedText = window.getSelection().toString().trim();
        if (isValidIPv4(selectedText)) {
            showQueryButton(selectedText,event);
        }
    }

    function showQueryButton(ip,event) {
        let queryButton = document.getElementById('floatingQueryButton');
        if (!queryButton) {
            queryButton = document.createElement('button');
            queryButton.id = 'floatingQueryButton';
            queryButton.innerHTML = '查询IP';
            queryButton.style.position = 'fixed';
            queryButton.style.zIndex = '10000';
            queryButton.style.padding = '5px 10px';
            queryButton.style.backgroundColor = '#007bff';
            queryButton.style.color = '#fff';
            queryButton.style.border = 'none';
            queryButton.style.borderRadius = '3px';
            queryButton.style.cursor = 'pointer';
            document.body.appendChild(queryButton);
        }

        const selection = window.getSelection();
        queryButton.style.left = `${event.clientX + 10}px`;
        queryButton.style.top = `${event.clientY + 10}px`;
        queryButton.style.display = 'block';

        queryButton.onclick = function() {
            document.getElementById('queryIpInput').value = ip;
            const ipElement = document.getElementById('ipInfo');
            if(ipElement.style.right !== '0px'){
                toggleIpInfo();
            }
            queryIpInfo();
            this.style.display = 'none';
        };
    }

    // 修改 toggleIpInfo 函数
    function toggleIpInfo() {
        const ipElement = document.getElementById('ipInfo');
        const expandButton = document.getElementById('expandIpInfo');
        const toggleButton = document.getElementById('toggleIpInfo');
        if (ipElement.style.right === '0px') {
            ipElement.style.right = '-500px';
            toggleButton.innerHTML = '展开信息';
            toggleButton.style.display = 'none';
            expandButton.style.display = 'block';
        } else {
            ipElement.style.right = '0px';
            toggleButton.innerHTML = '隐藏信息';
            toggleButton.style.display = 'inline-block';
            expandButton.style.display = 'none';
        }
    }

    let initialTop = 10;
    let initialY = 0;
    let dragging = false;

    function startDragging(e) {
        console.log('Start dragging...');
        dragging = true;
        initialY = e.clientY;
        const ipElement = document.getElementById('ipInfo');
        const expandButton = document.getElementById('expandIpInfo');
        initialTop = parseInt(ipElement.style.top, 10);
        expandButton.style.top = ipElement.style.top; // 同步expandButton的位置
        document.addEventListener('mousemove', handleDragging);
        document.addEventListener('mouseup', stopDragging);
    }

    function handleDragging(e) {
        if (dragging) {
            console.log('Dragging...');
            const deltaY = e.clientY - initialY;
            const newTop = initialTop + deltaY;
            const ipElement = document.getElementById('ipInfo');
            const expandButton = document.getElementById('expandIpInfo');
            ipElement.style.top = newTop + 'px';
            expandButton.style.top = newTop + 'px'; // 同步expandButton的位置
        }
    }

    function stopDragging() {
        console.log('Stop dragging...');
        dragging = false;
        document.removeEventListener('mousemove', handleDragging);
        document.removeEventListener('mouseup', stopDragging);

        const ipElement = document.getElementById('ipInfo');
        GM_setValue('ipInfoTop', ipElement.style.top);

        const expandButton = document.getElementById('expandIpInfo');
        GM_setValue('expandButtonTop', expandButton.style.top); // 同步保存expandButton的位置
    }

    // 初始创建ipElement,但不触发数据获取
    displayIPDetails(null,null, null, null);
    //fetchCurrentIP();
})();