arn-browser 0.1.1 → 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
|
@@ -91,3 +91,38 @@ export function isProxyAlive(proxyHost: string, proxyPort: number): Promise<stri
|
|
|
91
91
|
* @param timeout - Request timeout in ms.
|
|
92
92
|
*/
|
|
93
93
|
export function nativeGet(url: string, agent?: any, timeout?: number): Promise<string>;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Proxy configuration object returned by fetchAwsProxy.
|
|
97
|
+
*/
|
|
98
|
+
export interface ProxyConfig {
|
|
99
|
+
type: "socks5" | "http";
|
|
100
|
+
host: string;
|
|
101
|
+
port: number;
|
|
102
|
+
user: string | null;
|
|
103
|
+
pass: string | null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Parameters for fetchAwsProxy function.
|
|
108
|
+
*/
|
|
109
|
+
export interface FetchAwsProxyParams {
|
|
110
|
+
instance_name: string;
|
|
111
|
+
/**
|
|
112
|
+
* If true, uses getActiveProxyWithStartStop (hard reset).
|
|
113
|
+
* If false, uses getActiveProxy (IP cycling).
|
|
114
|
+
* @default true
|
|
115
|
+
*/
|
|
116
|
+
useStartStop?: boolean;
|
|
117
|
+
/**
|
|
118
|
+
* The proxy type. Determines the port (socks5: 10001, http: 9001).
|
|
119
|
+
* @default 'socks5'
|
|
120
|
+
*/
|
|
121
|
+
proxy_type?: "socks5" | "http";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Fetches an active AWS proxy and returns it in a standardized format.
|
|
126
|
+
* @returns The proxy configuration object or null if not found.
|
|
127
|
+
*/
|
|
128
|
+
export function fetchAwsProxy(params: FetchAwsProxyParams): Promise<ProxyConfig | null>;
|
|
@@ -623,3 +623,43 @@ export async function isProxyAlive(proxyHost, proxyPort) {
|
|
|
623
623
|
|
|
624
624
|
return null;
|
|
625
625
|
}
|
|
626
|
+
|
|
627
|
+
// ==========================================
|
|
628
|
+
// SECTION 8: HIGH-LEVEL PROXY FETCH
|
|
629
|
+
// ==========================================
|
|
630
|
+
|
|
631
|
+
/**
|
|
632
|
+
* @typedef {Object} ProxyConfig
|
|
633
|
+
* @property {'socks5'|'http'} type - The proxy type.
|
|
634
|
+
* @property {string} host - The proxy host IP address.
|
|
635
|
+
* @property {number} port - The proxy port.
|
|
636
|
+
* @property {string|null} user - The proxy username (null if not required).
|
|
637
|
+
* @property {string|null} pass - The proxy password (null if not required).
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* Fetches an active AWS proxy and returns it in a standardized format.
|
|
642
|
+
*
|
|
643
|
+
* @param {Object} params - The parameters object.
|
|
644
|
+
* @param {string} params.instance_name - The name of the EC2 instance.
|
|
645
|
+
* @param {boolean} [params.useStartStop=true] - If true, uses getActiveProxyWithStartStop (hard reset).
|
|
646
|
+
* If false, uses getActiveProxy (IP cycling).
|
|
647
|
+
* @param {'socks5'|'http'} [params.proxy_type='socks5'] - The proxy type (socks5: port 10001, http: port 9001).
|
|
648
|
+
* @returns {Promise<ProxyConfig|null>} - The proxy configuration object or null if not found.
|
|
649
|
+
*/
|
|
650
|
+
export const fetchAwsProxy = async ({ instance_name, useStartStop = true, proxy_type = "socks5" }) => {
|
|
651
|
+
let getawsproxy;
|
|
652
|
+
if (useStartStop) {
|
|
653
|
+
getawsproxy = await getActiveProxyWithStartStop({ instance_name: instance_name });
|
|
654
|
+
} else {
|
|
655
|
+
getawsproxy = await getActiveProxy({ instance_name: instance_name });
|
|
656
|
+
}
|
|
657
|
+
if (!getawsproxy) {
|
|
658
|
+
console.log("Aws proxy not found");
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
/** @type {ProxyConfig} */
|
|
662
|
+
const port = proxy_type === "socks5" ? 10001 : 9001;
|
|
663
|
+
let temp_proxy = { type: proxy_type, host: getawsproxy, port: port, user: null, pass: null };
|
|
664
|
+
return temp_proxy;
|
|
665
|
+
};
|
|
@@ -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
|
}
|