开发背景
一些订阅没有提供ip的归属地,每次都需要自己去对应网址查看,很不方便。索性就搞了一个ip检测工具,也方便C号使用
功能描述
提供ip风险检测(基于scamalytics和ping0),节点切换后,刷新获取当前节点的ip检测信息,展开、收缩的功能。目前功能可能较为简单,后续根据使用情况进行优化。
更新
v1.1 版本
- 新增复制按钮
- 新增上下拖动,并记录位置
- 修改初始化页面时,请求ip检测
v1.2 版本
- 新增zip展示
- 优化复制体验,不弹窗
- 支持点击空白处展开折叠
主要检测信息
- 公网ip
- 组织
- 城市
- 地区
- 国家
- 坐标
- ISP
- AS
- 风险分数
- 风控值
- ip类型
- 原生ip
其中风险分数参考的scamalytics
风控值,ip类型,原生ip参考的是ping0
https://ping0.cc
代码
// ==UserScript==
// @name ip-checker
// @namespace http://tampermonkey.net/
// @version 1.2
// @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 ip-api.com
// @connect scamalytics.com
// @connect ping0.cc
// @license MIT
// ==/UserScript==
(function() {
'use strict';
function fetchCurrentIP() {
console.log('Fetching current IP...');
const refreshButton = document.getElementById('refreshIpInfo');
if (refreshButton) {
refreshButton.disabled = true;
refreshButton.innerHTML = '正在刷新...';
}
GM_xmlhttpRequest({
method: "GET",
url: "https://api.ipify.org?format=json",
onload: function(response) {
console.log('IP fetched:', response.responseText);
const ipInfo = JSON.parse(response.responseText);
fetchIPDetails(ipInfo.ip);
},
onerror: function(error) {
console.log('Error fetching IP:', error);
if (refreshButton) {
refreshButton.disabled = false;
refreshButton.innerHTML = '点击刷新IP信息';
}
}
});
}
function fetchIPDetails(ip) {
console.log('Fetching IP details for:', ip);
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, ipDetails);
},
onerror: function(error) {
console.log('Error fetching IP details:', error);
const refreshButton = document.getElementById('refreshIpInfo');
if (refreshButton) {
refreshButton.disabled = false;
refreshButton.innerHTML = '点击刷新IP信息';
}
}
});
}
function fetchIPRisk(ip, details) {
console.log('Fetching IP risk for:', ip);
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, details, riskData);
},
onerror: function(error) {
console.log('Error fetching IP risk:', error);
displayIPDetails(details, null, 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 fetchPing0Risk(ip, details, riskData) {
console.log('Fetching Ping0 risk for:', ip);
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(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(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(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(details, riskData, null);
const refreshButton = document.getElementById('refreshIpInfo');
if (refreshButton) {
refreshButton.disabled = false;
refreshButton.innerHTML = '点击刷新IP信息';
}
}
});
}
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 createCopyButton(text) {
const button = document.createElement('button');
button.innerHTML = '复制';
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 = () => {
navigator.clipboard.writeText(text).then(() => {
alert('复制成功: ' + text);
}).catch(err => {
console.error('复制失败: ', err);
});
};
return button;
}
function displayIPDetails(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 = '0';
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.5)';
ipElement.style.textAlign = 'left';
ipElement.style.zIndex = '9999';
ipElement.style.color = '#004085'; // 设置深蓝色字体颜色
ipElement.style.transition = 'right 0.5s'; // 平滑过渡效果
ipElement.style.width = '300px'; // 指定宽度
ipElement.style.right = '-300px'; // 默认隐藏在屏幕边缘
ipElement.innerHTML = `
<div id="toggleIpInfo" style="position:absolute;left:-20px;top:0;width:20px;height:100%;background-color:#cfe6ff;cursor:pointer;z-index:10000;">
<span id="toggleIcon" style="position:absolute;top:50%;left:50%;transform:translate(-50%, -50%);font-size:18px;color:white;">◀</span>
</div>
<button id="refreshIpInfo" style="cursor:pointer;background-color:#28a745;color:#fff;border:none;padding:5px 10px;border-radius:5px;width:100%;margin-bottom:10px;">点击刷新IP信息</button>
<div id="ipDetails" style="display:none;">
<div>当前公网IP: ${details.query}<span id="copyButtonContainer"></span></div>
<div>组织: ${details.org}</div>
<div>城市: ${details.city}</div>
<div>地区: ${details.regionName}</div>
<div>zip: ${details.zip}</div>
<div>国家: ${details.country}</div>
<div>坐标: ${details.lon},${details.lat}</div>
<div>ISP: ${details.isp}</div>
<div>AS: ${details.as}</div>
<div>风险分数: ${riskData ? riskData.score : '查询失败'}(${riskData ? riskData.risk : ''})</div>
<div>风控值: ${ping0Data ? ping0Data.riskValue : '查询失败'}</div>
<div>IP类型: ${ping0Data ? ping0Data.ipType : '查询失败'}</div>
<div>原生IP: ${ping0Data ? ping0Data.nativeIP : '查询失败'}</div>
</div>
`;
document.body.appendChild(ipElement);
// 绑定点击事件
document.getElementById('toggleIpInfo').addEventListener('click', toggleIpInfo);
document.getElementById('refreshIpInfo').addEventListener('click', fetchCurrentIP);
// 初始化变量用于记录拖拽状态
let isDragging = false;
let startY = 0;
let startTop = 0;
// 鼠标按下事件,在ipElement区域生效
ipElement.addEventListener('mousedown', function(e) {
if (e.target.id !== 'refreshIpInfo' && e.target.id !== 'toggleIcon') {
isDragging = true;
startY = e.clientY;
startTop = parseInt(window.getComputedStyle(ipElement).top, 10);
ipElement.style.transition = 'none'; // 去除过渡效果以便拖拽时立即反应
}
});
// 鼠标移动事件
document.addEventListener('mousemove', function(e) {
if (isDragging) {
const moveY = e.clientY - startY;
ipElement.style.top = `${startTop + moveY}px`;
}
});
// 鼠标松开事件
document.addEventListener('mouseup', function() {
if (isDragging) {
isDragging = false;
ipElement.style.transition = 'right 0.5s'; // 恢复过渡效果
GM_setValue('ipInfoTop', ipElement.style.top); // 记录当前位置
}
});
// 添加复制按钮到 copyButtonContainer
const copyButtonContainer = document.getElementById('copyButtonContainer');
copyButtonContainer.appendChild(createCopyButton(details.query));
} else {
var ipDetails = document.getElementById('ipDetails');
ipDetails.innerHTML = `
<div>当前公网IP: ${details.query}<span id="copyButtonContainer"></span></div>
<div>组织: ${details.org}</div>
<div>城市: ${details.city}</div>
<div>地区: ${details.regionName}</div>
<div>zip: ${details.zip}</div>
<div>国家: ${details.country}</div>
<div>坐标: ${details.lon},${details.lat}</div>
<div>ISP: ${details.isp}</div>
<div>AS: ${details.as}</div>
<div>风险分数: ${riskData ? riskData.score : '查询失败'}(${riskData ? riskData.risk : ''})</div>
<div>风控值: ${ping0Data ? ping0Data.riskValue : '查询失败'}</div>
<div>IP类型: ${ping0Data ? ping0Data.ipType : '查询失败'}</div>
<div>原生IP: ${ping0Data ? ping0Data.nativeIP : '查询失败'}</div>
`;
// 添加复制按钮到 copyButtonContainer
const copyButtonContainer = document.getElementById('copyButtonContainer');
copyButtonContainer.appendChild(createCopyButton(details.query));
}
// 绑定 ipDetails 的点击事件
ipDetails.addEventListener('click', toggleIpInfo);
}
function toggleIpInfo() {
var ipDetails = document.getElementById('ipDetails');
var toggleIcon = document.getElementById('toggleIcon');
var ipElement = document.getElementById('ipInfo');
ipElement.style.right = (ipElement.style.right == '0px') ? '-300px' : '0px'; // 切换贴边隐藏
if (ipDetails.style.display === 'none') {
ipDetails.style.display = 'block';
toggleIcon.innerHTML = '▶';
} else {
ipDetails.style.display = 'none';
toggleIcon.innerHTML = '◀';
}
}
function createCopyButton(text) {
const button = document.createElement('button');
button.innerHTML = '复制';
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 = '复制';
}, 2000);
}).catch(err => {
console.error('复制失败: ', err);
});
};
return button;
}
// 添加样式表
const style = document.createElement('style');
style.innerHTML = `
#ipInfo button {
cursor: pointer;
background-color: #007bff;
color: #fff;
border: none;
padding: 2px 5px;
border-radius: 3px;
}
`;
document.head.appendChild(style);
// 初始创建ipElement,但不触发数据获取
displayIPDetails({}, null, null);
// fetchCurrentIP(); // 移除自动触发
})();
greasyfork地址
使用教程
初始化页面时自动开始检测ip,检测完毕后,会在右下角提供一个可以展开的按钮,点击展开就可以看到ip检测后的结果,再点击即收缩。
切换节点,点击刷新ip信息按钮,可以获取到当前节点ip信息。
使用截图
v1.0版本
【图1】
【图2】
v1.1版本
【图3】
v1.2版本
【图4】
欢迎各位佬友使用脚本给出建议或者对现有的功能接棒优化。最后如果脚本对你有用,给个免费的小红心
有个问题请教下佬友们,还有哪些参考价值比较高的ip检测网站?
感谢大佬的回答!