brave-real-browser 1.5.95 → 1.5.97
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/FIXES_NEEDED.md +131 -0
- package/lib/cjs/module/pageController.js +141 -34
- package/lib/esm/module/pageController.mjs +144 -34
- package/lib/esm/module/turnstile.mjs +4 -3
- package/package.json +2 -2
package/FIXES_NEEDED.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Brave-Real-Browser - Critical Fixes Needed
|
|
2
|
+
|
|
3
|
+
## ⚠️ Note
|
|
4
|
+
यह project compiled JavaScript library है। Source code इस repository में नहीं है।
|
|
5
|
+
|
|
6
|
+
## Critical Issues to Fix in Source Repository
|
|
7
|
+
|
|
8
|
+
### 1. **pageController Error Handling** (Critical)
|
|
9
|
+
**File**: `src/module/pageController.js` (in source repo)
|
|
10
|
+
**Issue**: Promise rejections और errors को properly handle नहीं किया गया
|
|
11
|
+
**Fix Required**:
|
|
12
|
+
```javascript
|
|
13
|
+
// Add comprehensive try-catch blocks
|
|
14
|
+
async function handleNavigation(page, url) {
|
|
15
|
+
try {
|
|
16
|
+
await page.goto(url, { timeout: 30000 });
|
|
17
|
+
} catch (error) {
|
|
18
|
+
if (error.name === 'TimeoutError') {
|
|
19
|
+
throw new NavigationTimeoutError(`Navigation to ${url} timed out`);
|
|
20
|
+
}
|
|
21
|
+
throw new NavigationError(`Failed to navigate: ${error.message}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Add error recovery mechanisms
|
|
26
|
+
async function withRetry(fn, maxRetries = 3) {
|
|
27
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
28
|
+
try {
|
|
29
|
+
return await fn();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (i === maxRetries - 1) throw error;
|
|
32
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 2. **turnstileSolver Infinite Loop Fix** (Critical)
|
|
39
|
+
**File**: `src/module/turnstileSolver.js` (in source repo)
|
|
40
|
+
**Issue**: Infinite loop possibility without timeout or max attempts
|
|
41
|
+
**Fix Required**:
|
|
42
|
+
```javascript
|
|
43
|
+
async function solveTurnstile(page, maxAttempts = 10, timeout = 60000) {
|
|
44
|
+
const startTime = Date.now();
|
|
45
|
+
let attempts = 0;
|
|
46
|
+
|
|
47
|
+
while (attempts < maxAttempts) {
|
|
48
|
+
// Check timeout
|
|
49
|
+
if (Date.now() - startTime > timeout) {
|
|
50
|
+
throw new TurnstileTimeoutError('Turnstile solving timed out');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
attempts++;
|
|
54
|
+
|
|
55
|
+
try {
|
|
56
|
+
const solved = await attemptSolve(page);
|
|
57
|
+
if (solved) return true;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(`Turnstile attempt ${attempts} failed:`, error);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Exponential backoff
|
|
63
|
+
await new Promise(resolve =>
|
|
64
|
+
setTimeout(resolve, Math.min(1000 * Math.pow(2, attempts), 10000))
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
throw new TurnstileMaxAttemptsError(`Failed after ${maxAttempts} attempts`);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. **Proxy Validation** (Medium)
|
|
73
|
+
**Fix Required**:
|
|
74
|
+
```javascript
|
|
75
|
+
function validateProxy(proxy) {
|
|
76
|
+
if (!proxy) return null;
|
|
77
|
+
|
|
78
|
+
const proxyRegex = /^(https?|socks[45]):\/\/([^:]+):(\d+)$/;
|
|
79
|
+
if (!proxyRegex.test(proxy)) {
|
|
80
|
+
throw new Error('Invalid proxy format. Expected: protocol://host:port');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return proxy;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 4. **Better Error Messages**
|
|
88
|
+
```javascript
|
|
89
|
+
class BrowserError extends Error {
|
|
90
|
+
constructor(message, code, details) {
|
|
91
|
+
super(message);
|
|
92
|
+
this.name = 'BrowserError';
|
|
93
|
+
this.code = code;
|
|
94
|
+
this.details = details;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
class NavigationError extends BrowserError {
|
|
99
|
+
constructor(message, details) {
|
|
100
|
+
super(message, 'NAVIGATION_ERROR', details);
|
|
101
|
+
this.name = 'NavigationError';
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Version Synchronization Required
|
|
107
|
+
- Current version: 1.5.95
|
|
108
|
+
- Should match: brave-real-launcher, brave-real-puppeteer-core
|
|
109
|
+
- Add version validation on startup
|
|
110
|
+
|
|
111
|
+
## Dependencies to Update
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"dependencies": {
|
|
115
|
+
"brave-real-launcher": "^1.5.95",
|
|
116
|
+
"brave-real-puppeteer-core": "^1.5.95"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Testing Requirements
|
|
122
|
+
1. Add unit tests for error handling
|
|
123
|
+
2. Add integration tests with other components
|
|
124
|
+
3. Add timeout/infinite loop regression tests
|
|
125
|
+
4. Add proxy validation tests
|
|
126
|
+
|
|
127
|
+
## Documentation Needed
|
|
128
|
+
1. API documentation
|
|
129
|
+
2. Error handling guide
|
|
130
|
+
3. Configuration examples
|
|
131
|
+
4. Troubleshooting guide
|
|
@@ -2,6 +2,11 @@ const { createCursor } = require('ghost-cursor');
|
|
|
2
2
|
const { checkTurnstile } = require('./turnstile.js');
|
|
3
3
|
const kill = require('tree-kill');
|
|
4
4
|
|
|
5
|
+
// Configuration constants
|
|
6
|
+
const TURNSTILE_CHECK_INTERVAL = 1000; // 1 second
|
|
7
|
+
const TURNSTILE_MAX_ATTEMPTS = 300; // 5 minutes max (300 attempts * 1 second)
|
|
8
|
+
const TURNSTILE_TIMEOUT = 300000; // 5 minutes in milliseconds
|
|
9
|
+
|
|
5
10
|
function getRandomInt(min, max) {
|
|
6
11
|
min = Math.ceil(min);
|
|
7
12
|
max = Math.floor(max);
|
|
@@ -10,60 +15,162 @@ function getRandomInt(min, max) {
|
|
|
10
15
|
|
|
11
16
|
async function pageController({ browser, page, proxy, turnstile, xvfbsession, pid, plugins, killProcess = false, chrome }) {
|
|
12
17
|
|
|
13
|
-
let solveStatus = turnstile
|
|
18
|
+
let solveStatus = turnstile;
|
|
19
|
+
let turnstileSolverRunning = false;
|
|
20
|
+
|
|
21
|
+
// Safe cleanup function
|
|
22
|
+
const cleanup = async () => {
|
|
23
|
+
solveStatus = false;
|
|
24
|
+
if (killProcess === true) {
|
|
25
|
+
if (xvfbsession) {
|
|
26
|
+
try {
|
|
27
|
+
xvfbsession.stopSync();
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.error('Error stopping Xvfb session:', err.message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (chrome) {
|
|
33
|
+
try {
|
|
34
|
+
chrome.kill();
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error('Error killing Chrome process:', err.message);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (pid) {
|
|
40
|
+
try {
|
|
41
|
+
kill(pid, 'SIGKILL', (err) => {
|
|
42
|
+
if (err) console.error('Error killing process:', err.message);
|
|
43
|
+
});
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error('Error in kill command:', err.message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
14
50
|
|
|
15
51
|
page.on('close', () => {
|
|
16
|
-
solveStatus = false
|
|
52
|
+
solveStatus = false;
|
|
17
53
|
});
|
|
18
54
|
|
|
19
|
-
|
|
20
55
|
browser.on('disconnected', async () => {
|
|
21
|
-
|
|
22
|
-
if (killProcess === true) {
|
|
23
|
-
if (xvfbsession) try { xvfbsession.stopSync() } catch (err) { }
|
|
24
|
-
if (chrome) try { chrome.kill() } catch (err) { console.log(err); }
|
|
25
|
-
if (pid) try { kill(pid, 'SIGKILL', () => { }) } catch (err) { }
|
|
26
|
-
}
|
|
56
|
+
await cleanup();
|
|
27
57
|
});
|
|
28
58
|
|
|
59
|
+
// Enhanced turnstile solver with timeout and max attempts protection
|
|
29
60
|
async function turnstileSolver() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
61
|
+
if (turnstileSolverRunning) {
|
|
62
|
+
console.warn('Turnstile solver already running, skipping duplicate start');
|
|
63
|
+
return;
|
|
33
64
|
}
|
|
34
|
-
|
|
35
|
-
|
|
65
|
+
|
|
66
|
+
turnstileSolverRunning = true;
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
let attempts = 0;
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
while (solveStatus && attempts < TURNSTILE_MAX_ATTEMPTS) {
|
|
72
|
+
// Check timeout
|
|
73
|
+
if (Date.now() - startTime > TURNSTILE_TIMEOUT) {
|
|
74
|
+
console.warn('Turnstile solver timeout reached after', attempts, 'attempts');
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Check if page is still valid
|
|
79
|
+
if (page.isClosed()) {
|
|
80
|
+
console.log('Page closed, stopping turnstile solver');
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
attempts++;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
await checkTurnstile({ page });
|
|
88
|
+
} catch (err) {
|
|
89
|
+
// Silent fail for individual checks, log only if debug enabled
|
|
90
|
+
if (process.env.DEBUG === 'true') {
|
|
91
|
+
console.debug('Turnstile check failed:', err.message);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Wait before next check
|
|
96
|
+
await new Promise(r => setTimeout(r, TURNSTILE_CHECK_INTERVAL));
|
|
97
|
+
}
|
|
36
98
|
|
|
37
|
-
|
|
99
|
+
if (attempts >= TURNSTILE_MAX_ATTEMPTS) {
|
|
100
|
+
console.warn('Turnstile solver stopped: max attempts reached');
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error('Error in turnstile solver:', err.message);
|
|
104
|
+
} finally {
|
|
105
|
+
turnstileSolverRunning = false;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
38
108
|
|
|
39
|
-
|
|
109
|
+
// Start turnstile solver only if enabled
|
|
110
|
+
if (turnstile) {
|
|
111
|
+
turnstileSolver().catch(err => {
|
|
112
|
+
console.error('Failed to start turnstile solver:', err.message);
|
|
113
|
+
});
|
|
114
|
+
}
|
|
40
115
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
116
|
+
// Proxy authentication with error handling
|
|
117
|
+
if (proxy && proxy.username && proxy.password) {
|
|
118
|
+
try {
|
|
119
|
+
await page.authenticate({
|
|
120
|
+
username: proxy.username,
|
|
121
|
+
password: proxy.password
|
|
122
|
+
});
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.error('Proxy authentication failed:', err.message);
|
|
125
|
+
throw new Error(`Failed to authenticate proxy: ${err.message}`);
|
|
44
126
|
}
|
|
45
127
|
}
|
|
46
128
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
129
|
+
// Plugin initialization with error handling
|
|
130
|
+
if (plugins && plugins.length > 0) {
|
|
131
|
+
for (const plugin of plugins) {
|
|
132
|
+
try {
|
|
133
|
+
if (plugin && typeof plugin.onPageCreated === 'function') {
|
|
134
|
+
await plugin.onPageCreated(page);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.error('Plugin initialization failed:', err.message);
|
|
138
|
+
// Continue with other plugins even if one fails
|
|
51
139
|
}
|
|
52
|
-
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
53
142
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
143
|
+
// Mouse event handling with error handling
|
|
144
|
+
try {
|
|
145
|
+
await page.evaluateOnNewDocument(() => {
|
|
146
|
+
Object.defineProperty(MouseEvent.prototype, 'screenX', {
|
|
147
|
+
get: function () {
|
|
148
|
+
return this.clientX + window.screenX;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
Object.defineProperty(MouseEvent.prototype, 'screenY', {
|
|
153
|
+
get: function () {
|
|
154
|
+
return this.clientY + window.screenY;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
58
157
|
});
|
|
158
|
+
} catch (err) {
|
|
159
|
+
console.error('Failed to setup mouse event handlers:', err.message);
|
|
160
|
+
// Non-critical, continue anyway
|
|
161
|
+
}
|
|
59
162
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
163
|
+
// Cursor setup with error handling
|
|
164
|
+
try {
|
|
165
|
+
const cursor = createCursor(page);
|
|
166
|
+
page.realCursor = cursor;
|
|
167
|
+
page.realClick = cursor.click;
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.error('Failed to create ghost cursor:', err.message);
|
|
170
|
+
// Non-critical, continue anyway
|
|
171
|
+
}
|
|
65
172
|
|
|
66
|
-
return page
|
|
173
|
+
return page;
|
|
67
174
|
}
|
|
68
175
|
|
|
69
176
|
module.exports = { pageController }
|
|
@@ -2,65 +2,175 @@ import { createCursor } from 'ghost-cursor';
|
|
|
2
2
|
import { checkTurnstile } from './turnstile.mjs';
|
|
3
3
|
import kill from 'tree-kill';
|
|
4
4
|
|
|
5
|
+
// Configuration constants
|
|
6
|
+
const TURNSTILE_CHECK_INTERVAL = 1000; // 1 second
|
|
7
|
+
const TURNSTILE_MAX_ATTEMPTS = 300; // 5 minutes max (300 attempts * 1 second)
|
|
8
|
+
const TURNSTILE_TIMEOUT = 300000; // 5 minutes in milliseconds
|
|
9
|
+
|
|
5
10
|
function getRandomInt(min, max) {
|
|
6
11
|
min = Math.ceil(min);
|
|
7
12
|
max = Math.floor(max);
|
|
8
13
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
9
14
|
}
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
async function pageController({ browser, page, proxy, turnstile, xvfbsession, pid, plugins, killProcess = false, chrome }) {
|
|
17
|
+
|
|
18
|
+
let solveStatus = turnstile;
|
|
19
|
+
let turnstileSolverRunning = false;
|
|
12
20
|
|
|
13
|
-
|
|
21
|
+
// Safe cleanup function
|
|
22
|
+
const cleanup = async () => {
|
|
23
|
+
solveStatus = false;
|
|
24
|
+
if (killProcess === true) {
|
|
25
|
+
if (xvfbsession) {
|
|
26
|
+
try {
|
|
27
|
+
xvfbsession.stopSync();
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.error('Error stopping Xvfb session:', err.message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (chrome) {
|
|
33
|
+
try {
|
|
34
|
+
chrome.kill();
|
|
35
|
+
} catch (err) {
|
|
36
|
+
console.error('Error killing Chrome process:', err.message);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (pid) {
|
|
40
|
+
try {
|
|
41
|
+
kill(pid, 'SIGKILL', (err) => {
|
|
42
|
+
if (err) console.error('Error killing process:', err.message);
|
|
43
|
+
});
|
|
44
|
+
} catch (err) {
|
|
45
|
+
console.error('Error in kill command:', err.message);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
14
50
|
|
|
15
51
|
page.on('close', () => {
|
|
16
|
-
solveStatus = false
|
|
52
|
+
solveStatus = false;
|
|
17
53
|
});
|
|
18
54
|
|
|
19
|
-
|
|
20
55
|
browser.on('disconnected', async () => {
|
|
21
|
-
|
|
22
|
-
if (killProcess === true) {
|
|
23
|
-
if (xvfbsession) try { xvfbsession.stopSync() } catch (err) { }
|
|
24
|
-
if (chrome) try { chrome.kill() } catch (err) { console.log(err); }
|
|
25
|
-
if (pid) try { kill(pid, 'SIGKILL', () => { }) } catch (err) { }
|
|
26
|
-
}
|
|
56
|
+
await cleanup();
|
|
27
57
|
});
|
|
28
58
|
|
|
59
|
+
// Enhanced turnstile solver with timeout and max attempts protection
|
|
29
60
|
async function turnstileSolver() {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
61
|
+
if (turnstileSolverRunning) {
|
|
62
|
+
console.warn('Turnstile solver already running, skipping duplicate start');
|
|
63
|
+
return;
|
|
33
64
|
}
|
|
34
|
-
|
|
35
|
-
|
|
65
|
+
|
|
66
|
+
turnstileSolverRunning = true;
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
let attempts = 0;
|
|
36
69
|
|
|
37
|
-
|
|
70
|
+
try {
|
|
71
|
+
while (solveStatus && attempts < TURNSTILE_MAX_ATTEMPTS) {
|
|
72
|
+
// Check timeout
|
|
73
|
+
if (Date.now() - startTime > TURNSTILE_TIMEOUT) {
|
|
74
|
+
console.warn('Turnstile solver timeout reached after', attempts, 'attempts');
|
|
75
|
+
break;
|
|
76
|
+
}
|
|
38
77
|
|
|
39
|
-
|
|
78
|
+
// Check if page is still valid
|
|
79
|
+
if (page.isClosed()) {
|
|
80
|
+
console.log('Page closed, stopping turnstile solver');
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
40
83
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
84
|
+
attempts++;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
await checkTurnstile({ page });
|
|
88
|
+
} catch (err) {
|
|
89
|
+
// Silent fail for individual checks, log only if debug enabled
|
|
90
|
+
if (process.env.DEBUG === 'true') {
|
|
91
|
+
console.debug('Turnstile check failed:', err.message);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Wait before next check
|
|
96
|
+
await new Promise(r => setTimeout(r, TURNSTILE_CHECK_INTERVAL));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (attempts >= TURNSTILE_MAX_ATTEMPTS) {
|
|
100
|
+
console.warn('Turnstile solver stopped: max attempts reached');
|
|
101
|
+
}
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error('Error in turnstile solver:', err.message);
|
|
104
|
+
} finally {
|
|
105
|
+
turnstileSolverRunning = false;
|
|
44
106
|
}
|
|
45
107
|
}
|
|
46
108
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
109
|
+
// Start turnstile solver only if enabled
|
|
110
|
+
if (turnstile) {
|
|
111
|
+
turnstileSolver().catch(err => {
|
|
112
|
+
console.error('Failed to start turnstile solver:', err.message);
|
|
52
113
|
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Proxy authentication with error handling
|
|
117
|
+
if (proxy && proxy.username && proxy.password) {
|
|
118
|
+
try {
|
|
119
|
+
await page.authenticate({
|
|
120
|
+
username: proxy.username,
|
|
121
|
+
password: proxy.password
|
|
122
|
+
});
|
|
123
|
+
} catch (err) {
|
|
124
|
+
console.error('Proxy authentication failed:', err.message);
|
|
125
|
+
throw new Error(`Failed to authenticate proxy: ${err.message}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
53
128
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
129
|
+
// Plugin initialization with error handling
|
|
130
|
+
if (plugins && plugins.length > 0) {
|
|
131
|
+
for (const plugin of plugins) {
|
|
132
|
+
try {
|
|
133
|
+
if (plugin && typeof plugin.onPageCreated === 'function') {
|
|
134
|
+
await plugin.onPageCreated(page);
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
console.error('Plugin initialization failed:', err.message);
|
|
138
|
+
// Continue with other plugins even if one fails
|
|
57
139
|
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Mouse event handling with error handling
|
|
144
|
+
try {
|
|
145
|
+
await page.evaluateOnNewDocument(() => {
|
|
146
|
+
Object.defineProperty(MouseEvent.prototype, 'screenX', {
|
|
147
|
+
get: function () {
|
|
148
|
+
return this.clientX + window.screenX;
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
Object.defineProperty(MouseEvent.prototype, 'screenY', {
|
|
153
|
+
get: function () {
|
|
154
|
+
return this.clientY + window.screenY;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
58
157
|
});
|
|
158
|
+
} catch (err) {
|
|
159
|
+
console.error('Failed to setup mouse event handlers:', err.message);
|
|
160
|
+
// Non-critical, continue anyway
|
|
161
|
+
}
|
|
59
162
|
|
|
60
|
-
|
|
163
|
+
// Cursor setup with error handling
|
|
164
|
+
try {
|
|
165
|
+
const cursor = createCursor(page);
|
|
166
|
+
page.realCursor = cursor;
|
|
167
|
+
page.realClick = cursor.click;
|
|
168
|
+
} catch (err) {
|
|
169
|
+
console.error('Failed to create ghost cursor:', err.message);
|
|
170
|
+
// Non-critical, continue anyway
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return page;
|
|
174
|
+
}
|
|
61
175
|
|
|
62
|
-
|
|
63
|
-
page.realCursor = cursor
|
|
64
|
-
page.realClick = cursor.click
|
|
65
|
-
return page
|
|
66
|
-
}
|
|
176
|
+
export { pageController };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
const checkTurnstile = ({ page }) => {
|
|
2
2
|
return new Promise(async (resolve, reject) => {
|
|
3
3
|
var waitInterval = setTimeout(() => { clearInterval(waitInterval); resolve(false) }, 5000);
|
|
4
|
-
|
|
5
4
|
try {
|
|
6
5
|
const elements = await page.$$('[name="cf-turnstile-response"]');
|
|
7
6
|
if (elements.length <= 0) {
|
|
@@ -59,4 +58,6 @@ export const checkTurnstile = ({ page }) => {
|
|
|
59
58
|
resolve(false)
|
|
60
59
|
}
|
|
61
60
|
})
|
|
62
|
-
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { checkTurnstile };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brave-real-browser",
|
|
3
|
-
"version": "1.5.
|
|
3
|
+
"version": "1.5.97",
|
|
4
4
|
"description": "This package is designed to bypass puppeteer's bot-detecting captchas such as Cloudflare. It acts like a real browser and can be managed with puppeteer.",
|
|
5
5
|
"main": "lib/cjs/index.js",
|
|
6
6
|
"module": "lib/esm/index.mjs",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"brave-real-launcher": "latest",
|
|
42
42
|
"brave-real-puppeteer-core": "latest",
|
|
43
|
-
"ghost-cursor": "^1.4.1
|
|
43
|
+
"ghost-cursor": "^1.4.1",
|
|
44
44
|
"puppeteer-extra": "^3.3.6",
|
|
45
45
|
"tree-kill": "^1.2.2",
|
|
46
46
|
"xvfb": "^0.4.0"
|