mirror of
https://github.com/jason5ng32/MyIP.git
synced 2026-11-04 08:55:47 +00:00
A new In-depth Checks tool shows which blocklists an IP is on: the real-time DNSBLs and the threat intelligence lists the private API's /iphitlist checks. Listings are split by kind, so a VPN or Tor exit reads as an anonymity mark rather than a bad record; hits stay open with their reasons and removal links, the remaining lists fold away, and a legend explains every mark. /api/ipblocklist proxies the upstream with the caller's headers and a 30s timeout (a cold DNSBL pass outlasts the default 8s), passing sign-in and quota rejections through. Signed-in users only, original site only, 150 checks a month (ip_hitlist in the usage dialog and the pre-flight quota gate). Shift+B opens it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
54 lines
2.2 KiB
JavaScript
54 lines
2.2 KiB
JavaScript
// GET /api/ipblocklist?ip= — which blocklists an IP is on, from the private
|
|
// IPCheck.ing API (`/iphitlist`: live DNSBL lookups plus static threat lists).
|
|
// `?ip` is validated by requirePublicIP(). Sign-in is enforced upstream, so
|
|
// the caller's headers (auth token) are forwarded as-is.
|
|
|
|
import { fetchUpstream } from '../common/fetch-with-timeout.js';
|
|
import logger from '../server/logger.js';
|
|
|
|
// A cold DNSBL pass queries dozens of zones under per-zone deadlines; well
|
|
// past the default 8s, and the frontend waits a little longer than this.
|
|
export const IP_BLOCKLIST_TIMEOUT_MS = 30000;
|
|
|
|
export default async (req, res) => {
|
|
const apiKey = process.env.IPCHECKING_API_KEY;
|
|
const apiEndpoint = process.env.IPCHECKING_API_ENDPOINT;
|
|
if (!apiKey || !apiEndpoint) {
|
|
return res.status(500).json({ error: 'API key is missing' });
|
|
}
|
|
|
|
const url = new URL(`${apiEndpoint}/iphitlist`);
|
|
url.searchParams.set('ip', req.query.ip);
|
|
url.searchParams.set('key', apiKey);
|
|
|
|
try {
|
|
const apiResponse = await fetchUpstream(url, {
|
|
headers: { ...req.headers },
|
|
timeoutMs: IP_BLOCKLIST_TIMEOUT_MS,
|
|
});
|
|
|
|
// Monthly quota exhausted: not a failure — pass status + code through
|
|
// so the frontend shows the quota hint.
|
|
if (apiResponse.status === 429) {
|
|
const errorData = await apiResponse.json().catch(() => ({}));
|
|
return res.status(429).json({ error: errorData.error || 'Monthly quota exceeded', code: 'quota_exceeded' });
|
|
}
|
|
|
|
// Sign-in problems are the visitor's state, not a failure: pass the
|
|
// status through so the frontend prompts sign-in.
|
|
if (apiResponse.status === 401 || apiResponse.status === 403) {
|
|
const errorData = await apiResponse.json().catch(() => ({}));
|
|
return res.status(apiResponse.status).json({ error: errorData.message || 'Sign in required' });
|
|
}
|
|
|
|
if (!apiResponse.ok) {
|
|
throw new Error(`API responded with status: ${apiResponse.status}`);
|
|
}
|
|
|
|
res.json(await apiResponse.json());
|
|
} catch (error) {
|
|
logger.error({ err: error, ip: req.query.ip }, 'ip-blocklist upstream request failed');
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
};
|