arn-browser 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -64,6 +64,8 @@ export interface ProxyServerOptions {
|
|
|
64
64
|
debug?: boolean;
|
|
65
65
|
/** Track proxy usage statistics (default: true) */
|
|
66
66
|
proxy_stats?: boolean;
|
|
67
|
+
/** Track hostname usage statistics (default: true) */
|
|
68
|
+
host_stats?: boolean;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
/**
|
|
@@ -102,11 +104,17 @@ export interface ProxyServerController {
|
|
|
102
104
|
/** The public IP of Proxy 2 */
|
|
103
105
|
PROXY_2_IP: string | null;
|
|
104
106
|
|
|
107
|
+
/** Check if the proxy server is currently running */
|
|
108
|
+
isServerRunning: () => boolean;
|
|
109
|
+
|
|
105
110
|
/** Gracefully closes the proxy server */
|
|
106
111
|
closeServer: () => Promise<void>;
|
|
107
112
|
|
|
108
113
|
/** Returns formatted statistics for all proxy channels */
|
|
109
114
|
getProxyStats: () => Record<string, TrafficStats>;
|
|
115
|
+
|
|
116
|
+
/** Returns formatted statistics for hostnames per proxy channel */
|
|
117
|
+
getHostStats: () => Record<string, Record<string, number>>;
|
|
110
118
|
}
|
|
111
119
|
|
|
112
120
|
/**
|
|
@@ -178,6 +178,7 @@ export async function startProxyServer({
|
|
|
178
178
|
ip2LocationKey = null,
|
|
179
179
|
debug = false,
|
|
180
180
|
proxy_stats = true,
|
|
181
|
+
host_stats = true,
|
|
181
182
|
}) {
|
|
182
183
|
// 1. Matchers
|
|
183
184
|
const matchers = {
|
|
@@ -227,7 +228,16 @@ export async function startProxyServer({
|
|
|
227
228
|
PROXY_1: { request: 0, Tx: 0, Rx: 0 },
|
|
228
229
|
PROXY_2: { request: 0, Tx: 0, Rx: 0 },
|
|
229
230
|
};
|
|
230
|
-
|
|
231
|
+
// hostStatsMap is now categorized by proxy type
|
|
232
|
+
const hostStatsMap = {
|
|
233
|
+
DEFAULT_PROXY: {},
|
|
234
|
+
NO_PROXY: {},
|
|
235
|
+
PROXY_1: {},
|
|
236
|
+
PROXY_2: {},
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
const connectionMap = {}; // Maps connectionId -> { type: "..." }
|
|
240
|
+
let serverRunning = false;
|
|
231
241
|
|
|
232
242
|
// 6. Server
|
|
233
243
|
const server = new ProxyChain.Server({
|
|
@@ -235,42 +245,61 @@ export async function startProxyServer({
|
|
|
235
245
|
host: "127.0.0.1",
|
|
236
246
|
verbose: debug,
|
|
237
247
|
prepareRequestFunction: ({ hostname, connectionId }) => {
|
|
238
|
-
|
|
248
|
+
let proxyType = "DEFAULT_PROXY";
|
|
249
|
+
let upstreamUrl = upstreamProxies.default;
|
|
250
|
+
let isCustomResponse = false;
|
|
251
|
+
let customResponseData = null;
|
|
252
|
+
|
|
253
|
+
// Logic to determine Proxy Type
|
|
239
254
|
if (matchers.noProxy(hostname)) {
|
|
240
|
-
|
|
241
|
-
|
|
255
|
+
// A. Direct
|
|
256
|
+
proxyType = "NO_PROXY";
|
|
257
|
+
upstreamUrl = null;
|
|
258
|
+
} else if (matchers.proxy1(hostname) && upstreamProxies.p1) {
|
|
259
|
+
// C1. Proxy 1
|
|
260
|
+
proxyType = "PROXY_1";
|
|
261
|
+
upstreamUrl = upstreamProxies.p1;
|
|
262
|
+
} else if (matchers.proxy2(hostname) && upstreamProxies.p2) {
|
|
263
|
+
// C2. Proxy 2
|
|
264
|
+
proxyType = "PROXY_2";
|
|
265
|
+
upstreamUrl = upstreamProxies.p2;
|
|
242
266
|
}
|
|
243
267
|
|
|
244
|
-
// B. IP Check Interception (
|
|
268
|
+
// B. IP Check Interception (Overrules standard routing for specific domain)
|
|
245
269
|
if (hostname === "ip.bablosoft.com") {
|
|
270
|
+
isCustomResponse = true;
|
|
271
|
+
// Inherit the proxyType determined above to fetch the correct IP details
|
|
272
|
+
// (e.g. if it matched PROXY_1 matchers, we show PROXY_1 IP)
|
|
246
273
|
let displayedIP;
|
|
247
|
-
|
|
248
|
-
if (
|
|
249
|
-
else if (
|
|
250
|
-
else displayedIP = defaultDetails?.ip;
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
body: displayedIP || "Unknown IP",
|
|
257
|
-
}),
|
|
274
|
+
if (proxyType === "PROXY_1") displayedIP = p1Details?.ip;
|
|
275
|
+
else if (proxyType === "PROXY_2") displayedIP = p2Details?.ip;
|
|
276
|
+
else if (proxyType === "NO_PROXY") displayedIP = "127.0.0.1";
|
|
277
|
+
else displayedIP = defaultDetails?.ip;
|
|
278
|
+
|
|
279
|
+
customResponseData = {
|
|
280
|
+
statusCode: 200,
|
|
281
|
+
headers: { "Content-Type": "text/plain", Connection: "close" },
|
|
282
|
+
body: displayedIP || "Unknown IP",
|
|
258
283
|
};
|
|
259
284
|
}
|
|
260
285
|
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
286
|
+
// Record Stats
|
|
287
|
+
connectionMap[connectionId] = { type: proxyType };
|
|
288
|
+
if (host_stats && hostname) {
|
|
289
|
+
// Ensure the type exists in map (it should, but safety first)
|
|
290
|
+
if (!hostStatsMap[proxyType]) hostStatsMap[proxyType] = {};
|
|
291
|
+
hostStatsMap[proxyType][hostname] = (hostStatsMap[proxyType][hostname] || 0) + 1;
|
|
265
292
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
293
|
+
|
|
294
|
+
// Return Decision
|
|
295
|
+
if (isCustomResponse) {
|
|
296
|
+
return { customResponseFunction: () => customResponseData };
|
|
269
297
|
}
|
|
270
298
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
299
|
+
return {
|
|
300
|
+
upstreamProxyUrl: upstreamUrl,
|
|
301
|
+
requestAuthentication: false, // Auto-handle upstream auth via URL
|
|
302
|
+
};
|
|
274
303
|
},
|
|
275
304
|
});
|
|
276
305
|
|
|
@@ -289,6 +318,7 @@ export async function startProxyServer({
|
|
|
289
318
|
|
|
290
319
|
try {
|
|
291
320
|
await server.listen();
|
|
321
|
+
serverRunning = true;
|
|
292
322
|
console.log(`✅ Local Proxy Started: http://127.0.0.1:${selectedPort}`);
|
|
293
323
|
} catch (err) {
|
|
294
324
|
console.error("❌ Failed to start proxy server:", err);
|
|
@@ -297,6 +327,37 @@ export async function startProxyServer({
|
|
|
297
327
|
|
|
298
328
|
const formatBytes = (bytes) => (bytes / 1024 / 1024).toFixed(2);
|
|
299
329
|
|
|
330
|
+
const getProxyStatsFormatted = () => {
|
|
331
|
+
const formatted = {};
|
|
332
|
+
for (const [key, val] of Object.entries(stats)) {
|
|
333
|
+
formatted[key] = {
|
|
334
|
+
req: val.request,
|
|
335
|
+
Tx: formatBytes(val.Tx) + " MB",
|
|
336
|
+
Rx: formatBytes(val.Rx) + " MB",
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return formatted;
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
const getHostStatsFormatted = () => {
|
|
343
|
+
const result = {};
|
|
344
|
+
// Iterate over each proxy category
|
|
345
|
+
for (const [type, hosts] of Object.entries(hostStatsMap)) {
|
|
346
|
+
const sortedHosts = Object.entries(hosts)
|
|
347
|
+
.sort((a, b) => b[1] - a[1]) // Sort by count descending
|
|
348
|
+
.reduce((acc, [host, count]) => {
|
|
349
|
+
acc[host] = count;
|
|
350
|
+
return acc;
|
|
351
|
+
}, {});
|
|
352
|
+
|
|
353
|
+
// Only include categories that have traffic
|
|
354
|
+
if (Object.keys(sortedHosts).length > 0) {
|
|
355
|
+
result[type] = sortedHosts;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
return result;
|
|
359
|
+
};
|
|
360
|
+
|
|
300
361
|
// 7. Return Controller
|
|
301
362
|
return {
|
|
302
363
|
port: selectedPort,
|
|
@@ -318,20 +379,24 @@ export async function startProxyServer({
|
|
|
318
379
|
PROXY_1_IP: p1Details?.ip || null,
|
|
319
380
|
PROXY_2_IP: p2Details?.ip || null,
|
|
320
381
|
|
|
382
|
+
isServerRunning: () => serverRunning,
|
|
383
|
+
|
|
321
384
|
closeServer: async () => {
|
|
322
385
|
await server.close(true);
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
Rx: formatBytes(val.Rx) + " MB",
|
|
332
|
-
};
|
|
386
|
+
serverRunning = false;
|
|
387
|
+
|
|
388
|
+
// Auto console.log stats on close
|
|
389
|
+
if (proxy_stats) {
|
|
390
|
+
console.log("📊 Proxy Stats:", getProxyStatsFormatted());
|
|
391
|
+
}
|
|
392
|
+
if (host_stats) {
|
|
393
|
+
console.log("🌐 Host Stats:", getHostStatsFormatted());
|
|
333
394
|
}
|
|
334
|
-
|
|
395
|
+
|
|
396
|
+
console.log("🔒 Proxy server closed.");
|
|
335
397
|
},
|
|
398
|
+
|
|
399
|
+
getProxyStats: getProxyStatsFormatted,
|
|
400
|
+
getHostStats: getHostStatsFormatted,
|
|
336
401
|
};
|
|
337
402
|
}
|