arn-browser 0.0.3 → 0.0.5
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/README.md +3 -2
- package/package.json +31 -47
- package/src/all_routes/routeWithSuperagent.d.ts +67 -0
- package/src/all_routes/routeWithSuperagent.js +322 -0
- package/src/human-cursor/HumanCursor.js +448 -0
- package/src/human-cursor/bezier.js +248 -0
- package/src/human-cursor/index.d.ts +154 -0
- package/src/human-cursor/index.js +9 -0
- package/src/human-cursor/randomizer.js +149 -0
- package/src/human-cursor/tweening.js +260 -0
- package/src/index.d.ts +19 -0
- package/src/index.js +15 -0
- package/src/others/totp-generator.d.ts +15 -0
- package/src/others/totp-generator.js +86 -0
- package/src/utility/deleteDirectory.js +105 -0
- package/src/utility/launchBrowser.d.ts +248 -0
- package/src/utility/launchBrowser.js +899 -0
- package/src/utility/multilogin_token_manager.js +164 -0
- package/src/utility/playwright-helper.d.ts +61 -0
- package/src/utility/playwright-helper.js +129 -0
- package/src/utility/proxy-utility/custom-proxy.d.ts +93 -0
- package/src/utility/proxy-utility/custom-proxy.js +625 -0
- package/src/utility/proxy-utility/proxy-chain.d.ts +123 -0
- package/src/utility/proxy-utility/proxy-chain.js +337 -0
- package/src/utility/proxy-utility/proxy-helper.d.ts +91 -0
- package/src/utility/proxy-utility/proxy-helper.js +222 -0
- package/dist/__main__.d.ts +0 -2
- package/dist/__main__.js +0 -127
- package/dist/__version__.d.ts +0 -11
- package/dist/__version__.js +0 -16
- package/dist/addons.d.ts +0 -17
- package/dist/addons.js +0 -70
- package/dist/data-files/territoryInfo.xml +0 -2024
- package/dist/data-files/webgl_data.db +0 -0
- package/dist/exceptions.d.ts +0 -76
- package/dist/exceptions.js +0 -153
- package/dist/fingerprints.d.ts +0 -4
- package/dist/fingerprints.js +0 -82
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/ip.d.ts +0 -25
- package/dist/ip.js +0 -90
- package/dist/locale.d.ts +0 -26
- package/dist/locale.js +0 -280
- package/dist/mappings/browserforge.config.d.ts +0 -47
- package/dist/mappings/browserforge.config.js +0 -72
- package/dist/mappings/fonts.config.d.ts +0 -6
- package/dist/mappings/fonts.config.js +0 -822
- package/dist/mappings/warnings.config.d.ts +0 -16
- package/dist/mappings/warnings.config.js +0 -28
- package/dist/pkgman.d.ts +0 -62
- package/dist/pkgman.js +0 -347
- package/dist/server.d.ts +0 -6
- package/dist/server.js +0 -9
- package/dist/sync_api.d.ts +0 -7
- package/dist/sync_api.js +0 -27
- package/dist/utils.d.ts +0 -88
- package/dist/utils.js +0 -500
- package/dist/virtdisplay.d.ts +0 -20
- package/dist/virtdisplay.js +0 -123
- package/dist/warnings.d.ts +0 -4
- package/dist/warnings.js +0 -30
- package/dist/webgl/db-compat.d.ts +0 -9
- package/dist/webgl/db-compat.js +0 -44
- package/dist/webgl/sample.d.ts +0 -19
- package/dist/webgl/sample.js +0 -85
- /package/{LICENSE.md → LICENSE} +0 -0
package/README.md
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
# arn-browser
|
|
1
|
+
# 🕵️♂️ arn-browser
|
|
2
|
+
|
|
3
|
+
A powerful, stealth-focused browser automation manager wrapping **Playwright**. Built for scraping, automation, and multi-accounting with built-in **fingerprint injection**, **persistent profiles**, and **Multilogin** integration.
|
|
2
4
|
|
|
3
|
-
This is the JavaScript client for Browser automation.
|
package/package.json
CHANGED
|
@@ -1,56 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arn-browser",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"types": "dist/index.d.ts",
|
|
8
|
-
"bin": "dist/__main__.js",
|
|
9
|
-
"scripts": {
|
|
10
|
-
"build": "rimraf dist && tsc && npm run copy-files",
|
|
11
|
-
"test": "vitest",
|
|
12
|
-
"copy-files": "cp -r src/data-files dist/data-files",
|
|
13
|
-
"check": "biome check"
|
|
14
|
-
},
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "A lightweight, browser autmation helper.",
|
|
5
|
+
"main": "src/index.js",
|
|
6
|
+
"types": "src/index.d.ts",
|
|
15
7
|
"files": [
|
|
16
|
-
"
|
|
17
|
-
],
|
|
18
|
-
"type": "module",
|
|
19
|
-
"keywords": [
|
|
20
|
-
"arn browser"
|
|
8
|
+
"src"
|
|
21
9
|
],
|
|
22
|
-
"
|
|
23
|
-
"
|
|
10
|
+
"directories": {
|
|
11
|
+
"test": "test"
|
|
24
12
|
},
|
|
25
|
-
"description": "Experimental JS port of Camoufox.",
|
|
26
13
|
"dependencies": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
14
|
+
"@aws-sdk/client-ec2": "^3.946.0",
|
|
15
|
+
"@ghostery/adblocker": "^2.13.0",
|
|
16
|
+
"arn-knexjs": "^0.0.1",
|
|
17
|
+
"camoufox-js": "^0.8.4",
|
|
18
|
+
"dotenv": "^17.2.3",
|
|
19
|
+
"fingerprint-injector": "^2.1.78",
|
|
20
|
+
"https-proxy-agent": "^7.0.6",
|
|
21
|
+
"node-cache": "^5.1.2",
|
|
22
|
+
"node-fetch": "^3.3.2",
|
|
23
|
+
"playwright": "^1.57.0",
|
|
24
|
+
"proxy-chain": "^2.6.0",
|
|
25
|
+
"randomstring": "^1.3.1",
|
|
26
|
+
"socks-proxy-agent": "^8.0.5",
|
|
27
|
+
"speakeasy": "^2.0.0",
|
|
28
|
+
"superagent": "^10.2.3"
|
|
37
29
|
},
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@types/adm-zip": "^0.5.7",
|
|
43
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
44
|
-
"@types/language-tags": "^1.0.4",
|
|
45
|
-
"@types/node": "^24.0.0",
|
|
46
|
-
"@types/progress": "^2.0.7",
|
|
47
|
-
"@types/xml2js": "^0.4.14",
|
|
48
|
-
"playwright-core": "^1.53.1",
|
|
49
|
-
"rimraf": "^6.0.1",
|
|
50
|
-
"typescript": "^5.8.3",
|
|
51
|
-
"vitest": "^4.0.0"
|
|
30
|
+
"scripts": {
|
|
31
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
52
32
|
},
|
|
53
|
-
"
|
|
54
|
-
"
|
|
55
|
-
|
|
33
|
+
"keywords": [
|
|
34
|
+
"browser",
|
|
35
|
+
"automation"
|
|
36
|
+
],
|
|
37
|
+
"author": "ARNDESK",
|
|
38
|
+
"license": "ISC",
|
|
39
|
+
"type": "module"
|
|
56
40
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Browser, BrowserContext, Page } from "playwright";
|
|
2
|
+
|
|
3
|
+
// ============================================================================
|
|
4
|
+
// ROUTING & CACHE TYPES
|
|
5
|
+
// ============================================================================
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options for the gotRoute function.
|
|
9
|
+
*/
|
|
10
|
+
export interface GotRouteOptions {
|
|
11
|
+
/** Playwright Context (provide either context or page) */
|
|
12
|
+
context?: BrowserContext | null;
|
|
13
|
+
|
|
14
|
+
/** Playwright Page (provide either context or page) */
|
|
15
|
+
page?: Page | null;
|
|
16
|
+
|
|
17
|
+
/** Log successful requests to console */
|
|
18
|
+
successLogs?: boolean;
|
|
19
|
+
|
|
20
|
+
/** Log failed requests to console */
|
|
21
|
+
errorLogs?: boolean;
|
|
22
|
+
|
|
23
|
+
/** Block Ad requests (Ghostery engine) */
|
|
24
|
+
blockAds?: boolean;
|
|
25
|
+
|
|
26
|
+
/** Block Image requests */
|
|
27
|
+
blockImage?: boolean;
|
|
28
|
+
|
|
29
|
+
/** Intercept requests using Superagent (bypassing browser stack for intercepted resources) */
|
|
30
|
+
useGot?: boolean;
|
|
31
|
+
|
|
32
|
+
/** Use full URL for cache key (otherwise origin+pathname) */
|
|
33
|
+
useFullUrl?: boolean;
|
|
34
|
+
|
|
35
|
+
/** Enable caching for requests */
|
|
36
|
+
useCache?: boolean;
|
|
37
|
+
|
|
38
|
+
/** Data object for Doublelist message interception (POST logic) */
|
|
39
|
+
m4w_send_on_post?: Record<string, any> | null;
|
|
40
|
+
|
|
41
|
+
/** Data object for Doublelist message interception (Message logic) */
|
|
42
|
+
m4w_send_on_message?: Record<string, any> | null;
|
|
43
|
+
|
|
44
|
+
/** * Array of URL substrings. If a URL contains any of these strings,
|
|
45
|
+
* it will NOT be blocked, even if blockImage is true.
|
|
46
|
+
* Default includes: ["cdn-cgi/challenge-platform"]
|
|
47
|
+
*/
|
|
48
|
+
allowImagePatterns?: string[];
|
|
49
|
+
|
|
50
|
+
/** * Array of URL substrings. If a URL contains any of these strings,
|
|
51
|
+
* the custom Superagent/Got fetch will be skipped, and the default
|
|
52
|
+
* Playwright network stack will be used instead.
|
|
53
|
+
*/
|
|
54
|
+
skipGotPatterns?: string[];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Sets up request interception, caching, and ad-blocking on a Playwright page or context.
|
|
59
|
+
*/
|
|
60
|
+
export function gotRoute(options: GotRouteOptions): Promise<void>;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Starts logging cache statistics to the console at a set interval.
|
|
64
|
+
* @param log_cache Optional NodeCache instance (uses global by default)
|
|
65
|
+
* @param interval Interval in seconds (default: 10)
|
|
66
|
+
*/
|
|
67
|
+
export function showCacheLogs(log_cache?: any, interval?: number): void;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
// Import required libraries
|
|
2
|
+
import superagent from "superagent";
|
|
3
|
+
import { FiltersEngine, Request } from "@ghostery/adblocker";
|
|
4
|
+
import fetch from "node-fetch";
|
|
5
|
+
import NodeCache from "node-cache";
|
|
6
|
+
|
|
7
|
+
let AdBlockEngine;
|
|
8
|
+
|
|
9
|
+
// Create a NodeCache instance for caching responses
|
|
10
|
+
// This helps reduce bandwidth usage and speed up repeated requests
|
|
11
|
+
const globalCache = new NodeCache({
|
|
12
|
+
stdTTL: 3600, // Standard Time To Live in seconds for every generated cache element
|
|
13
|
+
checkperiod: 600, // The period in seconds for the automatic delete check interval
|
|
14
|
+
useClones: false, // Don't use clones for performance reasons
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Function to start cache logging
|
|
19
|
+
* This outputs cache statistics (hits, misses, memory usage) to the console at a set interval.
|
|
20
|
+
* @param {Object} log_cache - The cache instance to monitor
|
|
21
|
+
* @param {number} interval - The interval in seconds between log outputs
|
|
22
|
+
*/
|
|
23
|
+
export function showCacheLogs(log_cache = globalCache, interval = 10) {
|
|
24
|
+
if (interval > 0) {
|
|
25
|
+
setInterval(() => {
|
|
26
|
+
const stats = log_cache.stats;
|
|
27
|
+
const ksizeMB = (stats.ksize / (1024 * 1024)).toFixed(2);
|
|
28
|
+
const vsizeMB = (stats.vsize / (1024 * 1024)).toFixed(2);
|
|
29
|
+
const totalRequests = stats.hits + stats.misses;
|
|
30
|
+
const hitPercentage = totalRequests > 0 ? ((stats.hits / totalRequests) * 100).toFixed(2) : "0.00";
|
|
31
|
+
const missPercentage = totalRequests > 0 ? ((stats.misses / totalRequests) * 100).toFixed(2) : "0.00";
|
|
32
|
+
|
|
33
|
+
console.warn(
|
|
34
|
+
`Cache Stats: Success: ${stats.hits} (${hitPercentage}%), Misses: ${stats.misses} (${missPercentage}%), Keys: ${stats.keys}, Key: ${ksizeMB} MB, Value: ${vsizeMB} MB`
|
|
35
|
+
);
|
|
36
|
+
}, interval * 1000);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Function to fetch resources using Superagent library with optional caching.
|
|
42
|
+
* This mimics the browser's request but handles it in Node.js to allow caching or header manipulation.
|
|
43
|
+
* @param {boolean} useCache - Whether to use caching
|
|
44
|
+
* @param {string} url - The URL to fetch
|
|
45
|
+
* @param {Object} requestHeaders - Request headers from the original request
|
|
46
|
+
* @param {string} method - HTTP method (GET, POST, etc.)
|
|
47
|
+
* @param {boolean} useFullUrl - Whether to use the full URL as cache key or just origin+path
|
|
48
|
+
* @param {boolean} successLogs - Whether to log successful requests
|
|
49
|
+
* @param {boolean} errorLogs - Whether to log error requests
|
|
50
|
+
* @returns {Promise<Object>} - The response object containing status, headers, and body
|
|
51
|
+
*/
|
|
52
|
+
async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl, successLogs, errorLogs) {
|
|
53
|
+
// Determine the cache key based on configuration
|
|
54
|
+
let mainUrl = new URL(url).origin + new URL(url).pathname;
|
|
55
|
+
if (useFullUrl) {
|
|
56
|
+
mainUrl = url;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Check if the response is cached
|
|
60
|
+
if (useCache) {
|
|
61
|
+
const cachedResponse = globalCache.get(mainUrl);
|
|
62
|
+
if (cachedResponse) {
|
|
63
|
+
if (successLogs) console.log(`Serving from globalCache: ${mainUrl}`);
|
|
64
|
+
return cachedResponse;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
// Fetch the resource using superagent
|
|
70
|
+
// buffer(true) ensures we get the raw binary data (essential for images/fonts)
|
|
71
|
+
const response = await superagent(method, url).set(requestHeaders).buffer(true);
|
|
72
|
+
|
|
73
|
+
// Determine the correct body type (Buffer for binary, text for others)
|
|
74
|
+
const responseBody = response.body instanceof Buffer ? response.body : response.text;
|
|
75
|
+
|
|
76
|
+
// Save to cache
|
|
77
|
+
globalCache.set(mainUrl, {
|
|
78
|
+
status: response.status,
|
|
79
|
+
headers: response.headers,
|
|
80
|
+
body: responseBody,
|
|
81
|
+
});
|
|
82
|
+
if (successLogs) console.log(`Success (cached): ${mainUrl}`);
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
status: response.status,
|
|
86
|
+
headers: response.headers,
|
|
87
|
+
body: responseBody,
|
|
88
|
+
};
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (errorLogs) console.error(`Failed to fetch: ${url}`, error);
|
|
91
|
+
// We return undefined on error, which signals the route handler to fall back to normal request
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Main function to set up routing, ad blocking, and request interception in Playwright.
|
|
97
|
+
* @param {Object} options - Configuration options
|
|
98
|
+
* @param {Object} options.context - Playwright context (optional, one is required)
|
|
99
|
+
* @param {Object} options.page - Playwright page (optional, one is required)
|
|
100
|
+
* @param {boolean} options.successLogs - Enable logging for successful fetches
|
|
101
|
+
* @param {boolean} options.errorLogs - Enable logging for failed fetches
|
|
102
|
+
* @param {boolean} options.blockImage - Enable global image blocking
|
|
103
|
+
* @param {boolean} options.blockAds - Enable Ghostery ad blocking
|
|
104
|
+
* @param {boolean} options.useGot - Enable custom fetching via Superagent (bypassing browser network stack for intercepted types)
|
|
105
|
+
* @param {boolean} options.useFullUrl - Use full URL for cache keys
|
|
106
|
+
* @param {boolean} options.useCache - Enable caching
|
|
107
|
+
* @param {Object} options.m4w_send_on_post - Custom handler data for Doublelist posts
|
|
108
|
+
* @param {Object} options.m4w_send_on_message - Custom handler data for Doublelist messages
|
|
109
|
+
* @param {Array<string>} options.allowImagePatterns - Array of strings/patterns. If a URL contains any of these, it will NOT be blocked even if blockImage is true.
|
|
110
|
+
* @param {Array<string>} options.skipGotPatterns - Array of strings/patterns. If a URL contains any of these, it will skip the custom Superagent fetch.
|
|
111
|
+
*/
|
|
112
|
+
export async function gotRoute({
|
|
113
|
+
context = null,
|
|
114
|
+
page = null,
|
|
115
|
+
successLogs = false,
|
|
116
|
+
errorLogs = false,
|
|
117
|
+
blockAds = true,
|
|
118
|
+
blockImage = true,
|
|
119
|
+
useGot = true,
|
|
120
|
+
useFullUrl = true,
|
|
121
|
+
useCache = true,
|
|
122
|
+
m4w_send_on_post = null,
|
|
123
|
+
m4w_send_on_message = null,
|
|
124
|
+
allowImagePatterns = [], // Default empty, merged inside
|
|
125
|
+
skipGotPatterns = [], // Default empty, merged inside
|
|
126
|
+
}) {
|
|
127
|
+
// Validation: Ensure we have a target to attach the route to
|
|
128
|
+
if (!context && !page) {
|
|
129
|
+
throw new Error("Either context or page must be provided.");
|
|
130
|
+
}
|
|
131
|
+
const contextOrPage = context ? context : page;
|
|
132
|
+
|
|
133
|
+
// --- SETUP: Merge Defaults for allowImagePatterns ---
|
|
134
|
+
// Always allow Cloudflare challenge platform images
|
|
135
|
+
const defaultAllowedPatterns = ["cdn-cgi/challenge-platform"];
|
|
136
|
+
const finalImagePatterns = [...defaultAllowedPatterns, ...allowImagePatterns];
|
|
137
|
+
|
|
138
|
+
// --- SETUP: Merge Defaults for skipGotPatterns ---
|
|
139
|
+
// Always skip custom fetch for Cloudflare challenges (let browser handle it)
|
|
140
|
+
const defaultSkipPatterns = [];
|
|
141
|
+
const finalSkipPatterns = [...defaultSkipPatterns, ...skipGotPatterns];
|
|
142
|
+
|
|
143
|
+
// Initialize ad blocking AdBlockEngine if enabled and not already loaded
|
|
144
|
+
if (blockAds && !AdBlockEngine) {
|
|
145
|
+
// console.log("Initializing AdBlockEngine..............................");
|
|
146
|
+
AdBlockEngine = await FiltersEngine.fromPrebuiltAdsAndTracking(fetch);
|
|
147
|
+
if (!AdBlockEngine) {
|
|
148
|
+
throw new Error("Failed to initialize AdBlockEngine.");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Define resource types to intercept for custom fetching (useGot)
|
|
153
|
+
const interceptedResourceTypes = ["stylesheet", "script", "font"];
|
|
154
|
+
|
|
155
|
+
// If images are NOT blocked, we generally want to intercept/cache them too.
|
|
156
|
+
if (!blockImage) {
|
|
157
|
+
interceptedResourceTypes.push("image");
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Set up the global route interception
|
|
161
|
+
await contextOrPage.route("**/*", async (route, request) => {
|
|
162
|
+
const url = request.url();
|
|
163
|
+
const method = request.method();
|
|
164
|
+
const resourceType = request.resourceType();
|
|
165
|
+
|
|
166
|
+
// ============================================================
|
|
167
|
+
// Group 1: Image Blocking
|
|
168
|
+
// ============================================================
|
|
169
|
+
if (blockImage && resourceType === "image") {
|
|
170
|
+
// Check against the merged list (defaults + user input)
|
|
171
|
+
const isAllowed = finalImagePatterns.some((pattern) => url.includes(pattern));
|
|
172
|
+
|
|
173
|
+
if (!isAllowed) {
|
|
174
|
+
route.abort();
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ============================================================
|
|
180
|
+
// Group 2: Ad Blocking
|
|
181
|
+
// ============================================================
|
|
182
|
+
if (blockAds && AdBlockEngine) {
|
|
183
|
+
const adsBlockResult = AdBlockEngine.match(
|
|
184
|
+
Request.fromRawDetails({
|
|
185
|
+
url: url,
|
|
186
|
+
type: resourceType,
|
|
187
|
+
})
|
|
188
|
+
);
|
|
189
|
+
if (adsBlockResult.match) {
|
|
190
|
+
route.abort();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// ============================================================
|
|
196
|
+
// Group 3: Specific Script Blocking (Cookie Law)
|
|
197
|
+
// ============================================================
|
|
198
|
+
if (url.includes("cdn.cookielaw.org")) {
|
|
199
|
+
route.abort();
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// ============================================================
|
|
204
|
+
// Group 4: m4w_send_on_message Handling (Doublelist API)
|
|
205
|
+
// ============================================================
|
|
206
|
+
if (m4w_send_on_message && url.includes("api.doublelist.com/api/messages") && method === "POST") {
|
|
207
|
+
const headers = request.headers();
|
|
208
|
+
const postData = request.postData();
|
|
209
|
+
const urlParams = new URLSearchParams(postData);
|
|
210
|
+
const messageJSON = decodeURIComponent(urlParams.get("messageJSON"));
|
|
211
|
+
const parsedMessageJSON = JSON.parse(messageJSON);
|
|
212
|
+
|
|
213
|
+
m4w_send_on_message.sender_id = parsedMessageJSON.sender_id;
|
|
214
|
+
const authorizationHeader = headers["authorization"];
|
|
215
|
+
m4w_send_on_message.token_value = authorizationHeader.replace("Bearer ", "");
|
|
216
|
+
|
|
217
|
+
console.log("posts_send_message Blocked (Data Extracted)");
|
|
218
|
+
route.abort();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (m4w_send_on_message && url.includes("https://doublelist.com/posts_send_message/")) {
|
|
223
|
+
console.log("posts_send_message Blocked");
|
|
224
|
+
route.abort();
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ============================================================
|
|
229
|
+
// Group 5: m4w_send_on_post Handling (Doublelist API)
|
|
230
|
+
// ============================================================
|
|
231
|
+
if (m4w_send_on_post && url.includes("api.doublelist.com/api/messages") && method === "POST") {
|
|
232
|
+
if (
|
|
233
|
+
m4w_send_on_post.current_post_id &&
|
|
234
|
+
m4w_send_on_post.current_post_id !== m4w_send_on_post.last_post_id &&
|
|
235
|
+
m4w_send_on_post.current_send_to &&
|
|
236
|
+
m4w_send_on_post.current_send_to != m4w_send_on_post.last_send_to
|
|
237
|
+
) {
|
|
238
|
+
m4w_send_on_post.last_send_to = m4w_send_on_post.current_send_to;
|
|
239
|
+
m4w_send_on_post.last_post_id = m4w_send_on_post.current_post_id;
|
|
240
|
+
|
|
241
|
+
let postData = request.postData();
|
|
242
|
+
const urlParams = new URLSearchParams(postData);
|
|
243
|
+
const messageJSON = decodeURIComponent(urlParams.get("messageJSON"));
|
|
244
|
+
let parsedMessageJSON = JSON.parse(messageJSON);
|
|
245
|
+
|
|
246
|
+
parsedMessageJSON.chat_user = m4w_send_on_post.current_send_to;
|
|
247
|
+
parsedMessageJSON.post_id = m4w_send_on_post.current_post_id;
|
|
248
|
+
|
|
249
|
+
urlParams.set("messageJSON", JSON.stringify(parsedMessageJSON));
|
|
250
|
+
const final_postData = urlParams.toString();
|
|
251
|
+
|
|
252
|
+
await route.continue({
|
|
253
|
+
postData: final_postData,
|
|
254
|
+
});
|
|
255
|
+
return;
|
|
256
|
+
} else {
|
|
257
|
+
console.log("send Message route abort (Duplicate or missing data)");
|
|
258
|
+
route.abort();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (m4w_send_on_post && url.includes("https://doublelist.com/posts_send_message/")) {
|
|
264
|
+
console.log("posts_send_message Blocked");
|
|
265
|
+
await route.abort();
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (m4w_send_on_post && url.includes("doublelist.com/messages/")) {
|
|
270
|
+
console.log("doublelist.com/messages/ Redirected");
|
|
271
|
+
await route.fulfill({
|
|
272
|
+
status: 302,
|
|
273
|
+
headers: {
|
|
274
|
+
location: "https://httpbin.org/ip",
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// ============================================================
|
|
281
|
+
// Group 6: Resource Interception (Custom Fetch/Cache)
|
|
282
|
+
// ============================================================
|
|
283
|
+
if (useGot && interceptedResourceTypes.includes(resourceType)) {
|
|
284
|
+
// Check against the merged list (defaults + user input)
|
|
285
|
+
const shouldSkipGot = finalSkipPatterns.some((pattern) => url.includes(pattern));
|
|
286
|
+
|
|
287
|
+
if (!shouldSkipGot) {
|
|
288
|
+
const requestHeaders = request.headers();
|
|
289
|
+
const requestMethod = request.method();
|
|
290
|
+
|
|
291
|
+
const response = await fetchWithClient(
|
|
292
|
+
useCache,
|
|
293
|
+
url,
|
|
294
|
+
requestHeaders,
|
|
295
|
+
requestMethod,
|
|
296
|
+
useFullUrl,
|
|
297
|
+
successLogs,
|
|
298
|
+
errorLogs
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
if (response) {
|
|
302
|
+
await route.fulfill({
|
|
303
|
+
status: response.status,
|
|
304
|
+
headers: response.headers,
|
|
305
|
+
body: response.body,
|
|
306
|
+
});
|
|
307
|
+
return;
|
|
308
|
+
} else {
|
|
309
|
+
if (errorLogs) console.log("Continuing with normal request (fetchWithClient returned null):", url);
|
|
310
|
+
await route.continue();
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// ============================================================
|
|
317
|
+
// Default: Continue with normal request
|
|
318
|
+
// ============================================================
|
|
319
|
+
await route.continue();
|
|
320
|
+
return;
|
|
321
|
+
});
|
|
322
|
+
}
|