95 lines
2.2 KiB
TypeScript
95 lines
2.2 KiB
TypeScript
import net from 'node:net'
|
|
import TsCache from '$lib/ts-cache.js'
|
|
import geoip from 'geoip-lite'
|
|
import whoiser from 'whoiser'
|
|
import {
|
|
AbuseIPDBClient,
|
|
type APICheckEndpointResponse
|
|
} from 'abuseipdb-client'
|
|
import type { Whois } from './Result/ip'
|
|
|
|
export const WHOIS_CACHE_TTL = process.env.WHOIS_CACHE_TTL
|
|
? parseInt(process.env.WHOIS_CACHE_TTL)
|
|
: 60 * 60 * 24
|
|
const ABUSEIPDB_KEY = process.env.ABUSEIPDB_KEY
|
|
let ipdb: AbuseIPDBClient | null = null
|
|
|
|
if (ABUSEIPDB_KEY) ipdb = new AbuseIPDBClient(ABUSEIPDB_KEY)
|
|
|
|
const whoisCache = new TsCache<Lookup>(WHOIS_CACHE_TTL)
|
|
|
|
function isIp(query: string) {
|
|
const isIp = net.isIP(query)
|
|
if (isIp == 4 || isIp == 6) return true
|
|
return false
|
|
}
|
|
|
|
async function whoisLookup(query: string, ip: boolean = false) {
|
|
const whoisCheck = await whoiser(query, {
|
|
timeout: 1000
|
|
})
|
|
const whoisData = ip
|
|
? whoisCheck
|
|
: Object.values(whoisCheck)
|
|
.reverse()
|
|
// @ts-expect-error whoiser types are wrong
|
|
.find(a => !a.error)
|
|
if (!whoisData) throw new Error("Couldn't get successful Whois response")
|
|
return whoisData
|
|
}
|
|
|
|
function geoLookup(query: string) {
|
|
const geoLookup = geoip.lookup(query)
|
|
// Don't want to use geo location if it's just the center of America
|
|
if (geoLookup && geoLookup.ll[0] != 37.751 && geoLookup.ll[1] != -97.822) {
|
|
return geoLookup
|
|
}
|
|
return null
|
|
}
|
|
|
|
type IPDBLookup = APICheckEndpointResponse['data']
|
|
|
|
async function ipdbLookup(query: string): Promise<IPDBLookup | null> {
|
|
const ipdbCheck = await ipdb?.check(query, { maxAgeInDays: 60 })
|
|
return ipdbCheck?.result?.data ?? null
|
|
}
|
|
|
|
export type Lookup = {
|
|
query: string
|
|
whois: Whois
|
|
geo: geoip.Lookup | null
|
|
check: IPDBLookup | null
|
|
isIp: boolean
|
|
}
|
|
|
|
export default async function lookup(query: string) {
|
|
const ip = isIp(query)
|
|
if (whoisCache.has(query)) {
|
|
const value = whoisCache.get(query)
|
|
if (value) return value
|
|
}
|
|
let whoquery = query
|
|
if (!ip) {
|
|
whoquery = whoquery
|
|
.split('.')
|
|
.slice(whoquery.split('.').length - 2)
|
|
.join('.')
|
|
}
|
|
const whois = <Whois>await whoisLookup(whoquery, ip)
|
|
|
|
const geo = ip ? geoLookup(query) : null
|
|
const check = ip ? await ipdbLookup(query) : null
|
|
|
|
const value = {
|
|
query,
|
|
whois,
|
|
geo,
|
|
check,
|
|
isIp: ip
|
|
}
|
|
|
|
whoisCache.set(query, value)
|
|
|
|
return value
|
|
}
|