arn-browser 0.1.16 → 0.1.18
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
package/src/utility/mlx_token.js
CHANGED
|
@@ -3,18 +3,12 @@
|
|
|
3
3
|
import crypto from "crypto";
|
|
4
4
|
import { arn, query } from "arn-knexjs";
|
|
5
5
|
|
|
6
|
-
// Module-level cache for credentials (fetched once per process)
|
|
7
|
-
let _credentials = null;
|
|
8
|
-
|
|
9
6
|
/**
|
|
10
7
|
* Loads Multilogin credentials from the database.
|
|
11
|
-
*
|
|
12
|
-
* Results are cached in-memory so the DB is only hit once per process.
|
|
8
|
+
* Always reads fresh from DB (no in-memory cache) to support multiple processes.
|
|
13
9
|
* @returns {Promise<{id: string, email: string, password: string, workspace_id: string, data: object}>}
|
|
14
10
|
*/
|
|
15
11
|
async function loadCredentials() {
|
|
16
|
-
if (_credentials) return _credentials;
|
|
17
|
-
|
|
18
12
|
const { data: [row] = [], error } = await arn.single(
|
|
19
13
|
query("api_multilogin_token").select("*").where({ status: 1 }).orderByRaw("random()").limit(1)
|
|
20
14
|
);
|
|
@@ -23,13 +17,10 @@ async function loadCredentials() {
|
|
|
23
17
|
throw new Error("[TokenManager] No active Multilogin credentials found (status = 1).");
|
|
24
18
|
}
|
|
25
19
|
|
|
26
|
-
|
|
27
|
-
return _credentials;
|
|
20
|
+
return row;
|
|
28
21
|
}
|
|
29
22
|
|
|
30
|
-
async function saveTokens(tokens) {
|
|
31
|
-
const creds = await loadCredentials();
|
|
32
|
-
|
|
23
|
+
async function saveTokens(creds, tokens) {
|
|
33
24
|
await arn.single(
|
|
34
25
|
query("api_multilogin_token")
|
|
35
26
|
.update({
|
|
@@ -39,18 +30,6 @@ async function saveTokens(tokens) {
|
|
|
39
30
|
);
|
|
40
31
|
}
|
|
41
32
|
|
|
42
|
-
async function loadTokens() {
|
|
43
|
-
try {
|
|
44
|
-
const creds = await loadCredentials();
|
|
45
|
-
if (!creds.data || Object.keys(creds.data).length === 0) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
return creds.data;
|
|
49
|
-
} catch (err) {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
33
|
function isJwtExpired(token) {
|
|
55
34
|
if (!token) return true;
|
|
56
35
|
try {
|
|
@@ -62,9 +41,7 @@ function isJwtExpired(token) {
|
|
|
62
41
|
}
|
|
63
42
|
}
|
|
64
43
|
|
|
65
|
-
async function loginAndSaveTokens() {
|
|
66
|
-
const creds = await loadCredentials();
|
|
67
|
-
|
|
44
|
+
async function loginAndSaveTokens(creds) {
|
|
68
45
|
const passwordHash = crypto.createHash("md5").update(creds.password).digest("hex");
|
|
69
46
|
const data = {
|
|
70
47
|
email: creds.email,
|
|
@@ -85,7 +62,7 @@ async function loginAndSaveTokens() {
|
|
|
85
62
|
const json = await res.json();
|
|
86
63
|
const { token, refresh_token } = json.data;
|
|
87
64
|
|
|
88
|
-
await saveTokens({
|
|
65
|
+
await saveTokens(creds, {
|
|
89
66
|
token,
|
|
90
67
|
refresh_token,
|
|
91
68
|
email: creds.email,
|
|
@@ -96,9 +73,7 @@ async function loginAndSaveTokens() {
|
|
|
96
73
|
return { token, refresh_token };
|
|
97
74
|
}
|
|
98
75
|
|
|
99
|
-
async function refreshAndSaveTokens(refresh_token) {
|
|
100
|
-
const creds = await loadCredentials();
|
|
101
|
-
|
|
76
|
+
async function refreshAndSaveTokens(creds, refresh_token) {
|
|
102
77
|
const data = {
|
|
103
78
|
email: creds.email,
|
|
104
79
|
refresh_token: refresh_token,
|
|
@@ -119,7 +94,7 @@ async function refreshAndSaveTokens(refresh_token) {
|
|
|
119
94
|
const json = await res.json();
|
|
120
95
|
const { token, refresh_token: new_refresh } = json.data;
|
|
121
96
|
|
|
122
|
-
await saveTokens({
|
|
97
|
+
await saveTokens(creds, {
|
|
123
98
|
token,
|
|
124
99
|
refresh_token: new_refresh,
|
|
125
100
|
email: creds.email,
|
|
@@ -131,7 +106,8 @@ async function refreshAndSaveTokens(refresh_token) {
|
|
|
131
106
|
}
|
|
132
107
|
|
|
133
108
|
async function getMultiloginToken() {
|
|
134
|
-
|
|
109
|
+
const creds = await loadCredentials();
|
|
110
|
+
const tokens = creds.data && Object.keys(creds.data).length > 0 ? creds.data : null;
|
|
135
111
|
|
|
136
112
|
if (tokens && tokens.token && !isJwtExpired(tokens.token)) {
|
|
137
113
|
return tokens.token;
|
|
@@ -139,14 +115,14 @@ async function getMultiloginToken() {
|
|
|
139
115
|
|
|
140
116
|
if (tokens && tokens.refresh_token) {
|
|
141
117
|
try {
|
|
142
|
-
const { token } = await refreshAndSaveTokens(tokens.refresh_token);
|
|
118
|
+
const { token } = await refreshAndSaveTokens(creds, tokens.refresh_token);
|
|
143
119
|
return token;
|
|
144
120
|
} catch (err) {
|
|
145
121
|
console.warn("[REFRESH FAILED] Will login again:", err.message);
|
|
146
122
|
}
|
|
147
123
|
}
|
|
148
124
|
|
|
149
|
-
const { token } = await loginAndSaveTokens();
|
|
125
|
+
const { token } = await loginAndSaveTokens(creds);
|
|
150
126
|
return token;
|
|
151
127
|
}
|
|
152
128
|
|
|
@@ -90,11 +90,13 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
|
|
|
90
90
|
mainUrl = url;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
const viaProxy = proxyAgent ? " via Proxy" : "";
|
|
94
|
+
|
|
93
95
|
// Check if the response is cached
|
|
94
96
|
if (useCache) {
|
|
95
97
|
const cachedResponse = globalCache.get(mainUrl);
|
|
96
98
|
if (cachedResponse) {
|
|
97
|
-
if (logger === "info") console.log(`Serving from globalCache: ${mainUrl}`);
|
|
99
|
+
if (logger === "info") console.log(`Serving from globalCache${viaProxy}: ${mainUrl}`);
|
|
98
100
|
return cachedResponse;
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -121,9 +123,9 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
|
|
|
121
123
|
headers: response.headers,
|
|
122
124
|
body: responseBody,
|
|
123
125
|
});
|
|
124
|
-
if (logger === "info") console.log(`Success (cached): ${mainUrl}`);
|
|
126
|
+
if (logger === "info") console.log(`Success (cached${viaProxy}): ${mainUrl}`);
|
|
125
127
|
} else {
|
|
126
|
-
if (logger === "info") console.log(`Success (not cached): ${mainUrl}`);
|
|
128
|
+
if (logger === "info") console.log(`Success (not cached${viaProxy}): ${mainUrl}`);
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
return {
|
|
@@ -183,7 +185,15 @@ export async function pwRoute({
|
|
|
183
185
|
// --- SETUP: Merge Defaults for skipGotPatterns ---
|
|
184
186
|
// Always skip custom fetch for Cloudflare challenges (let browser handle it)
|
|
185
187
|
const defaultSkipPatterns = [];
|
|
186
|
-
|
|
188
|
+
// Normalize: if entry contains "://", extract hostname. Otherwise keep as-is (assumed to be a hostname).
|
|
189
|
+
const finalSkipHosts = new Set(
|
|
190
|
+
[...defaultSkipPatterns, ...skipGotPatterns].map((entry) => {
|
|
191
|
+
try {
|
|
192
|
+
if (entry.includes("://")) return new URL(entry).hostname;
|
|
193
|
+
} catch {}
|
|
194
|
+
return entry;
|
|
195
|
+
})
|
|
196
|
+
);
|
|
187
197
|
|
|
188
198
|
// Initialize ad blocking AdBlockEngine if enabled and not already loaded
|
|
189
199
|
if (blockAds && !AdBlockEngine) {
|
|
@@ -329,9 +339,12 @@ export async function pwRoute({
|
|
|
329
339
|
// ============================================================
|
|
330
340
|
// Group 6: Resource Interception (Custom Fetch/Cache)
|
|
331
341
|
// ============================================================
|
|
332
|
-
if (useGot && interceptedResourceTypes.includes(resourceType)) {
|
|
333
|
-
// Check against the
|
|
334
|
-
|
|
342
|
+
if (useGot && interceptedResourceTypes.includes(resourceType) && !url.startsWith("data:")) {
|
|
343
|
+
// Check against the normalized host list (defaults + user input)
|
|
344
|
+
let shouldSkipGot = false;
|
|
345
|
+
try {
|
|
346
|
+
shouldSkipGot = finalSkipHosts.has(new URL(url).hostname);
|
|
347
|
+
} catch {}
|
|
335
348
|
|
|
336
349
|
if (!shouldSkipGot) {
|
|
337
350
|
const requestHeaders = request.headers();
|
|
@@ -90,11 +90,13 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
|
|
|
90
90
|
mainUrl = url;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
const viaProxy = proxyAgent ? " via Proxy" : "";
|
|
94
|
+
|
|
93
95
|
// Check if the response is cached
|
|
94
96
|
if (useCache) {
|
|
95
97
|
const cachedResponse = globalCache.get(mainUrl);
|
|
96
98
|
if (cachedResponse) {
|
|
97
|
-
if (logger === "info") console.log(`Serving from globalCache: ${mainUrl}`);
|
|
99
|
+
if (logger === "info") console.log(`Serving from globalCache${viaProxy}: ${mainUrl}`);
|
|
98
100
|
return cachedResponse;
|
|
99
101
|
}
|
|
100
102
|
}
|
|
@@ -121,9 +123,9 @@ async function fetchWithClient(useCache, url, requestHeaders, method, useFullUrl
|
|
|
121
123
|
headers: response.headers,
|
|
122
124
|
body: responseBody,
|
|
123
125
|
});
|
|
124
|
-
if (logger === "info") console.log(`Success (cached): ${mainUrl}`);
|
|
126
|
+
if (logger === "info") console.log(`Success (cached${viaProxy}): ${mainUrl}`);
|
|
125
127
|
} else {
|
|
126
|
-
if (logger === "info") console.log(`Success (not cached): ${mainUrl}`);
|
|
128
|
+
if (logger === "info") console.log(`Success (not cached${viaProxy}): ${mainUrl}`);
|
|
127
129
|
}
|
|
128
130
|
|
|
129
131
|
return {
|
|
@@ -180,7 +182,15 @@ export async function ppRoute({
|
|
|
180
182
|
// --- SETUP: Merge Defaults for skipGotPatterns ---
|
|
181
183
|
// Always skip custom fetch for Cloudflare challenges (let browser handle it)
|
|
182
184
|
const defaultSkipPatterns = [];
|
|
183
|
-
|
|
185
|
+
// Normalize: if entry contains "://", extract hostname. Otherwise keep as-is (assumed to be a hostname).
|
|
186
|
+
const finalSkipHosts = new Set(
|
|
187
|
+
[...defaultSkipPatterns, ...skipGotPatterns].map((entry) => {
|
|
188
|
+
try {
|
|
189
|
+
if (entry.includes("://")) return new URL(entry).hostname;
|
|
190
|
+
} catch {}
|
|
191
|
+
return entry;
|
|
192
|
+
})
|
|
193
|
+
);
|
|
184
194
|
|
|
185
195
|
// Initialize ad blocking AdBlockEngine if enabled and not already loaded
|
|
186
196
|
if (blockAds && !AdBlockEngine) {
|
|
@@ -332,9 +342,12 @@ export async function ppRoute({
|
|
|
332
342
|
// ============================================================
|
|
333
343
|
// Group 6: Resource Interception (Custom Fetch/Cache)
|
|
334
344
|
// ============================================================
|
|
335
|
-
if (useGot && interceptedResourceTypes.includes(resourceType)) {
|
|
336
|
-
// Check against the
|
|
337
|
-
|
|
345
|
+
if (useGot && interceptedResourceTypes.includes(resourceType) && !url.startsWith("data:")) {
|
|
346
|
+
// Check against the normalized host list (defaults + user input)
|
|
347
|
+
let shouldSkipGot = false;
|
|
348
|
+
try {
|
|
349
|
+
shouldSkipGot = finalSkipHosts.has(new URL(url).hostname);
|
|
350
|
+
} catch {}
|
|
338
351
|
|
|
339
352
|
if (!shouldSkipGot) {
|
|
340
353
|
const requestHeaders = request.headers();
|