mirror of
https://github.com/skidoodle/hostinfo
synced 2026-04-28 17:47:36 +02:00
refactor DNS resolution and IP handling; remove unused utility
This commit is contained in:
+82
-27
@@ -4,51 +4,87 @@ let currentTabUrl: string | null = null
|
|||||||
|
|
||||||
async function resolveARecord(hostname: string): Promise<string | null> {
|
async function resolveARecord(hostname: string): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
const dnsResponse = await fetch(
|
let dnsResponse = await fetch(
|
||||||
`https://cloudflare-dns.com/dns-query?name=${hostname}&type=A`,
|
`https://cloudflare-dns.com/dns-query?name=${hostname}&type=A`,
|
||||||
{
|
{ headers: { Accept: 'application/dns-json' } }
|
||||||
headers: { Accept: 'application/dns-json' },
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
if (dnsResponse.ok) {
|
||||||
if (!dnsResponse.ok) {
|
const dnsData = await dnsResponse.json()
|
||||||
console.error(`DNS query failed: ${dnsResponse.status}`)
|
const aRecord = dnsData.Answer?.find(
|
||||||
return null
|
(entry: DNSEntry) => entry.type === 1
|
||||||
|
)?.data
|
||||||
|
if (aRecord) return aRecord
|
||||||
}
|
}
|
||||||
|
|
||||||
const dnsData = await dnsResponse.json()
|
dnsResponse = await fetch(
|
||||||
return (
|
`https://cloudflare-dns.com/dns-query?name=${hostname}&type=AAAA`,
|
||||||
dnsData.Answer?.find((entry: DNSEntry) => entry.type === 1)?.data || null
|
{ headers: { Accept: 'application/dns-json' } }
|
||||||
)
|
)
|
||||||
|
if (dnsResponse.ok) {
|
||||||
|
const dnsData = await dnsResponse.json()
|
||||||
|
const aaaaRecord = dnsData.Answer?.find(
|
||||||
|
(entry: DNSEntry) => entry.type === 28
|
||||||
|
)?.data
|
||||||
|
if (aaaaRecord) return aaaaRecord
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch DNS data:', error)
|
console.error('Failed to fetch DNS data:', error)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isIP(host: string): boolean {
|
||||||
|
const cleanedHost = host.replace(/^\[|\]$/g, '')
|
||||||
|
|
||||||
|
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]?)$/
|
||||||
|
|
||||||
|
const ipv6Regex =
|
||||||
|
/(([0-9a-fA-F]{1,4}:){7,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,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/
|
||||||
|
|
||||||
|
return ipv4Regex.test(cleanedHost) || ipv6Regex.test(cleanedHost)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getIPInfo(host: string): Promise<any | null> {
|
||||||
|
const cleanedHost = host.replace(/^\[|\]$/g, '')
|
||||||
|
|
||||||
|
if (isIP(cleanedHost)) {
|
||||||
|
const response = await fetch(`https://ip.albert.lol/${cleanedHost}`)
|
||||||
|
const data = await response.json()
|
||||||
|
return data.ip ? data : null
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedIp = await resolveARecord(cleanedHost)
|
||||||
|
if (!resolvedIp) return null
|
||||||
|
|
||||||
|
const response = await fetch(`https://ip.albert.lol/${resolvedIp}`)
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
async function handleTabUpdate(url: string) {
|
async function handleTabUpdate(url: string) {
|
||||||
if (url === currentTabUrl) return
|
if (url === currentTabUrl) return
|
||||||
currentTabUrl = url
|
currentTabUrl = url
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const hostname = new URL(url).hostname
|
const hostname = new URL(url).hostname
|
||||||
const ip = await resolveARecord(hostname)
|
const apiData = await getIPInfo(hostname)
|
||||||
|
if (!apiData || !apiData.ip) {
|
||||||
if (!ip) {
|
|
||||||
await updateIcon(null)
|
await updateIcon(null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`)
|
if (apiData.bogon === true) {
|
||||||
const apiData = await apiResponse.json()
|
await updateIcon(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
const country = apiData.country || null
|
const country = apiData.country || null
|
||||||
const asn = apiData.org?.split(' ')[0]
|
const asn = apiData.org?.split(' ')[0]
|
||||||
let iconCode = country
|
let iconCode = country
|
||||||
if (!iconCode && asn === 'AS13335') {
|
if (!iconCode && asn === 'AS13335') {
|
||||||
iconCode = 'cloudflare'
|
iconCode = 'cloudflare'
|
||||||
}
|
}
|
||||||
|
|
||||||
await updateIcon(iconCode)
|
await updateIcon(iconCode)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to handle tab update:', error)
|
console.error('Failed to handle tab update:', error)
|
||||||
@@ -72,18 +108,37 @@ export default defineBackground({
|
|||||||
if (request.type === 'FETCH_SERVER_INFO') {
|
if (request.type === 'FETCH_SERVER_INFO') {
|
||||||
;(async () => {
|
;(async () => {
|
||||||
try {
|
try {
|
||||||
const ip = await resolveARecord(request.hostname)
|
const cleanHostname =
|
||||||
if (!ip) {
|
request.hostname.startsWith('[') &&
|
||||||
|
request.hostname.endsWith(']')
|
||||||
|
? request.hostname.slice(1, -1)
|
||||||
|
: request.hostname
|
||||||
|
|
||||||
|
const apiData = await getIPInfo(cleanHostname)
|
||||||
|
if (!apiData || !apiData.ip) {
|
||||||
sendResponse({ error: 'DNS resolution failed', data: null })
|
sendResponse({ error: 'DNS resolution failed', data: null })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if (apiData.bogon === true) {
|
||||||
|
await updateIcon(null)
|
||||||
|
sendResponse({
|
||||||
|
error: null,
|
||||||
|
data: {
|
||||||
|
origin: '',
|
||||||
|
ip: cleanHostname,
|
||||||
|
hostname: '',
|
||||||
|
country: '',
|
||||||
|
city: '',
|
||||||
|
org: '',
|
||||||
|
isLocal: true,
|
||||||
|
isBrowserResource: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const apiResponse = await fetch(`https://ip.albert.lol/${ip}`)
|
const parsed = psl.parse(cleanHostname)
|
||||||
const apiData = await apiResponse.json()
|
|
||||||
|
|
||||||
const parsed = psl.parse(request.hostname)
|
|
||||||
const origin = 'domain' in parsed ? parsed.domain : null
|
const origin = 'domain' in parsed ? parsed.domain : null
|
||||||
|
|
||||||
const country = apiData.country || null
|
const country = apiData.country || null
|
||||||
const asn = apiData.org?.split(' ')[0]
|
const asn = apiData.org?.split(' ')[0]
|
||||||
let iconCode = country
|
let iconCode = country
|
||||||
@@ -91,7 +146,6 @@ export default defineBackground({
|
|||||||
iconCode = 'cloudflare'
|
iconCode = 'cloudflare'
|
||||||
}
|
}
|
||||||
await updateIcon(iconCode)
|
await updateIcon(iconCode)
|
||||||
|
|
||||||
sendResponse({
|
sendResponse({
|
||||||
error: null,
|
error: null,
|
||||||
data: {
|
data: {
|
||||||
@@ -101,6 +155,8 @@ export default defineBackground({
|
|||||||
country: apiData.country || null,
|
country: apiData.country || null,
|
||||||
city: apiData.city || null,
|
city: apiData.city || null,
|
||||||
org: apiData.org,
|
org: apiData.org,
|
||||||
|
isLocal: false,
|
||||||
|
isBrowserResource: false,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -113,7 +169,6 @@ export default defineBackground({
|
|||||||
})()
|
})()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
sendResponse({ error: 'Unknown request type', data: null })
|
sendResponse({ error: 'Unknown request type', data: null })
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,3 @@
|
|||||||
import { useState, useEffect } from 'react'
|
|
||||||
import { isPrivateIP } from '@/utils'
|
|
||||||
import {
|
|
||||||
FetchServerInfoRequest,
|
|
||||||
FetchServerInfoResponse,
|
|
||||||
ServerData,
|
|
||||||
} from '@/utils/model'
|
|
||||||
import browser from 'webextension-polyfill'
|
|
||||||
|
|
||||||
export function useTabData() {
|
export function useTabData() {
|
||||||
const [data, setData] = useState<ServerData | null>(null)
|
const [data, setData] = useState<ServerData | null>(null)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
@@ -38,20 +29,6 @@ export function useTabData() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const isInternal = isPrivateIP(hostname)
|
|
||||||
if (isInternal) {
|
|
||||||
return setData({
|
|
||||||
origin: '',
|
|
||||||
ip: hostname,
|
|
||||||
hostname: '',
|
|
||||||
country: '',
|
|
||||||
city: '',
|
|
||||||
org: '',
|
|
||||||
isLocal: true,
|
|
||||||
isBrowserResource: false,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await browser.runtime.sendMessage<
|
const response = await browser.runtime.sendMessage<
|
||||||
FetchServerInfoRequest,
|
FetchServerInfoRequest,
|
||||||
FetchServerInfoResponse
|
FetchServerInfoResponse
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
export function isPrivateIP(host: string): boolean {
|
|
||||||
try {
|
|
||||||
const rawIp = host.startsWith('[') ? host.slice(1, -1) : host
|
|
||||||
|
|
||||||
if (rawIp === 'localhost') return true
|
|
||||||
|
|
||||||
if (rawIp.includes('.')) {
|
|
||||||
const parts = rawIp.split('.').map(Number)
|
|
||||||
if (parts.length !== 4 || parts.some(isNaN)) return false
|
|
||||||
|
|
||||||
return (
|
|
||||||
parts[0] === 10 ||
|
|
||||||
(parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) ||
|
|
||||||
(parts[0] === 192 && parts[1] === 168) ||
|
|
||||||
(parts[0] === 169 && parts[1] === 254)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawIp.includes(':')) {
|
|
||||||
const ip = rawIp.split('%')[0]
|
|
||||||
|
|
||||||
if (ip === '::1') return true
|
|
||||||
|
|
||||||
const firstHextet = parseInt(ip.split(':')[0], 16)
|
|
||||||
if ((firstHextet & 0xfe00) === 0xfc00) return true
|
|
||||||
|
|
||||||
if ((firstHextet & 0xffc0) === 0xfe80) return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+4
-4
@@ -15,11 +15,11 @@ export interface DNSEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchServerInfoRequest {
|
export interface FetchServerInfoRequest {
|
||||||
type: 'FETCH_SERVER_INFO';
|
type: 'FETCH_SERVER_INFO'
|
||||||
hostname: string;
|
hostname: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FetchServerInfoResponse {
|
export interface FetchServerInfoResponse {
|
||||||
error?: string;
|
error?: string
|
||||||
data?: ServerData;
|
data?: ServerData
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user