DEMO
源码
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
let clientIp = url.searchParams.get('ip');
let displayIp = clientIp || request.headers.get('CF-Connecting-IP');
if (request.method === 'GET') {
// 验证 IP 地址格式,如果用户提交了 IP 地址
if (clientIp && !isValidIpAddress(clientIp)) {
return new Response('Invalid IP address format.', {
status: 400,
headers: { 'Content-Type': 'text/plain' },
});
}
let response;
try {
// 如果用户没有提交 IP 地址,或者提交了有效的 IP 地址,进行查询
response = await fetchInformation(displayIp);
} catch (error) {
return new Response('Error fetching data.', {
status: 500,
headers: { 'Content-Type': 'text/plain' },
});
}
const result = await response.json();
// 生成 HTML 内容
const htmlContent = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>IP Information Lookup - IPGET.WIN</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.9.3/css/bulma.min.css">
<style>
.is-hidden {
display: none;
}
</style>
</head>
<body>
${searchForm()}
${
!result || result.error
? formatNoDataMessage()
: formatDataAsHtml(result)
}
</body>
</html>
`;
return new Response(htmlContent, {
headers: { 'Content-Type': 'text/html' },
});
} else {
// 显示搜索表单和默认信息
return new Response(searchForm(), {
headers: { 'Content-Type': 'text/html' },
});
}
}
async function fetchInformation(ip) {
const shodanApiKey = SHODAN_API_KEY;
const shodanApiUrl = `https://api.shodan.io/shodan/host/${ip}?key=${shodanApiKey}`;
return fetch(shodanApiUrl);
}
function isValidIpAddress(ip) {
// 正则表达式验证 IPv4 地址格式
const ipv4Regex = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
return ipv4Regex.test(ip);
}
function searchForm() {
// 使用 Bulma CDN
return `
<section class="section">
<div class="container">
<h1 class="title">IP Information Lookup</h1>
<form action="/" method="get" class="field has-addons">
<div class="control is-expanded">
<input class="input" type="text" name="ip" placeholder="Enter an IP address" pattern="\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b" title="Please enter a valid IP address." required>
</div>
<div class="control">
<button class="button is-info" type="submit">Search</button>
</div>
</form>
</div>
</section>
`;
}
function formatNoDataMessage() {
return `
<section class="section">
<div class="container">
<div class="notification is-warning">
<button class="delete"></button>
No information available for the given IP address.
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
const $notification = $delete.parentNode;
$delete.addEventListener('click', () => {
$notification.parentNode.removeChild($notification);
});
});
});
</script>
`;
}
function formatDataAsHtml(data) {
// 递归函数来创建表格,并添加按钮来切换显示/隐藏
function createTable(data, level = 0) {
let tableClass = level === 0 ? 'table is-fullwidth is-bordered is-striped' : 'table is-bordered is-striped';
let html = `<table class="${tableClass}">`;
for (const [key, value] of Object.entries(data)) {
html += `<tr>`;
if (!Array.isArray(data)) {
// 如果当前处理的不是数组,显示键
html += `<th>${escapeHtml(key)}</th>`;
}
html += `<td>`;
if (Array.isArray(value) || (value !== null && typeof value === 'object')) {
if (level == 1) {
// 为嵌套数据创建一个按钮来切换显示/隐藏
const uniqueId = `details-${Math.random().toString(36).substr(2, 9)}`;
html += `
<button class="button is-small is-info" onclick="toggleDetails('${uniqueId}')">
Show Details
</button>
<div id="${uniqueId}" class="is-hidden">
${createTable(value, level + 1)}
</div>
`;
} else {
// 如果嵌套层级小于2,直接显示表格
html += createTable(value, level + 1);
}
} else {
// 否则直接显示值
html += escapeHtml(String(value));
}
html += '</td></tr>';
}
html += '</table>';
return html;
}
// 转义 HTML 特殊字符
function escapeHtml(text) {
return text
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// 生成初始 HTML 结构
let html = `
<section class="section">
<div class="container">
<h2 class="title">Details</h2>
${createTable(data)}
</div>
</section>
<script>
function toggleDetails(id) {
const details = document.getElementById(id);
if (details) {
details.classList.toggle('is-hidden');
}
}
</script>
`;
return html;
}
使用方法
1.首先访问shodan.io,注册一个普通用户,登录后复制api key备用
2.登录cloudflare,创建worker
3.添加SHODAN_API_KEY环境变量值为shodan的api key,具体操作: 设置 -> 变量 > 环境变量
点击 编辑变量
,添加变量名称 SHODAN_API_KEY
值 填写刚才复制的api key,点击加密
然后点击下面的部署
按钮
4.点击 编辑代码
粘贴源码,点击部署
网站源码是独角数卡,加密货币收款用的也独角数卡作者开发的epusdt https://github.com/assimon/epusdt
好帖
收藏
好帖,鸡腿奉上
好帖绑定
不给个演示站吗
@drfy #5 ipget.win,我补上吧
@wt #6 这个好像只能查,不能识别当前ip.建议弄成这样的比较吸引人https://iplark.com/
支持
@wt #9 等你好消息