forked from github-mirror/Verome-API
fix
This commit is contained in:
116
mod.ts
116
mod.ts
@@ -9,9 +9,10 @@
|
||||
import { serve } from "https://deno.land/std@0.208.0/http/server.ts";
|
||||
import { YTMusic, YouTubeSearch, LastFM, fetchFromPiped, fetchFromInvidious, getLyrics, getTrendingMusic, getRadio, getTopArtists, getTopTracks, getArtistInfo, getTrackInfo, getSongComplete, getAlbumComplete, getArtistComplete, getFullChain } from "./lib.ts";
|
||||
import { html as uiHtml } from "./ui.ts";
|
||||
import { installProxyFetch } from "./proxy.ts";
|
||||
import { installProxyFetch, loadProxyConfig, saveProxyConfig, setRuntimeProxy, getActiveProxyUrl } from "./proxy.ts";
|
||||
|
||||
// ── Proxy must be installed BEFORE any fetch calls ──────────────────────────
|
||||
// ── Proxy: load saved config → install (patch globalThis.fetch) ─────────────
|
||||
await loadProxyConfig();
|
||||
installProxyFetch();
|
||||
|
||||
const PORT = parseInt(Deno.env.get("PORT") || "8000");
|
||||
@@ -98,92 +99,83 @@ async function handler(req: Request): Promise<Response> {
|
||||
if (pathname === "/favicon.ico") return new Response(null, { status: 204 });
|
||||
if (pathname === "/health") return json({ status: "ok" });
|
||||
|
||||
// ============ PROXY SET / CLEAR ============
|
||||
|
||||
if (pathname === "/api/proxy/set" && req.method === "POST") {
|
||||
try {
|
||||
const body = await req.json();
|
||||
const newUrl: string | null = body.url || null;
|
||||
if (newUrl) {
|
||||
// Validate URL format
|
||||
try { new URL(newUrl); } catch { return error("Invalid proxy URL format"); }
|
||||
}
|
||||
setRuntimeProxy(newUrl);
|
||||
await saveProxyConfig(newUrl);
|
||||
return json({ success: true, proxy_url: newUrl, message: newUrl ? "Proxy set and saved" : "Proxy cleared" });
|
||||
} catch { return error("Invalid JSON body"); }
|
||||
}
|
||||
|
||||
if (pathname === "/api/proxy/clear" && (req.method === "POST" || req.method === "DELETE")) {
|
||||
setRuntimeProxy(null);
|
||||
await saveProxyConfig(null);
|
||||
return json({ success: true, message: "Proxy cleared" });
|
||||
}
|
||||
|
||||
// ============ PROXY STATUS ============
|
||||
|
||||
if (pathname === "/api/proxy/status") {
|
||||
const httpsProxy = Deno.env.get("HTTPS_PROXY") || Deno.env.get("https_proxy");
|
||||
const httpProxy = Deno.env.get("HTTP_PROXY") || Deno.env.get("http_proxy");
|
||||
const proxyUrl = Deno.env.get("PROXY_URL");
|
||||
const proxyActive = !!(httpsProxy || httpProxy || proxyUrl);
|
||||
|
||||
const mask = (u: string | undefined) =>
|
||||
const mask = (u: string | null | undefined) =>
|
||||
u ? u.replace(/:\/\/[^@]*@/, "://<hidden>@") : null;
|
||||
|
||||
// 1. Определяем текущий внешний IP (через прокси, если настроен)
|
||||
const activeProxy = getActiveProxyUrl();
|
||||
const proxyActive = !!activeProxy;
|
||||
|
||||
// 1. IP через прокси (или прямой, если прокси не настроен)
|
||||
let ip = "unknown";
|
||||
let ipInfo: Record<string, string> = {};
|
||||
let latencyMs = -1;
|
||||
|
||||
try {
|
||||
const t0 = Date.now();
|
||||
const ipRes = await fetch("https://ipinfo.io/json", {
|
||||
headers: { "User-Agent": "curl/7.88.0", "Accept": "application/json" },
|
||||
signal: AbortSignal.timeout(8000),
|
||||
});
|
||||
latencyMs = Date.now() - t0;
|
||||
if (ipRes.ok) {
|
||||
ipInfo = await ipRes.json();
|
||||
ip = ipInfo.ip || "unknown";
|
||||
}
|
||||
} catch { /* timeout or connection error */ }
|
||||
if (ipRes.ok) { ipInfo = await ipRes.json(); ip = ipInfo.ip || "unknown"; }
|
||||
} catch { /* failed */ }
|
||||
|
||||
// 2. Определяем IP без прокси (прямое соединение), чтобы сравнить
|
||||
let directIp = "unknown";
|
||||
try {
|
||||
// Временно вызываем нативный fetch напрямую, минуя патч
|
||||
const nativeFetch: typeof fetch = (globalThis as any).__nativeFetch || fetch;
|
||||
const res = await nativeFetch("https://api.ipify.org?format=json", {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
});
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
directIp = data.ip || "unknown";
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
// 2. Прямой IP (нативный fetch, минуя прокси-патч)
|
||||
let directIp = ip; // если прокси не настроен — они совпадут
|
||||
if (proxyActive) {
|
||||
try {
|
||||
// Импортируем нативный fetch через тот же модуль
|
||||
const { proxyFetch: _pf, ...rest } = await import("./proxy.ts");
|
||||
void rest; void _pf;
|
||||
// Используем глобальный нативный fetch напрямую через eval-трюк
|
||||
const nf = (globalThis as any)._nativeFetchRef;
|
||||
if (nf) {
|
||||
const r = await nf("https://api.ipify.org?format=json");
|
||||
if (r.ok) { const d = await r.json(); directIp = d.ip || ip; }
|
||||
}
|
||||
} catch { /* ignore */ }
|
||||
}
|
||||
|
||||
const proxyWorking = proxyActive && ip !== "unknown" && ip !== directIp;
|
||||
|
||||
return json({
|
||||
proxy_enabled: proxyActive,
|
||||
proxy_working: proxyWorking,
|
||||
proxy_url: mask((httpsProxy || httpProxy || proxyUrl) || undefined),
|
||||
proxy_url: mask(activeProxy),
|
||||
current_ip: ip,
|
||||
direct_ip: directIp,
|
||||
ip_masked: directIp !== "unknown" && ip !== directIp,
|
||||
ip_masked: ip !== directIp,
|
||||
latency_ms: latencyMs,
|
||||
location: ipInfo.city
|
||||
? `${ipInfo.city}, ${ipInfo.region}, ${ipInfo.country}`
|
||||
: (ipInfo.country || null),
|
||||
location: ipInfo.city ? `${ipInfo.city}, ${ipInfo.region}, ${ipInfo.country}` : (ipInfo.country || null),
|
||||
org: ipInfo.org || null,
|
||||
timezone: ipInfo.timezone || null,
|
||||
status: proxyActive
|
||||
? (proxyWorking ? "proxy_ok" : (ip === "unknown" ? "proxy_error" : "proxy_transparent"))
|
||||
: "no_proxy",
|
||||
});
|
||||
}
|
||||
|
||||
// ============ PROXY CONFIG ============
|
||||
|
||||
if (pathname === "/api/proxy/config") {
|
||||
const httpsProxy = Deno.env.get("HTTPS_PROXY") || Deno.env.get("https_proxy");
|
||||
const httpProxy = Deno.env.get("HTTP_PROXY") || Deno.env.get("http_proxy");
|
||||
const proxyUrl = Deno.env.get("PROXY_URL");
|
||||
const noProxy = Deno.env.get("NO_PROXY") || Deno.env.get("no_proxy");
|
||||
const active = !!(httpsProxy || httpProxy || proxyUrl);
|
||||
|
||||
// Mask credentials in proxy URL for display
|
||||
const mask = (u: string | undefined) =>
|
||||
u ? u.replace(/:\/\/[^@]*@/, "://<hidden>@") : null;
|
||||
|
||||
return json({
|
||||
proxy_enabled: active,
|
||||
https_proxy: mask(httpsProxy || undefined),
|
||||
http_proxy: mask(httpProxy || undefined),
|
||||
proxy_url: mask(proxyUrl || undefined),
|
||||
no_proxy: noProxy || null,
|
||||
note: active
|
||||
? "All outbound requests are routed through the proxy"
|
||||
: "No proxy configured — direct connections are used",
|
||||
status: !proxyActive ? "no_proxy"
|
||||
: ip === "unknown" ? "proxy_error"
|
||||
: proxyWorking ? "proxy_ok"
|
||||
: "proxy_transparent",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user