CH-J Server ManagerSSH کے ذریعے سرور کا انتظام
مینو
شائع شدہ سورس

CH-J Server Manager

ایپلیکیشن کی کسی مخصوص ریلیز کی ڈائریکٹریز اور فائلیں دیکھیں۔

سورس ZIP ڈاؤن لوڈ کریں
CH-J / Server Manager 377 فائلیں
core-20261019T111616Z-160a00bfcddc شامل کیا گیا: · بلڈ کیا گیا:
common.js شامل کیا گیا: تاریخ درج نہیں 8.5 KB · 110 لائنیں
کوڈ فائل ڈاؤن لوڈ کریں
1"use strict";
2const net = require("node:net");
3const tls = require("node:tls");
4const { X509Certificate } = require("node:crypto");
5const { domainToASCII } = require("node:url");
6const { performance } = require("node:perf_hooks");
7const PING_INTERVAL_MIN_MS = 50, PING_DURATION_LIMIT_MS = 30 * 60 * 1000;
8const TOOLS = ["dns", "ping", "traceroute", "http", "compression", "tls", "tcp", "websocket"];
9const SERVICES = { 21: "FTP", 22: "SSH", 25: "SMTP", 53: "DNS TCP", 80: "HTTP", 110: "POP3", 143: "IMAP", 443: "HTTPS", 445: "SMB", 587: "SMTP Submission", 993: "IMAPS", 995: "POP3S", 3306: "MySQL", 3389: "RDP", 5432: "PostgreSQL", 6379: "Redis" };
10class DiagnosticError extends Error {
11 constructor(code, message = code) { super(message); this.code = code; }
13// Verify IP SANs directly. Node TLS releases that IDNA-normalize every host can
14// misclassify an unbracketed IPv6 literal as a DNS name. Trust verification stays on.
15function verifyPeerIdentity(host, cert) {
16 if (!net.isIP(host)) return tls.checkServerIdentity(host, cert);
17 try { if (new X509Certificate(cert.raw).checkIP(host)) return undefined; } catch {}
18 return new DiagnosticError("ERR_TLS_CERT_ALTNAME_INVALID", "Certificate IP SAN does not match the requested IP address.");
20function hostname(raw) {
21 const value = String(raw || "").replace(/^\[|\]$/g, "");
22 if (net.isIP(value)) return value;
23 const ascii = domainToASCII(value.replace(/\.$/, "")).toLowerCase();
24 if (!ascii || ascii.length > 253 || !ascii.split(".").every((label) => /^[a-z0-9_](?:[a-z0-9_-]{0,61}[a-z0-9_])?$/i.test(label))) throw new DiagnosticError("INVALID_HOST");
25 return ascii;
27function parseTarget(raw) {
28 const input = String(raw || "").trim();
29 if (!input || input.length > 2048 || /[\x00-\x20\x7f\\]/.test(input)) throw new DiagnosticError("INVALID_TARGET");
30 let url;
31 const literal = net.isIP(input.replace(/^\[|\]$/g, ""));
32 try { url = new URL(literal === 6 ? `https://[${hostname(input)}]/` : /^[a-z][a-z0-9+.-]*:\/\//i.test(input) ? input : `https://${input}`); }
33 catch { throw new DiagnosticError("INVALID_URL"); }
34 if (!["http:", "https:", "ws:", "wss:"].includes(url.protocol) || url.username || url.password) throw new DiagnosticError("URL_AUTH_OR_SCHEME_FORBIDDEN");
35 const host = hostname(url.hostname);
36 url.hash = "";
37 return { input, host, url: url.href, port: Number(url.port || (["https:", "wss:"].includes(url.protocol) ? 443 : 80)), type: net.isIP(host) ? `ipv${net.isIP(host)}` : input.includes("://") ? "url" : "hostname" };
39function integer(value, fallback, min, max) {
40 if (value === undefined || value === "") return fallback;
41 const number = Number(value);
42 if (!Number.isInteger(number) || number < min || number > max) throw new DiagnosticError("INVALID_PARAMETER");
43 return number;
45// "192.0.2.1, 2001:db8::1" tests one IPv4 and one IPv6 literal in a single run without DNS.
46function manualPair(source) {
47 const list = Array.isArray(source.manualAddresses) ? source.manualAddresses.map((entry) => entry?.address ?? entry)
48 : typeof source.target === "string" && /^[^/]*[\s,;][^/]*$/.test(source.target.trim()) ? source.target.trim().split(/[\s,;]+/).filter(Boolean) : null;
49 if (!list) return null;
50 const addresses = list.map((value) => String(value).replace(/^\[|\]$/g, ""));
51 if (addresses.length !== 2 || addresses.some((value) => !net.isIP(value)) || net.isIP(addresses[0]) === net.isIP(addresses[1])) throw new DiagnosticError("INVALID_MANUAL_ADDRESSES");
52 return addresses.map((address) => ({ address: hostname(address), family: net.isIP(address) })).sort((a, b) => a.family - b.family);
54function normalizeOptions(source = {}) {
55 const manualAddresses = manualPair(source);
56 const target = parseTarget(manualAddresses && !Array.isArray(source.manualAddresses) ? manualAddresses[0].address : source.target);
57 const mode = source.mode || "auto";
58 if (!["auto", "ipv4", "ipv6", "both"].includes(mode)) throw new DiagnosticError("INVALID_IP_MODE");
59 const tools = source.tools === undefined ? TOOLS.filter((tool) => tool !== "websocket") : source.tools;
60 if (!Array.isArray(tools) || !tools.length || tools.length > TOOLS.length || tools.some((tool) => !TOOLS.includes(tool))) throw new DiagnosticError("INVALID_TOOLS");
61 const portsText = String(source.ports || "22,80,443");
62 if (portsText.length > 512) throw new DiagnosticError("PORT_LIMIT");
63 const ports = [...new Set(portsText.split(/[,;\s]+/).filter(Boolean).map((port) => integer(port, 443, 1, 65535)))];
64 if (!ports.length || ports.length > 16) throw new DiagnosticError("PORT_LIMIT");
65 const resolver = source.resolver || "system";
66 if (!["system", "custom", "cloudflare", "google", "quad9"].includes(resolver)) throw new DiagnosticError("INVALID_RESOLVER");
67 const customDns = String(source.customDns || "");
68 if (resolver === "custom" && !net.isIP(customDns)) throw new DiagnosticError("INVALID_DNS_SERVER");
69 const selectedIp = String(source.selectedIp || "");
70 if (selectedIp && !net.isIP(selectedIp)) throw new DiagnosticError("INVALID_IP");
71 const protocols = source.protocols || ["1.1", "2", "3"];
72 if (!Array.isArray(protocols) || !protocols.length || protocols.length > 3 || protocols.some((p) => !["1.1", "2", "3"].includes(p))) throw new DiagnosticError("INVALID_PROTOCOL");
73 const optional = (value, min, max) => value === undefined || value === null || value === "" ? null : integer(value, null, min, max);
74 const count = integer(source.count, 4, 1, 100000), repetitions = integer(source.repetitions, 1, 1, 20), intervalMs = integer(source.intervalMs, 1000, PING_INTERVAL_MIN_MS, 60000);
75 const continuous = source.continuous === true;
76 if (!continuous && count * repetitions * intervalMs > PING_DURATION_LIMIT_MS) throw new DiagnosticError("PING_DURATION_LIMIT");
77 return { target, ...(manualAddresses ? { manualAddresses } : {}), tools: [...new Set(tools)], mode, selectedIp, resolver, customDns,
78 timeoutMs: integer(source.timeoutMs, 5000, 250, 30000), count, intervalMs,
79 pingTimeoutMs: optional(source.pingTimeoutMs, 100, 30000), packetSize: optional(source.packetSize, 0, 65500), ttl: optional(source.ttl, 1, 255), dontFragment: source.dontFragment === true,
80 repetitions, maxHops: integer(source.maxHops, 20, 1, 40),
81 continuous, warm: source.warm === true, protocols: [...new Set(protocols)], ports,
82 compareSchemes: source.compareSchemes === true };
84function stats(values) {
85 const list = values.filter((v) => typeof v === "number" && Number.isFinite(v)).sort((a, b) => a - b);
86 if (!list.length) return { min: null, average: null, median: null, max: null, p95: null, stddev: null, jitter: null };
87 const average = list.reduce((a, b) => a + b, 0) / list.length;
88 const sequence = values.filter((v) => typeof v === "number" && Number.isFinite(v));
89 return { min: list[0], average, median: list.length % 2 ? list[(list.length - 1) / 2] : (list[list.length / 2 - 1] + list[list.length / 2]) / 2,
90 max: list.at(-1), p95: list[Math.ceil(list.length * 0.95) - 1], stddev: Math.sqrt(list.reduce((sum, v) => sum + (v - average) ** 2, 0) / list.length),
91 jitter: sequence.length < 2 ? null : sequence.slice(1).reduce((sum, v, index) => sum + Math.abs(v - sequence[index]), 0) / (sequence.length - 1) };
93function checkAbort(signal) { if (signal?.aborted) throw new DiagnosticError("CANCELLED"); }
94function errorResult(error) { return { status: error?.code === "CANCELLED" || error?.name === "AbortError" ? "cancelled" : "error", code: error?.code || "DIAGNOSTIC_ERROR", reason: String(error?.message || error).slice(0, 400) }; }
95async function mapLimit(items, limit, fn) {
96 const results = new Array(items.length); let cursor = 0;
97 const outcomes = await Promise.allSettled(Array.from({ length: Math.min(limit, items.length) }, async () => { while (cursor < items.length) { const index = cursor++; results[index] = await fn(items[index], index); } }));
98 const failure = outcomes.find((entry) => entry.status === "rejected");
99 if (failure) throw failure.reason;
100 return results;
102function boundedSignal(parent, timeoutMs) {
103 const controller = new AbortController();
104 const abort = () => controller.abort(parent?.reason);
105 parent?.addEventListener("abort", abort, { once: true });
106 if (parent?.aborted) abort();
107 const timer = setTimeout(() => controller.abort(new DiagnosticError("TIMEOUT")), timeoutMs);
108 return { signal: controller.signal, close() { clearTimeout(timer); parent?.removeEventListener("abort", abort); } };
110module.exports = { PING_INTERVAL_MIN_MS, PING_DURATION_LIMIT_MS, verifyPeerIdentity, DiagnosticError, TOOLS, SERVICES, hostname, parseTarget, normalizeOptions, integer, stats, checkAbort, errorResult, mapLimit, boundedSignal, now: () => performance.now() };
SHA-256f88630862175f4f28dfbf84642a02fb9920b15e6dbb6c8070a5bd1a1264b8ed8

CH-J Proprietary Software License 1.14 · سورس CH-J Proprietary Software License 1.14 کے تحت فراہم کیا جاتا ہے۔ اس کی دستیابی لائسنس کی شرائط نہیں بدلتی اور نہ ہی اضافی حقوق دیتی ہے۔

آرکائیو کا SHA-256a9605c0870a223b6a8542bb0705edd51d8b04f3069582653417a8397fabcc09a
فائلیں