const axios = require('axios') const HttpsProxyAgent = require('https-proxy-agent') const config = require('../../config.json') const API = require('../../lib/API') const { BaseStdResponse } = require('../../BaseStdResponse') const QgProxyManager = require('../../lib/Lepao/QgProxyManager') function buildAxiosOutboundConfig(fragment) { if (!fragment || fragment.proxy === false || !fragment.proxy) { return { proxy: false } } const { host, port, auth } = fragment.proxy let userPart = '' if (auth && String(auth.username || '').length > 0) { const u = encodeURIComponent(auth.username) const p = encodeURIComponent(auth.password != null ? String(auth.password) : '') userPart = `${u}:${p}@` } const proxyUrl = `http://${userPart}${host}:${port}` const rejectUnauthorized = process.env.NODE_TLS_REJECT_UNAUTHORIZED !== '0' return { proxy: false, httpsAgent: new HttpsProxyAgent(proxyUrl, { rejectUnauthorized }) } } function resolveSelfEchoUrl() { const base = String(config.url || '').trim() if (!base) return `http://127.0.0.1:${config.port}/Corn/ProxySelfIpEcho` return `${base.replace(/\/+$/, '')}/Corn/ProxySelfIpEcho` } class ProxySelfCheck extends API { constructor() { super() this.noEncrypt() this.setPath('/Corn/ProxySelfCheck') this.setMethod('GET') } async onRequest(req, res) { try { const qgOn = await QgProxyManager.isOutboundProxyEnabled() if (!qgOn) { await QgProxyManager.recordLog({ event: 'proxy_self_check_skip', detail: { reason: 'proxy_disabled' } }) return res.json({ ...BaseStdResponse.OK, data: { skipped: true, reason: 'proxy_disabled' } }) } const frag = await QgProxyManager.getOutboundAxiosFragment({ forceRefresh: false }) if (frag.proxy === false) { await QgProxyManager.recordLog({ event: 'proxy_self_check_skip', detail: { reason: 'no_proxy_available' } }) return res.json({ ...BaseStdResponse.OK, data: { skipped: true, reason: 'no_proxy_available' } }) } const outbound = buildAxiosOutboundConfig(frag) const echoUrl = resolveSelfEchoUrl() const rsp = await axios.get(echoUrl, { timeout: 15000, validateStatus: () => true, ...outbound }) const body = rsp.data || {} const now = Date.now() const cached = await QgProxyManager.getCachedParsed() const proxyIp = body?.data?.ip || null await QgProxyManager.recordLog({ event: 'proxy_self_check', server: cached?.server || `${frag.proxy.host}:${frag.proxy.port}`, deadline: cached?.deadline || null, detail: { code: body?.code, http_status: rsp.status, target: echoUrl, proxy_ip: proxyIp, x_forwarded_for: body?.data?.x_forwarded_for || '', checked_at: now } }) return res.json({ ...BaseStdResponse.OK, data: { proxy_ip: proxyIp, http_status: rsp.status, target: echoUrl } }) } catch (e) { const msg = e?.message || String(e) await QgProxyManager.recordLog({ event: 'proxy_self_check_fail', detail: { message: msg, code: e?.code, status: e?.response?.status } }) this.logger?.error?.(`[ProxySelfCheck] ${e?.stack || e}`) return res.json({ ...BaseStdResponse.ERR, msg: `代理自检失败: ${msg}` }) } } } module.exports.ProxySelfCheck = ProxySelfCheck