|
function isBrowserUA(request) { |
|
const userAgent = request.headers.get('User-Agent') || ''; |
|
const acceptHeader = request.headers.get('Accept') || ''; |
|
|
|
const prefersHtml = acceptHeader.includes('text/html'); |
|
|
|
const browserPatterns = [ |
|
'mozilla', |
|
'chrome', |
|
'safari', |
|
'firefox', |
|
'edge', |
|
'opera', |
|
'ucbrowser', |
|
'samsungbrowser', |
|
]; |
|
|
|
const nonBrowserPatterns = [ |
|
'curl', |
|
'wget', |
|
'httpie', |
|
'postman', |
|
'python-requests', |
|
'bot', |
|
'spider', |
|
'crawler', |
|
]; |
|
|
|
const isBrowserAgent = browserPatterns.some(pattern => userAgent.toLowerCase().includes(pattern)); |
|
|
|
const isNonBrowserAgent = nonBrowserPatterns.some(pattern => userAgent.toLowerCase().includes(pattern)); |
|
|
|
return prefersHtml || (isBrowserAgent && !isNonBrowserAgent); |
|
} |
|
|
|
async function process_json(request) { |
|
let data = { |
|
ip: request.headers.get('CF-Connecting-IP') || null, |
|
cf: { |
|
continent: request.cf?.continent || null, |
|
country: request.cf?.country || null, |
|
isEUCountry: request.cf?.isEUCountry || false, |
|
region: request.cf?.region || null, |
|
regionCode: request.cf?.regionCode || null, |
|
city: request.cf?.city || null, |
|
latitude: request.cf?.latitude || null, |
|
longitude: request.cf?.longitude || null, |
|
postalCode: request.cf?.postalCode || null, |
|
metroCode: request.cf?.metroCode || null, |
|
colo: request.cf?.colo || null, |
|
asn: request.cf?.asn || null, |
|
asOrganization: request.cf?.asOrganization || null, |
|
timezone: request.cf?.timezone || null, |
|
}, |
|
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}; |
|
const dataJson = JSON.stringify(data, null, 4); |
|
return new Response(dataJson, { |
|
headers: { |
|
'Content-Type': 'application/json;charset=UTF-8', |
|
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
}); |
|
} |
|
|
|
async function process_txt(request) { |
|
let data = { |
|
ip: request.headers.get('CF-Connecting-IP') || null, |
|
cf: { |
|
continent: request.cf?.continent || null, |
|
country: request.cf?.country || null, |
|
region: request.cf?.region || null, |
|
city: request.cf?.city || null, |
|
colo: request.cf?.colo || null, |
|
asn: request.cf?.asn || null, |
|
asOrganization: request.cf?.asOrganization || null, |
|
}, |
|
}; |
|
const text = `IP: ${data.ip || 'N/A'}\n` + |
|
`Continent: ${data.cf.continent || 'N/A'}\n` + |
|
`Country: ${data.cf.country || 'N/A'}\n` + |
|
`Region: ${data.cf.region || 'N/A'}\n` + |
|
`City: ${data.cf.city || 'N/A'}\n` + |
|
`Colo: ${data.cf.colo || 'N/A'}\n` + |
|
`ASN: ${data.cf.asn || 'N/A'}\n` + |
|
`ASOrganization: ${data.cf.asOrganization || 'N/A'}\n` + |
|
`Source: https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e\n`; |
|
return new Response(text, { |
|
headers: { |
|
'Content-Type': 'text/plain;charset=UTF-8', |
|
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
}); |
|
} |
|
|
|
async function process_html(request) { |
|
let data = { |
|
ip: request.headers.get('CF-Connecting-IP') || null, |
|
cf: { |
|
continent: request.cf?.continent || null, |
|
country: request.cf?.country || null, |
|
region: request.cf?.region || null, |
|
city: request.cf?.city || null, |
|
colo: request.cf?.colo || null, |
|
asn: request.cf?.asn || null, |
|
asOrganization: request.cf?.asOrganization || null, |
|
}, |
|
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}; |
|
|
|
const info = []; |
|
if (data.ip) info.push(`<strong>IP:</strong> ${data.ip}`); |
|
if (data.cf.continent) info.push(`<strong>大陆 | Continent:</strong> ${data.cf.continent}`); |
|
if (data.cf.country) info.push(`<strong>国家 | Country:</strong> ${data.cf.country}`); |
|
if (data.cf.region) info.push(`<strong>地区 | Region:</strong> ${data.cf.region}`); |
|
if (data.cf.city) info.push(`<strong>城市 | City:</strong> ${data.cf.city}`); |
|
if (data.cf.colo) info.push(`<strong>数据中心 | Colo:</strong> ${data.cf.colo}`); |
|
if (data.cf.asn) info.push(`<strong>ASN:</strong> ${data.cf.asn}`); |
|
if (data.cf.asOrganization) info.push(`<strong>AS 组织 | AS Organization:</strong> ${data.cf.asOrganization}`); |
|
const visitorInfo = info.length > 0 ? info.join('<br/><br/>') : '没有可用的访客信息 | No visitor information available.'; |
|
const html = ` |
|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<title>IP 信息 | IP Information</title> |
|
<style> |
|
body { |
|
font-family: Arial, sans-serif; |
|
padding: 20px; |
|
max-width: 800px; |
|
margin: 0 auto; |
|
background: var(--bg-color); |
|
color: var(--text-color); |
|
} |
|
@media (prefers-color-scheme: dark) { |
|
:root { |
|
--bg-color: #1a1a1a; |
|
--text-color: #e0e0e0; |
|
--pre-bg: #2a2a2a; |
|
} |
|
} |
|
@media (prefers-color-scheme: light) { |
|
:root { |
|
--bg-color: #ffffff; |
|
--text-color: #333333; |
|
--pre-bg: #f4f4f4; |
|
} |
|
} |
|
h1 { font-size: 24px; } |
|
.info { margin-bottom: 20px; } |
|
pre { |
|
background: var(--pre-bg); |
|
padding: 10px; |
|
border-radius: 5px; |
|
overflow-x: auto; |
|
} |
|
a { color: var(--text-color); } |
|
.source { font-size: 14px; margin-top: 20px; } |
|
</style> |
|
</head> |
|
<body> |
|
<h1>您的 IP 信息 | Your IP Information</h1> |
|
<div class="info">${visitorInfo}</div> |
|
<h2>原始数据 | Raw Data</h2> |
|
<pre>${JSON.stringify(data, null, 2)}</pre> |
|
<p class="source">源代码 | Source: <a href="${data.source}">${data.source}</a></p> |
|
</body> |
|
</html> |
|
`; |
|
return new Response(html, { |
|
headers: { |
|
'Content-Type': 'text/html;charset=UTF-8', |
|
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
}); |
|
} |
|
|
|
async function process_root(request) { |
|
return isBrowserUA(request) ? process_html(request) : process_txt(request); |
|
} |
|
|
|
async function process_full(request, url) { |
|
let data = { |
|
method: request.method, |
|
url: request.url, |
|
origin: url.origin, |
|
ip: request.headers.get('CF-Connecting-IP') || null, |
|
cf: { |
|
continent: request.cf?.continent || null, |
|
country: request.cf?.country || null, |
|
isEUCountry: request.cf?.isEUCountry || false, |
|
region: request.cf?.region || null, |
|
regionCode: request.cf?.regionCode || null, |
|
city: request.cf?.city || null, |
|
latitude: request.cf?.latitude || null, |
|
longitude: request.cf?.longitude || null, |
|
postalCode: request.cf?.postalCode || null, |
|
metroCode: request.cf?.metroCode || null, |
|
colo: request.cf?.colo || null, |
|
asn: request.cf?.asn || null, |
|
asOrganization: request.cf?.asOrganization || null, |
|
timezone: request.cf?.timezone || null, |
|
}, |
|
headers: {}, |
|
security: {}, |
|
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}; |
|
|
|
// Populate Headers |
|
request.headers.forEach((value, name) => { |
|
data.headers[name] = value; |
|
}); |
|
|
|
// Populate Security fields |
|
const securityKeys = [ |
|
'clientTcpRtt', |
|
'tlsCipher', |
|
'tlsVersion', |
|
'httpProtocol', |
|
'clientHandshake', |
|
'clientFinished', |
|
'serverHandshake', |
|
'serverFinished', |
|
'corporateProxy', |
|
'verifiedBot', |
|
'score', |
|
]; |
|
if (request.cf) { |
|
for (const key of securityKeys) { |
|
if (request.cf[key]) { |
|
if (typeof request.cf[key] === 'object') { |
|
for (const innerKey in request.cf[key]) { |
|
data.security[innerKey] = request.cf[key][innerKey]; |
|
} |
|
} else { |
|
data.security[key] = request.cf[key]; |
|
} |
|
} |
|
} |
|
} |
|
|
|
const dataJson = JSON.stringify(data, null, 4); |
|
return new Response(dataJson, { |
|
headers: { |
|
'Content-Type': 'application/json;charset=UTF-8', |
|
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
}); |
|
} |
|
|
|
export default { |
|
async fetch(request) { |
|
const url = new URL(request.url); |
|
|
|
switch (url.pathname) { |
|
case '/ip': |
|
case '/.ip': |
|
return new Response(request.headers.get('CF-Connecting-IP') || 'N/A', { |
|
headers: { |
|
'Content-Type': 'text/plain;charset=UTF-8', |
|
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
}); |
|
case '/json': |
|
case '/.json': |
|
return await process_json(request); |
|
case '/': |
|
return await process_root(request); |
|
case '/txt': |
|
case '/.txt': |
|
return await process_txt(request); |
|
case '/html': |
|
case '/.html': |
|
return await process_html(request); |
|
case '/full': |
|
case '/.full': |
|
return await process_full(request, url); |
|
default: |
|
return new Response( |
|
JSON.stringify( |
|
{ |
|
usage: { |
|
'/ip': '返回纯 IP | Return only IP', |
|
'/json': '返回 JSON 数据 (仅 IP 和位置信息) | Return JSON data (IP and location only)', |
|
'/full': '返回完整数据 (包括头部和安全信息) | Return FULL data (includes headers & security)', |
|
'/txt': '返回纯文本数据 (IP 和位置信息) | Return plain text data (IP and location)', |
|
'/html': '返回 HTML 页面 (IP 和位置信息) | Return HTML with IP and location data', |
|
}, |
|
source: 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
null, |
|
4 |
|
), |
|
{ |
|
status: 404, |
|
headers: { |
|
'Content-Type': 'application/json;charset=UTF-8', |
|
'x-script-info': 'https://gist.github.com/wyf9/beeb6746fa7fda73f78380cbdda5461e', |
|
}, |
|
} |
|
); |
|
} |
|
}, |
|
}; |