ip-checker

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

当前为 2024-06-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name ip-checker
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.6
  5. // @description 显示当前使用的公网IP地址,并带有折叠展开功能和刷新功能,以及IP风险查询功能
  6. // @author https://linux.do/u/snaily
  7. // @match http://*/*
  8. // @match https://*/*
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @connect api.ipify.org
  13. // @connect api64.ipify.org
  14. // @connect ip-api.com
  15. // @connect scamalytics.com
  16. // @connect ping0.cc
  17. // @license MIT
  18. // ==/UserScript==
  19.  
  20. (function() {
  21. 'use strict';
  22.  
  23. // 检查是否为顶级窗口
  24. if (window !== top) {
  25. console.log('Not in top window, exiting script.');
  26. return;
  27. }
  28. function fetchCurrentIP() {
  29. console.log('Fetching current IP...');
  30. const refreshButton = document.getElementById('refreshIpInfo');
  31. if (refreshButton) {
  32. refreshButton.disabled = true;
  33. refreshButton.innerHTML = '正在刷新...';
  34. }
  35.  
  36. let ipv6 = null;
  37. // Fetch IPv6
  38. GM_xmlhttpRequest({
  39. method: "GET",
  40. url: "https://api64.ipify.org?format=json",
  41. onload: function(response) {
  42. console.log('IPv6 fetched:', response.responseText);
  43. const ipInfo = JSON.parse(response.responseText);
  44. ipv6 = isIPv6(ipInfo.ip)? ipInfo.ip: null;
  45. console.log(ipv6);
  46. },
  47. onerror: function(error) {
  48. console.log('Error fetching IPv6:', error);
  49. if (refreshButton) {
  50. refreshButton.disabled = false;
  51. refreshButton.innerHTML = '点击刷新IP信息';
  52. }
  53. }
  54. });
  55.  
  56. // Fetch IPv4
  57. GM_xmlhttpRequest({
  58. method: "GET",
  59. url: "https://api.ipify.org?format=json",
  60. onload: function(response) {
  61. console.log('IPv4 fetched:', response.responseText);
  62. const ipInfo = JSON.parse(response.responseText);
  63. fetchIPDetails(ipInfo.ip,ipv6);
  64. },
  65. onerror: function(error) {
  66. console.log('Error fetching IPv4:', error);
  67. if (refreshButton) {
  68. refreshButton.disabled = false;
  69. refreshButton.innerHTML = '点击刷新IP信息';
  70. }
  71. }
  72. });
  73. }
  74.  
  75. function isIPv6(ip) {
  76. // IPv6正则表达式
  77. 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])$');
  78. return ipv6Pattern.test(ip);
  79. }
  80. function fetchIPDetails(ip,ipv6, callback) {
  81. console.log('Fetching IP details for:', ip);
  82. console.log(ipv6);
  83. GM_xmlhttpRequest({
  84. method: "GET",
  85. url: "http://ip-api.com/json/" + ip,
  86. onload: function(response) {
  87. console.log('IP details fetched:', response.responseText);
  88. const ipDetails = JSON.parse(response.responseText);
  89. fetchIPRisk(ip,ipv6,ipDetails, callback);
  90. },
  91. onerror: function(error) {
  92. console.log('Error fetching IP details:', error);
  93. const refreshButton = document.getElementById('refreshIpInfo');
  94. if (refreshButton) {
  95. refreshButton.disabled = false;
  96. refreshButton.innerHTML = '点击刷新IP信息';
  97. }
  98. if (callback) {
  99. callback(); // 查询失败后恢复按钮状态
  100. }
  101. }
  102. });
  103. }
  104.  
  105. function fetchIPRisk(ip,ipv6,details,callback) {
  106. console.log('Fetching IP risk for:', ip);
  107. console.log(ipv6);
  108. GM_xmlhttpRequest({
  109. method: "GET",
  110. url: `https://scamalytics.com/ip/${ip}`,
  111. onload: function(response) {
  112. console.log('IP risk fetched:', response.responseText);
  113. const riskData = parseIPRisk(response.responseText);
  114. fetchPing0Risk(ip,ipv6,details, riskData);
  115. if (callback) {
  116. callback(); // 查询成功后恢复按钮状态
  117. }
  118. },
  119. onerror: function(error) {
  120. console.log('Error fetching IP risk:', error);
  121. displayIPDetails(ipv6,details, null, null);
  122. const refreshButton = document.getElementById('refreshIpInfo');
  123. if (refreshButton) {
  124. refreshButton.disabled = false;
  125. refreshButton.innerHTML = '点击刷新IP信息';
  126. }
  127. }
  128. });
  129. }
  130.  
  131. function fetchPing0Risk(ip,ipv6, details, riskData) {
  132. console.log('Fetching Ping0 risk for:', ip);
  133. console.log(ipv6);
  134. GM_xmlhttpRequest({
  135. method: "GET",
  136. url: `https://ping0.cc/ip/${ip}`,
  137. headers: {
  138. "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"
  139. },
  140. onload: function(response) {
  141. console.log('Initial Ping0 response:', response.responseText);
  142. const windowX = parseWindowX(response.responseText);
  143. if (windowX) {
  144. console.log('Parsed window.x value:', windowX);
  145. GM_xmlhttpRequest({
  146. method: "GET",
  147. url: `https://ping0.cc/ip/${ip}`,
  148. headers: {
  149. "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",
  150. "Cookie": `jskey=${windowX}`
  151. },
  152. onload: function(response) {
  153. console.log('Final Ping0 response:', response.responseText);
  154. const ping0Data = parsePing0Risk(response.responseText);
  155. displayIPDetails(ipv6,details, riskData, ping0Data);
  156. const refreshButton = document.getElementById('refreshIpInfo');
  157. if (refreshButton) {
  158. refreshButton.disabled = false;
  159. refreshButton.innerHTML = '点击刷新IP信息';
  160. }
  161. },
  162. onerror: function(error) {
  163. console.log('Error fetching final Ping0 risk:', error);
  164. displayIPDetails(ipv6,details, riskData, null);
  165. const refreshButton = document.getElementById('refreshIpInfo');
  166. if (refreshButton) {
  167. refreshButton.disabled = false;
  168. refreshButton.innerHTML = '点击刷新IP信息';
  169. }
  170. }
  171. });
  172. } else {
  173. console.log('Failed to retrieve window.x value.');
  174. displayIPDetails(ipv6,details, riskData, null);
  175. const refreshButton = document.getElementById('refreshIpInfo');
  176. if (refreshButton) {
  177. refreshButton.disabled = false;
  178. refreshButton.innerHTML = '点击刷新IP信息';
  179. }
  180. }
  181. },
  182. onerror: function(error) {
  183. console.log('Error fetching initial Ping0 page:', error);
  184. displayIPDetails(ipv6,details, riskData, null);
  185. const refreshButton = document.getElementById('refreshIpInfo');
  186. if (refreshButton) {
  187. refreshButton.disabled = false;
  188. refreshButton.innerHTML = '点击刷新IP信息';
  189. }
  190. }
  191. });
  192. }
  193.  
  194. function parseIPRisk(html) {
  195. console.log('Parsing IP risk data...');
  196. const scoreMatch = html.match(/"score":"(.*?)"/);
  197. const riskMatch = html.match(/"risk":"(.*?)"/);
  198. if (riskMatch) {
  199. const riskData = {
  200. score: scoreMatch[1],
  201. risk: riskMatch[1]
  202. };
  203. console.log('Parsed risk data:', riskData);
  204. return riskData;
  205. }
  206. console.log('Failed to parse risk data.');
  207. return null;
  208. }
  209.  
  210. function parseWindowX(html) {
  211. console.log('Parsing window.x value...');
  212. const match = html.match(/window\.x\s*=\s*'([^']+)'/);
  213. const windowX = match ? match[1] : null;
  214. console.log('Parsed window.x:', windowX);
  215. return windowX;
  216. }
  217.  
  218. function parsePing0Risk(html) {
  219. console.log('Parsing Ping0 risk data...');
  220. const parser = new DOMParser();
  221. const doc = parser.parseFromString(html, 'text/html');
  222.  
  223. 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;
  224. 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;
  225. 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;
  226.  
  227. const ping0Data = {
  228. riskValue: riskValue.trim(),
  229. ipType: ipType.trim(),
  230. nativeIP: nativeIP.trim()
  231. };
  232. console.log('Parsed Ping0 data:', ping0Data);
  233. return ping0Data;
  234. }
  235.  
  236. function displayIPDetails(ipv6,details, riskData, ping0Data) {
  237. console.log('Displaying IP details...');
  238. var ipElement = document.getElementById('ipInfo');
  239. if (!ipElement) {
  240. ipElement = document.createElement('div');
  241. ipElement.id = 'ipInfo';
  242. ipElement.style.position = 'fixed';
  243. ipElement.style.top = GM_getValue('ipInfoTop', '10px');
  244. ipElement.style.right = '-500px';
  245. ipElement.style.backgroundColor = '#fff';
  246. ipElement.style.padding = '10px';
  247. ipElement.style.borderRadius = '5px 0 0 5px'; // 仅左侧有圆角
  248. ipElement.style.boxShadow = '0 0 10px rgba(0,0,0,0.1)';
  249. ipElement.style.fontSize = '14px';
  250. ipElement.style.color = '#333';
  251. ipElement.style.zIndex = '9999';
  252. ipElement.style.transition = 'right 0.3s ease'; // 添加平滑过渡效果
  253.  
  254. const title = document.createElement('div');
  255. title.style.fontWeight = 'bold';
  256. title.style.marginBottom = '5px';
  257. title.innerText = 'IP检测信息';
  258.  
  259. const refreshButton = document.createElement('button');
  260. refreshButton.id = 'refreshIpInfo';
  261. refreshButton.style.display = 'inline-block';
  262. refreshButton.style.width = 'auto';
  263. refreshButton.style.marginLeft = '10px';
  264. refreshButton.style.backgroundColor = '#007bff';
  265. refreshButton.style.color = '#fff';
  266. refreshButton.style.border = 'none';
  267. refreshButton.style.borderRadius = '3px';
  268. refreshButton.style.padding = '2px 5px';
  269. refreshButton.style.cursor = 'pointer';
  270. refreshButton.style.fontSize = '12px';
  271. refreshButton.innerHTML = '刷新IP信息';
  272. refreshButton.onclick = fetchCurrentIP;
  273.  
  274. const toggleButton = document.createElement('button');
  275. toggleButton.id = 'toggleIpInfo';
  276. toggleButton.style.display = 'none';
  277. toggleButton.style.width = 'auto';
  278. toggleButton.style.marginLeft = '10px';
  279. toggleButton.style.backgroundColor = '#007bff';
  280. toggleButton.style.color = '#fff';
  281. toggleButton.style.border = 'none';
  282. toggleButton.style.borderRadius = '3px';
  283. toggleButton.style.padding = '2px 5px';
  284. toggleButton.style.cursor = 'pointer';
  285. toggleButton.style.fontSize = '12px';
  286. toggleButton.innerHTML = '展开信息';
  287. toggleButton.onclick = toggleIpInfo;
  288.  
  289. const inputContainer = document.createElement('div');
  290. inputContainer.style.marginTop = '10px';
  291.  
  292. const ipInput = document.createElement('input');
  293. ipInput.type = 'text';
  294. ipInput.placeholder = '输入IP地址';
  295. ipInput.style.marginRight = '5px';
  296. ipInput.id = 'queryIpInput';
  297.  
  298. const queryButton = document.createElement('button');
  299. queryButton.id = 'queryIpButton';
  300. queryButton.innerHTML = '查询IP';
  301. queryButton.style.width = 'auto';
  302. queryButton.style.backgroundColor = '#007bff';
  303. queryButton.style.color = '#fff';
  304. queryButton.style.border = 'none';
  305. queryButton.style.borderRadius = '3px';
  306. queryButton.style.padding = '2px 5px';
  307. queryButton.style.cursor = 'pointer';
  308. queryButton.style.fontSize = '12px';
  309. queryButton.onclick = queryIpInfo;
  310.  
  311.  
  312. const dragHandle = document.createElement('div');
  313. dragHandle.style.width = '100%';
  314. dragHandle.style.height = '10px';
  315. dragHandle.style.backgroundColor = '#ccc';
  316. dragHandle.style.cursor = 'move';
  317. dragHandle.style.marginBottom = '10px';
  318. dragHandle.onmousedown = startDragging;
  319.  
  320. const content = document.createElement('div');
  321. content.id = 'ipInfoContent';
  322.  
  323. title.appendChild(refreshButton);
  324. title.appendChild(toggleButton);
  325. inputContainer.appendChild(ipInput);
  326. inputContainer.appendChild(queryButton);
  327. title.appendChild(inputContainer);
  328. ipElement.appendChild(title);
  329. ipElement.appendChild(dragHandle);
  330. ipElement.appendChild(content);
  331. document.body.appendChild(ipElement);
  332.  
  333. // 创建展开按钮
  334. const expandButton = document.createElement('button');
  335. expandButton.id = 'expandIpInfo';
  336. expandButton.style.position = 'fixed';
  337. expandButton.style.top = GM_getValue('ipInfoTop', '10px');
  338. expandButton.style.width = 'auto';
  339. expandButton.style.right = '0';
  340. expandButton.style.backgroundColor = '#007bff';
  341. expandButton.style.color = '#fff';
  342. expandButton.style.border = 'none';
  343. expandButton.style.borderRadius = '3px 0 0 3px';
  344. expandButton.style.padding = '2px 5px';
  345. expandButton.style.cursor = 'pointer';
  346. expandButton.style.fontSize = '12px';
  347. expandButton.style.zIndex = '9999';
  348. expandButton.innerHTML = '展开信息';
  349. expandButton.onclick = toggleIpInfo;
  350. expandButton.style.display = 'block'; // 默认隐藏
  351. document.body.appendChild(expandButton);
  352. }
  353.  
  354. var contentElement = document.getElementById('ipInfoContent');
  355. if (!contentElement) {
  356. contentElement = document.createElement('div');
  357. contentElement.id = 'ipInfoContent';
  358. ipElement.appendChild(contentElement);
  359. }
  360.  
  361. const content = `
  362. <div>
  363. <strong>IPv4:</strong> ${details.query} <span id="copyButtonContainer1"></span>
  364. </div>
  365. <div>
  366. <strong>IPv6:</strong> ${ipv6 ? ipv6 : 'N/A'} <span id="copyButtonContainer2"></span>
  367. </div>
  368. <div>
  369. <strong>城市:</strong> ${details.city}, ${details.regionName}
  370. </div>
  371. <div>
  372. <strong>zip:</strong> ${details.zip ? details.zip : 'N/A'}
  373. </div>
  374. <div>
  375. <strong>国家:</strong> ${details.country}
  376. </div>
  377. <div>
  378. <strong>ISP:</strong> ${details.isp}
  379. </div>
  380. <div>
  381. <strong>AS:</strong> ${details.as}
  382. </div>
  383. <div>
  384. <strong>风险评分:</strong> ${riskData ? riskData.score : 'N/A'}
  385. </div>
  386. <div>
  387. <strong>风险类型:</strong> ${riskData ? riskData.risk : 'N/A'}
  388. </div>
  389. <div>
  390. <strong>Ping0风险值:</strong> ${ping0Data ? ping0Data.riskValue : 'N/A'}
  391. </div>
  392. <div>
  393. <strong>IP类型:</strong> ${ping0Data ? ping0Data.ipType : 'N/A'}
  394. </div>
  395. <div>
  396. <strong>原生IP:</strong> ${ping0Data ? ping0Data.nativeIP : 'N/A'}
  397. </div>
  398. <hr>
  399. `;
  400. contentElement.innerHTML = content; // Use innerHTML instead of insertAdjacentHTML to replace old content
  401. // 添加复制按钮到 copyButtonContainer
  402. const copyButtonContainer1 = document.getElementById('copyButtonContainer1');
  403. copyButtonContainer1.appendChild(createCopyButton(details.query));
  404. const copyButtonContainer2 = document.getElementById('copyButtonContainer2');
  405. copyButtonContainer2.appendChild(createCopyButton(ipv6));
  406. }
  407. function isValidIPv4(ip) {
  408. 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}$/;
  409. return ipv4Pattern.test(ip);
  410. }
  411. function queryIpInfo() {
  412. const queryIp = document.getElementById('queryIpInput').value.trim();
  413. const queryButton = document.getElementById('queryIpButton');
  414.  
  415. if (!queryIp) {
  416. alert('请输入一个有效的IP地址');
  417. return;
  418. }
  419.  
  420. if (!isValidIPv4(queryIp)) {
  421. alert('请输入一个有效的IPv4地址');
  422. return;
  423. }
  424.  
  425. console.log('Querying IP info for:', queryIp);
  426.  
  427. // 禁用查询按钮并显示“正在查询”
  428. queryButton.disabled = true;
  429. queryButton.innerHTML = '正在查询...';
  430.  
  431. // 调用 fetchIPDetails 并传递回调函数以恢复按钮状态
  432. fetchIPDetails(queryIp, null, function() {
  433. // 查询完成后恢复按钮状态
  434. queryButton.disabled = false;
  435. queryButton.innerHTML = '查询IP';
  436. });
  437. }
  438.  
  439. function createCopyButton(text) {
  440. const button = document.createElement('button');
  441. button.innerHTML = '复制';
  442. button.style.width = 'auto';
  443. button.style.marginLeft = '5px';
  444. button.style.cursor = 'pointer';
  445. //button.style.backgroundColor = '#007bff';
  446. //button.style.color = '#fff';
  447. button.style.border = 'none';
  448. button.style.padding = '2px 5px';
  449. button.style.borderRadius = '3px';
  450. button.onclick = (event) => {
  451. event.stopPropagation(); // 阻止事件冒泡
  452. navigator.clipboard.writeText(text).then(() => {
  453. button.innerHTML = '已复制';
  454. setTimeout(() => {
  455. button.innerHTML = '复制';
  456. }, 500);
  457. }).catch(err => {
  458. console.error('复制失败: ', err);
  459. });
  460. };
  461. return button;
  462. }
  463.  
  464. function toggleIpInfo() {
  465. const ipElement = document.getElementById('ipInfo');
  466. const expandButton = document.getElementById('expandIpInfo');
  467. const toggleButton = document.getElementById('toggleIpInfo');
  468. if (ipElement.style.right === '0px') {
  469. ipElement.style.right = '-500px'; // 将其隐藏到右侧,调整宽度以适应内容
  470. toggleButton.innerHTML = '展开信息';
  471. toggleButton.style.display = 'none';
  472. expandButton.style.display = 'block';
  473. } else {
  474. ipElement.style.right = '0px';
  475. toggleButton.innerHTML = '隐藏信息';
  476. toggleButton.style.display = 'inline-block';
  477. expandButton.style.display = 'none';
  478. }
  479. }
  480.  
  481. let initialTop = 10;
  482. let initialY = 0;
  483. let dragging = false;
  484.  
  485. function startDragging(e) {
  486. console.log('Start dragging...');
  487. dragging = true;
  488. initialY = e.clientY;
  489. const ipElement = document.getElementById('ipInfo');
  490. const expandButton = document.getElementById('expandIpInfo');
  491. initialTop = parseInt(ipElement.style.top, 10);
  492. expandButton.style.top = ipElement.style.top; // 同步expandButton的位置
  493. document.addEventListener('mousemove', handleDragging);
  494. document.addEventListener('mouseup', stopDragging);
  495. }
  496.  
  497. function handleDragging(e) {
  498. if (dragging) {
  499. console.log('Dragging...');
  500. const deltaY = e.clientY - initialY;
  501. const newTop = initialTop + deltaY;
  502. const ipElement = document.getElementById('ipInfo');
  503. const expandButton = document.getElementById('expandIpInfo');
  504. ipElement.style.top = newTop + 'px';
  505. expandButton.style.top = newTop + 'px'; // 同步expandButton的位置
  506. }
  507. }
  508.  
  509. function stopDragging() {
  510. console.log('Stop dragging...');
  511. dragging = false;
  512. document.removeEventListener('mousemove', handleDragging);
  513. document.removeEventListener('mouseup', stopDragging);
  514.  
  515. const ipElement = document.getElementById('ipInfo');
  516. GM_setValue('ipInfoTop', ipElement.style.top);
  517.  
  518. const expandButton = document.getElementById('expandIpInfo');
  519. GM_setValue('expandButtonTop', expandButton.style.top); // 同步保存expandButton的位置
  520. }
  521.  
  522. // 初始创建ipElement,但不触发数据获取
  523. displayIPDetails(null,null, null, null);
  524. //fetchCurrentIP();
  525. })();