nexus-fca 2.0.7 β 2.1.0
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/CHANGELOG.md +36 -0
- package/README.md +140 -280
- package/index.js +63 -29
- package/package.json +1 -1
- package/src/listenMqtt.js +23 -0
- package/utils.js +153 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.1.0] - 2025-08-20 - SESSION RELIABILITY & PROMISE LOGIN
|
|
4
|
+
### π Highlights
|
|
5
|
+
Stability-focused release improving longβrunning bot sessions, reducing false `not_logged_in` events, and modernizing the login flow.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- β
Promise support for `login()` (dual callback + Promise API)
|
|
9
|
+
- π Persistent device fingerprint (saved to `persistent-device.json`) to reduce checkpoint / lock frequency
|
|
10
|
+
- π‘οΈ New `validateSession()` multi-endpoint heuristic (lightweight, resilient preflight)
|
|
11
|
+
- βοΈ New global option: `disablePreflight` (skip session validation if desired)
|
|
12
|
+
- π Structured error types from `parseAndCheckLogin` (`login_redirect`, `html_login_page`, `network_redirect`, etc.)
|
|
13
|
+
- π§ͺ Example: `examples/echo-test.js` (Promise style, supports env credentials or appstate)
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- π `listenMqtt` now performs silent initial validation; only emits `not_logged_in` after a confirmatory retry
|
|
17
|
+
- π§ `parseAndCheckLogin` now robustly handles 3xx chains & HTML login fallback pages
|
|
18
|
+
- π Default behavior: device identity no longer rotates unless explicitly overridden
|
|
19
|
+
- π§© Refactored internal cookie & session utilities (centralized in `utils.js`)
|
|
20
|
+
- π Rewritten documentation (README, DOCS, CHANGELOG) for concise modern onboarding
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
- β Spurious `parseAndCheckLogin got status code: 302` fatal errors now classified & recovered when possible
|
|
24
|
+
- π€ False negatives from legacy preflight removed (no premature `not_logged_in` during transient redirects)
|
|
25
|
+
- π Edge reconnect loop where MQTT closed before revalidation completed
|
|
26
|
+
|
|
27
|
+
### Migration Notes (2.0.x β 2.1.0)
|
|
28
|
+
- Existing code using callbacks continues to work. To use Promises: `const api = await login(opts);`
|
|
29
|
+
- If you previously depended on device rotation, disable persistent device via option (see README) or delete `persistent-device.json`.
|
|
30
|
+
- Remove any custom preflight hacks; builtβin `validateSession` supersedes them.
|
|
31
|
+
|
|
32
|
+
### Developer / Internal
|
|
33
|
+
- Centralized session validation pipeline
|
|
34
|
+
- Added granular error classification to aid future retry/backoff strategies
|
|
35
|
+
- Prepared foundation for upcoming metrics hooks in 2.2.x
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
3
39
|
## [2.0.5] - 2025-07-29 - FULLY INTEGRATED NPM EDITION
|
|
4
40
|
### π― MAJOR: Full NPM Integration
|
|
5
41
|
- **β
FULLY INTEGRATED**: Entire Nexus Login System now embedded directly in main `index.js`
|
package/README.md
CHANGED
|
@@ -1,334 +1,194 @@
|
|
|
1
|
-
|
|
1
|
+
# Nexus-FCA v2.1.0
|
|
2
2
|
|
|
3
|
-
<
|
|
3
|
+
<p align="center">
|
|
4
|
+
<!-- Preview image wrapped in link (corrected ibb.co domain) -->
|
|
5
|
+
<a href="https://ibb.co/8ymR1tw"><img src="https://i.ibb.co/Sk61FGg/Dragon-Fruit-1.jpg" alt="Nexus-FCA Dragon Fruit" width="520" border="0" /></a>
|
|
6
|
+
</p>
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
# Nex## β οΈ## π¬ Community & Support
|
|
8
|
-
- **GitHub**: [github.com/Nexus-016/Nexus-fCA](https://github.com/Nexus-016/Nexus-fCA)
|
|
9
|
-
- **Docs**: See `/docs` for per-feature usage and safety guidelines
|
|
10
|
-
- **Safety Tips**: Always monitor your account status and use fresh appstate cookies
|
|
11
|
-
- **Contributions**: PRs and issues welcome! Safety improvements prioritized
|
|
8
|
+
> Advanced, safe, modern Facebook Chat (Messenger) API with integrated secure login (ID / Password / 2FA), ultraβlow ban rate session management, MQTT listener, and TypeScript-ready developer experience.
|
|
12
9
|
|
|
13
10
|
---
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
11
|
+
## β¨ Highlights
|
|
12
|
+
- π Integrated secure login system (username/password + TOTP 2FA) β auto appstate
|
|
13
|
+
- π‘οΈ Ultra-low ban rate design (human timing, safety limiter, risk heuristics)
|
|
14
|
+
- π Resilient MQTT listener (improved session validation + graceful reconnect)
|
|
15
|
+
- π Persistent device fingerprint (no random rotation β fewer checkpoints)
|
|
16
|
+
- π§ Smart session validation (multi-endpoint retry, reduced false logouts)
|
|
17
|
+
- βοΈ Zero-config appstate reuse & automatic backup/versioned snapshots
|
|
18
|
+
- π§© Modular architecture (safety, performance, error, mqtt managers)
|
|
19
|
+
- ποΈ Rich feature docs in `/docs` (thread, message, reactions, attachments)
|
|
20
|
+
- π§Ύ Type definitions (`index.d.ts`) & modern Promise / callback API
|
|
20
21
|
|
|
21
22
|
---
|
|
22
|
-
|
|
23
|
-
## β οΈ Important Disclaimer
|
|
24
|
-
Nexus-FCA is not affiliated with Facebook. This software is provided for educational and research purposes. Users are responsible for complying with Facebook's terms of service and local laws. The ultra-safe features are designed to minimize risks but cannot guarantee complete protection. Always use responsibly and monitor your account status regularly. Account Safety Notice
|
|
25
|
-
Nexus-FCA Maximum Safety Edition is specifically designed to minimize Facebook account ban, lock, checkpoint, and block rates. Our advanced safety system ensures your Facebook account remains secure during bot operations.
|
|
26
|
-
|
|
27
|
-
**Advanced Safety Protection:**
|
|
28
|
-
- β
Ultra-low ban rate protection (minimizes account suspension risk)
|
|
29
|
-
- β
Real-time lock and checkpoint detection with auto-shutdown
|
|
30
|
-
- β
Smart request patterns that mimic human behavior
|
|
31
|
-
- β
Advanced session management to prevent account flags
|
|
32
|
-
- β
Intelligent delay patterns for maximum account safety
|
|
33
|
-
- β
Enhanced error recovery without triggering Facebook security
|
|
34
|
-
|
|
35
|
-
Use responsibly and at your own risk. This package is not affiliated with Facebook.Nexus-FCA (2.0.0)
|
|
36
|
-
|
|
37
|
-
> **A next-generation, high-performance, developer-friendly Facebook Messenger bot framework.**
|
|
38
|
-
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
## π What's New in 2.0.3 - Fully Integrated NPM Edition
|
|
42
|
-
- **π― FULLY INTEGRATED**: Nexus Login System now built directly into main package!
|
|
43
|
-
- **οΏ½ NPM COMPATIBLE**: Works perfectly when installed via `npm install nexus-fca`
|
|
44
|
-
- **β‘ ZERO CONFIG**: No external folders needed - everything works out of the box
|
|
45
|
-
- **οΏ½π NEXUS LOGIN SYSTEM**: Revolutionary auto-login with appstate generation from username/password
|
|
46
|
-
- **π‘οΈ ULTRA-LOW BAN RATE**: Advanced protection reduces Facebook account suspension risk by 95%+
|
|
47
|
-
- **π 2FA SUPPORT**: Full TOTP integration with Google Authenticator for maximum security
|
|
48
|
-
- **β‘ ONE-LINE SETUP**: Complete bot setup with just one line of code
|
|
49
|
-
- **π INTELLIGENT MANAGEMENT**: Auto-backup, validation, and appstate lifecycle management
|
|
50
|
-
- **π‘οΈ MAXIMUM SAFETY**: Human-like device simulation with Android fingerprinting
|
|
51
|
-
- **π ENHANCED AUTO-RECONNECT**: Smart MQTT connection with safe reconnection patterns
|
|
52
|
-
|
|
53
|
-
## π― Integrated Nexus Login System
|
|
54
|
-
|
|
55
|
-
**The most advanced Facebook login system, now fully integrated for NPM usage!**
|
|
56
|
-
|
|
57
|
-
### οΏ½ **NPM Installation**
|
|
23
|
+
## π Install
|
|
58
24
|
```bash
|
|
59
25
|
npm install nexus-fca
|
|
60
26
|
```
|
|
61
27
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
// Complete bot ready in one line!
|
|
67
|
-
const result = await nexusLogin({
|
|
68
|
-
username: 'your_email@gmail.com',
|
|
69
|
-
password: 'your_password',
|
|
70
|
-
twofactor: 'YOUR_2FA_SECRET'
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
if (result.success) {
|
|
74
|
-
// Bot is ready! API available immediately
|
|
75
|
-
result.api.sendMessage('Hello World!', result.api.getCurrentUserID());
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### π **Smart Auto-Detection**
|
|
80
|
-
```javascript
|
|
81
|
-
// Will automatically:
|
|
82
|
-
// 1. Check for existing appstate
|
|
83
|
-
// 2. Use it if valid
|
|
84
|
-
// 3. Generate new one if needed
|
|
85
|
-
// 4. Start Nexus-FCA with ultra-safe settings
|
|
86
|
-
|
|
87
|
-
const result = await nexusLogin(); // No credentials needed if appstate exists!
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
### π‘οΈ **Maximum Safety Features**
|
|
91
|
-
- β
**Human-like Android simulation** with real device fingerprints
|
|
92
|
-
- β
**2FA TOTP auto-generation** from Google Authenticator secrets
|
|
93
|
-
- β
**Rate limiting & safety delays** to prevent Facebook detection
|
|
94
|
-
- β
**Automatic appstate backup** and lifecycle management
|
|
95
|
-
- β
**Session validation** and health monitoring
|
|
96
|
-
- β
**Error recovery** without triggering security flags
|
|
97
|
-
|
|
98
|
-
### π **Quick Start Guide**
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
2. **Create test file:**
|
|
103
|
-
```javascript
|
|
104
|
-
// test-bot.js
|
|
105
|
-
const { nexusLogin } = require('nexus-fca');
|
|
28
|
+
---
|
|
29
|
+
## β‘ Quick Start (Appstate)
|
|
30
|
+
```js
|
|
31
|
+
const login = require('nexus-fca');
|
|
106
32
|
|
|
107
33
|
(async () => {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
console.log('β
Bot ready!');
|
|
115
|
-
result.api.sendMessage('Hello from Nexus!', result.api.getCurrentUserID());
|
|
116
|
-
}
|
|
34
|
+
const api = await login({ appState: require('./appstate.json') });
|
|
35
|
+
console.log('Logged in as', api.getCurrentUserID());
|
|
36
|
+
api.listen((err, evt) => {
|
|
37
|
+
if (err) return console.error('Listen error:', err);
|
|
38
|
+
if (evt.body) api.sendMessage('Echo: ' + evt.body, evt.threadID);
|
|
39
|
+
});
|
|
117
40
|
})();
|
|
118
41
|
```
|
|
119
42
|
|
|
120
|
-
|
|
121
|
-
```
|
|
122
|
-
node test-bot.js
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### π **Complete Documentation**
|
|
126
|
-
- **[NPM Integration Guide](npm-integration-guide.md)** - Complete NPM usage guide
|
|
127
|
-
- **[Integrated Login Guide](integrated-login-guide.md)** - All login methods
|
|
128
|
-
- **[Test Files](test-*.js)** - Ready-to-use test scripts
|
|
129
|
-
- **[Legacy Guide](newloginhowtouse.md)** - Previous version docs
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
## π Legacy Appstate Support
|
|
134
|
-
|
|
135
|
-
Nexus-FCA maintains full backward compatibility with traditional appstate login.
|
|
136
|
-
|
|
137
|
-
### β‘ Traditional Usage
|
|
138
|
-
|
|
139
|
-
```javascript
|
|
43
|
+
## π Quick Start (Credentials + 2FA)
|
|
44
|
+
```js
|
|
140
45
|
const login = require('nexus-fca');
|
|
141
46
|
|
|
142
|
-
|
|
47
|
+
(async () => {
|
|
48
|
+
const api = await login({
|
|
49
|
+
email: process.env.FB_EMAIL,
|
|
50
|
+
password: process.env.FB_PASS,
|
|
51
|
+
twofactor: process.env.FB_2FA_SECRET // optional
|
|
52
|
+
});
|
|
53
|
+
api.listen((err, msg) => {
|
|
143
54
|
if (err) return console.error(err);
|
|
144
|
-
|
|
145
|
-
});
|
|
55
|
+
if (msg.body === 'ping') api.sendMessage('pong', msg.threadID);
|
|
56
|
+
});
|
|
57
|
+
})();
|
|
146
58
|
```
|
|
147
59
|
|
|
148
|
-
### π Migration Guide
|
|
149
|
-
|
|
150
|
-
- **Existing appstate files work unchanged**
|
|
151
|
-
- **New integrated system generates fresh appstate automatically**
|
|
152
|
-
- **Mix and match both approaches as needed**
|
|
153
|
-
|
|
154
60
|
---
|
|
61
|
+
## π‘οΈ Safety Layer (v2.1.0 Improvements)
|
|
62
|
+
| Feature | Benefit |
|
|
63
|
+
|---------|---------|
|
|
64
|
+
| Persistent device profile | Prevents repeated βnew deviceβ flags & locks |
|
|
65
|
+
| Smarter session preflight | Eliminates noisy false `not_logged_in` errors |
|
|
66
|
+
| Redirect & HTML detection | Accurate login checkpoint identification |
|
|
67
|
+
| Controlled retries (5xx) | Backoff without hammering endpoints |
|
|
68
|
+
| Human-like delays | Reduces automated pattern detection |
|
|
155
69
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
</div>
|
|
70
|
+
Disable preflight if needed:
|
|
71
|
+
```js
|
|
72
|
+
await login({ appState }, { disablePreflight: true });
|
|
73
|
+
```
|
|
161
74
|
|
|
162
75
|
---
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
-
|
|
166
|
-
-
|
|
167
|
-
- **οΏ½ Real-time Account Lock/Ban/Checkpoint Prevention**
|
|
168
|
-
- **π Advanced Safe MQTT Auto-Reconnect**
|
|
169
|
-
- **π Intelligent Safety-Focused Performance Optimization**
|
|
170
|
-
- **οΏ½οΈ Proactive Account Health Monitoring & Alerts**
|
|
171
|
-
- **π Safe Automatic Token Refresh & Session Management**
|
|
172
|
-
- **π Region Protection & Safe Connection Optimization**
|
|
173
|
-
- **π Professional Safety Analytics & Monitoring**
|
|
174
|
-
- **π» Full TypeScript Support & Modern APIs**
|
|
175
|
-
- **π§ Discord.js-style Objects & Event System**
|
|
176
|
-
- **π Comprehensive Safety Documentation & Migration Guides**
|
|
76
|
+
## π°οΈ MQTT Listener Enhancements
|
|
77
|
+
- Preflight now async & tolerant (second-stage check only logs failure)
|
|
78
|
+
- Classified errors: `login_redirect`, `html_login_page`, `not_logged_in`
|
|
79
|
+
- Automatic cookie/token refresh propagation
|
|
177
80
|
|
|
178
81
|
---
|
|
179
|
-
|
|
180
|
-
|
|
82
|
+
## π¦ Example Echo Test
|
|
83
|
+
`examples/echo-test.js` (already included):
|
|
181
84
|
```bash
|
|
182
|
-
|
|
85
|
+
node examples/echo-test.js
|
|
183
86
|
```
|
|
87
|
+
Provide `appstate.json` or set `EMAIL` / `PASSWORD` env variables.
|
|
184
88
|
|
|
185
89
|
---
|
|
90
|
+
## π§ Advanced Login Flow
|
|
91
|
+
1. New integrated system safely generates / refreshes cookies (if credentials supplied)
|
|
92
|
+
2. Legacy core consumes resulting appstate for stable API behavior
|
|
93
|
+
3. Optional persistent device JSON: `persistent-device.json`
|
|
186
94
|
|
|
187
|
-
|
|
95
|
+
Persistent device toggle:
|
|
188
96
|
```js
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
login({ appState: require("./appstate.json") }, (err, api) => {
|
|
192
|
-
if (err) return console.error("Login error:", err);
|
|
193
|
-
api.listenMqtt((err, event) => {
|
|
194
|
-
if (err) return console.error("Listen error:", err);
|
|
195
|
-
if (event.body && event.threadID) {
|
|
196
|
-
api.sendMessage("Echo: " + event.body, event.threadID);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
});
|
|
97
|
+
const { IntegratedNexusLoginSystem } = require('nexus-fca');
|
|
98
|
+
new IntegratedNexusLoginSystem({ persistentDevice: true });
|
|
200
99
|
```
|
|
201
100
|
|
|
202
101
|
---
|
|
102
|
+
## π Using Nexus-FCA with GoatBot V2
|
|
103
|
+
Nexus-FCA can act as a dropβin enhancement for the legacy fb-chat-api layer inside GoatBot V2.
|
|
203
104
|
|
|
204
|
-
|
|
105
|
+
### Option 1: Nonβinvasive (generate fresh appstate)
|
|
106
|
+
1. In a separate script, run Nexus-FCA credential login (with 2FA if needed):
|
|
205
107
|
```js
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
cachingEnabled: true,
|
|
214
|
-
autoReconnect: true,
|
|
215
|
-
logLevel: 'info'
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
client.on('ready', (api, userID) => {
|
|
219
|
-
console.log(`π‘οΈ Login successful with ultra-low ban rate protection!`);
|
|
220
|
-
console.log(`π€ User ID: ${userID}`);
|
|
221
|
-
console.log(`β‘ Smart safety system: ACTIVE`);
|
|
222
|
-
console.log(`οΏ½οΈ Account protection level: MAXIMUM`);
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
client.on('message', async (message) => {
|
|
226
|
-
if (message.body === 'ping') await message.reply('π Pong!');
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
// Enhanced safety event listeners
|
|
230
|
-
client.on('accountLocked', (details) => {
|
|
231
|
-
console.log('π¨ ACCOUNT LOCKED - Emergency shutdown initiated for safety');
|
|
232
|
-
process.exit(1);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
client.on('checkpointRequired', (details) => {
|
|
236
|
-
console.log('β οΈ CHECKPOINT REQUIRED - Manual verification needed');
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
client.on('riskLevelHigh', (details) => {
|
|
240
|
-
console.log('οΏ½ HIGH RISK DETECTED - Automatically applying safety measures');
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
client.login({ appState: require('./appstate.json') });
|
|
108
|
+
const login = require('nexus-fca');
|
|
109
|
+
(async () => {
|
|
110
|
+
const api = await login({ email: process.env.FB_EMAIL, password: process.env.FB_PASS, twofactor: process.env.FB_2FA });
|
|
111
|
+
const appState = api.getAppState();
|
|
112
|
+
require('fs').writeFileSync('./appstate.json', JSON.stringify(appState, null, 2));
|
|
113
|
+
console.log('Saved appstate.json');
|
|
114
|
+
})();
|
|
244
115
|
```
|
|
116
|
+
2. Configure GoatBot to use that `appstate.json` (no credential scraping needed).
|
|
117
|
+
3. Repeat only when session truly expires (persistent device reduces frequency).
|
|
245
118
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
-
|
|
255
|
-
|
|
256
|
-
|
|
119
|
+
### Option 2: Replace internal fb-chat-api
|
|
120
|
+
GoatBot has a local `fb-chat-api` folder. To leverage Nexus-FCA improvements globally:
|
|
121
|
+
1. Install Nexus-FCA inside GoatBot project:
|
|
122
|
+
```bash
|
|
123
|
+
npm install nexus-fca
|
|
124
|
+
```
|
|
125
|
+
2. Rename GoatBotβs original folder for backup:
|
|
126
|
+
```bash
|
|
127
|
+
mv fb-chat-api fb-chat-api.orig # (Windows: rename manually)
|
|
128
|
+
```
|
|
129
|
+
3. Create a shim folder `fb-chat-api/index.js` with:
|
|
130
|
+
```js
|
|
131
|
+
module.exports = require('nexus-fca');
|
|
132
|
+
```
|
|
133
|
+
4. Start GoatBot normally. All calls (`login`, `api.listen`, send methods) now use Nexus-FCA (Promise supported).
|
|
257
134
|
|
|
258
|
-
|
|
135
|
+
### Option 3: Direct require patch
|
|
136
|
+
Search GoatBot source for `require("fb-chat-api")` and change to `require("nexus-fca")`.
|
|
259
137
|
|
|
260
|
-
|
|
138
|
+
### Promise usage inside GoatBot scripts
|
|
139
|
+
Replace:
|
|
140
|
+
```js
|
|
141
|
+
fbapi(loginData, (err, api) => { ... });
|
|
142
|
+
```
|
|
143
|
+
with:
|
|
144
|
+
```js
|
|
145
|
+
const login = require('nexus-fca');
|
|
146
|
+
const api = await login(loginData); // supports { appState } or { email, password, twofactor }
|
|
147
|
+
```
|
|
261
148
|
|
|
262
|
-
|
|
149
|
+
### Recommended settings
|
|
150
|
+
- Keep `persistent-device.json` at project root so repeated restarts reuse the same fingerprint.
|
|
151
|
+
- If GoatBot already performs its own βlive cookie checkβ loops, you can set `{ disablePreflight: true }` to avoid duplicate validation.
|
|
152
|
+
- Handle reconnect events: listen for `error` and `listen` callbacks just like original; classified errors now have `error.type` (`login_redirect`, etc.).
|
|
263
153
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
154
|
+
### Minimal integration example
|
|
155
|
+
```js
|
|
156
|
+
const login = require('nexus-fca');
|
|
157
|
+
(async () => {
|
|
158
|
+
const api = await login({ appState: require('./appstate.json') });
|
|
159
|
+
api.listen(async (err, event) => {
|
|
160
|
+
if (err) return console.error('[Nexus-FCA]', err);
|
|
161
|
+
if (event.body === '!ping') api.sendMessage('pong', event.threadID);
|
|
162
|
+
});
|
|
163
|
+
})();
|
|
164
|
+
```
|
|
268
165
|
|
|
269
166
|
---
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
-
|
|
273
|
-
-
|
|
274
|
-
-
|
|
275
|
-
- **π¨ Proactive Safety Alerts**: Early warning system for potential account risks
|
|
276
|
-
- **π Advanced Session Management**: Secure token handling with automatic safety validation
|
|
277
|
-
- **π Region Protection**: Advanced techniques to safely bypass restrictions and improve connectivity
|
|
278
|
-
- **π Safety Analytics**: Real-time monitoring focused on minimizing ban/lock/checkpoint rates
|
|
279
|
-
- **π§ Intelligent Error Recovery**: Smart error handling that prioritizes account safety over speed
|
|
167
|
+
## π Documentation
|
|
168
|
+
- Full API reference: `DOCS.md`
|
|
169
|
+
- Per-feature guides: `/docs/*.md`
|
|
170
|
+
- Safety: `docs/account-safety.md`
|
|
171
|
+
- Examples: `/examples`
|
|
280
172
|
|
|
281
173
|
---
|
|
174
|
+
## π Updating from 2.0.x β 2.1.0
|
|
175
|
+
| Change | Action |
|
|
176
|
+
|--------|--------|
|
|
177
|
+
| Preflight errors | Noise reduced automatically |
|
|
178
|
+
| Device rotation | Now persistent by default |
|
|
179
|
+
| parseAndCheckLogin | Handles 3xx & HTML login responses |
|
|
180
|
+
| Session validation | New `validateSession` helper |
|
|
282
181
|
|
|
283
|
-
|
|
284
|
-
- **Full API Reference**: See [`DOCS.md`](./DOCS.md)
|
|
285
|
-
- **Safety Guide**: See [`docs/account-safety.md`](./docs/account-safety.md) for best practices
|
|
286
|
-
- **TypeScript Usage**: Complete types in [`index.d.ts`](./index.d.ts)
|
|
287
|
-
- **Performance & Error Handling**: See advanced sections in docs
|
|
182
|
+
No breaking API changes.
|
|
288
183
|
|
|
289
184
|
---
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- **Account Locked/Suspended**: Advanced safety system will detect and immediately stop operations, preventing further issues
|
|
293
|
-
- **Checkpoint Required**: Manual verification needed - check Facebook for security prompts while bot automatically pauses
|
|
294
|
-
- **Session Expired**: Update your `appstate.json` with fresh cookies from browser using recommended browser extensions
|
|
295
|
-
- **MQTT Connection Issues**: Intelligent auto-reconnect system handles temporary disconnections with human-like patterns
|
|
296
|
-
- **High Risk Level Detected**: System automatically applies enhanced safety measures and increases delays between actions
|
|
297
|
-
- **Performance Issues**: Smart safety delays ensure optimal balance between speed and account protection
|
|
298
|
-
- **Memory Issues**: Automatic cleanup and optimization prevent resource leaks while maintaining safety
|
|
299
|
-
- **Network Issues**: Enhanced retry logic with safety-first approach handles connectivity problems intelligently
|
|
185
|
+
## β οΈ Disclaimer
|
|
186
|
+
This project is not affiliated with Facebook. Use responsibly. You are solely responsible for compliance with platform terms and local laws.
|
|
300
187
|
|
|
301
188
|
---
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
### π Whatβs New?
|
|
306
|
-
- **Nexus Login System**: Fully integrated, advanced, and safe Facebook login system under `/nexloginsystem`.
|
|
307
|
-
- **ID/Password/2FA Login**: Now you can login directly with your Facebook username, password, and 2FA secret key (Google Authenticator supported).
|
|
308
|
-
- **Automatic Appstate Generation**: No need to manually extract cookiesβjust provide credentials and get a fresh, safe appstate automatically.
|
|
309
|
-
- **Seamless Bot Start**: After login, your bot starts instantly with the generated appstateβno manual steps needed.
|
|
310
|
-
- **Ultra-Safe Device Simulation**: Human-like Android device/user-agent simulation for maximum account safety.
|
|
311
|
-
- **Auto-Backup & Validation**: Appstate is auto-backed up and validated for every login.
|
|
312
|
-
- **Advanced Error Handling**: Smart retry, 2FA fallback, and detailed error messages.
|
|
313
|
-
- **Full Documentation**: See `/nexloginsystem/README.md` for usage, API, and safety tips.
|
|
314
|
-
- **Test File Included**: Test your login system easily with `/nexloginsystem/test-login.js`.
|
|
315
|
-
|
|
316
|
-
### β‘ Example Usage
|
|
317
|
-
```js
|
|
318
|
-
const { nexusLogin } = require('./nexloginsystem');
|
|
319
|
-
const result = await nexusLogin({
|
|
320
|
-
username: 'your_email@gmail.com',
|
|
321
|
-
password: 'your_password',
|
|
322
|
-
twofactor: 'YOUR_2FA_SECRET_KEY'
|
|
323
|
-
});
|
|
324
|
-
if (result.success) {
|
|
325
|
-
// Bot is ready! API available immediately
|
|
326
|
-
result.api.sendMessage('Hello World!', result.api.getCurrentUserID());
|
|
327
|
-
}
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
### π Learn More
|
|
331
|
-
- See `/nexloginsystem/README.md` for full API, advanced usage, and safety best practices.
|
|
332
|
-
- For 2FA setup, see the guide in the login system docs.
|
|
189
|
+
## π€ Contribute
|
|
190
|
+
PRs for safety, stability, perf, and updated GraphQL doc_ids welcome.
|
|
333
191
|
|
|
334
192
|
---
|
|
193
|
+
## π License
|
|
194
|
+
MIT Β© 2025 Nexus-FCA Contributors
|
package/index.js
CHANGED
|
@@ -380,37 +380,52 @@ class IntegratedNexusLoginSystem {
|
|
|
380
380
|
safeMode: options.safeMode !== false,
|
|
381
381
|
maxRetries: options.maxRetries || 3,
|
|
382
382
|
retryDelay: options.retryDelay || 5000,
|
|
383
|
+
// New: persistentDevice disables random device rotation
|
|
384
|
+
persistentDevice: options.persistentDevice !== false,
|
|
385
|
+
persistentDeviceFile: options.persistentDeviceFile || path.join(process.cwd(), 'persistent-device.json'),
|
|
383
386
|
...options
|
|
384
387
|
};
|
|
385
388
|
|
|
386
389
|
this.deviceCache = new Map();
|
|
387
390
|
this.loginAttempts = 0;
|
|
388
391
|
this.lastLoginTime = 0;
|
|
392
|
+
// New: load previously persisted device if any
|
|
393
|
+
this.fixedDeviceProfile = this.loadPersistentDevice();
|
|
389
394
|
|
|
390
395
|
this.ensureDirectories();
|
|
391
396
|
this.logger('Login system ready', 'π');
|
|
392
397
|
}
|
|
393
398
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
399
|
+
loadPersistentDevice() {
|
|
400
|
+
try {
|
|
401
|
+
if (!this.options.persistentDevice) return null;
|
|
402
|
+
if (fs.existsSync(this.options.persistentDeviceFile)) {
|
|
403
|
+
const raw = JSON.parse(fs.readFileSync(this.options.persistentDeviceFile, 'utf8'));
|
|
404
|
+
if (raw && raw.device && raw.deviceId && raw.familyDeviceId && raw.userAgent) {
|
|
405
|
+
this.logger('Loaded persistent device profile', 'π±');
|
|
406
|
+
return raw;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
} catch (e) {
|
|
410
|
+
this.logger('Failed to load persistent device: ' + e.message, 'β οΈ');
|
|
411
|
+
}
|
|
412
|
+
return null;
|
|
397
413
|
}
|
|
398
414
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
this.
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
if (!fs.existsSync(dir)) {
|
|
408
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
409
|
-
}
|
|
410
|
-
});
|
|
415
|
+
savePersistentDevice(profile) {
|
|
416
|
+
if (!this.options.persistentDevice) return;
|
|
417
|
+
try {
|
|
418
|
+
fs.writeFileSync(this.options.persistentDeviceFile, JSON.stringify(profile, null, 2));
|
|
419
|
+
this.logger('Saved persistent device profile', 'πΎ');
|
|
420
|
+
} catch (e) {
|
|
421
|
+
this.logger('Failed to save persistent device: ' + e.message, 'β οΈ');
|
|
422
|
+
}
|
|
411
423
|
}
|
|
412
424
|
|
|
413
425
|
getRandomDevice() {
|
|
426
|
+
if (this.fixedDeviceProfile) {
|
|
427
|
+
return this.fixedDeviceProfile; // reuse device
|
|
428
|
+
}
|
|
414
429
|
const devices = [
|
|
415
430
|
{ model: "Pixel 6", build: "SP2A.220505.002", sdk: "30", release: "11" },
|
|
416
431
|
{ model: "Pixel 5", build: "RQ3A.210805.001.A1", sdk: "30", release: "11" },
|
|
@@ -420,17 +435,21 @@ class IntegratedNexusLoginSystem {
|
|
|
420
435
|
{ model: "Pixel 7", build: "TD1A.220804.031", sdk: "33", release: "13" },
|
|
421
436
|
{ model: "Samsung Galaxy S22", build: "S901USQU2AVB3", sdk: "32", release: "12" }
|
|
422
437
|
];
|
|
423
|
-
|
|
424
438
|
const device = devices[Math.floor(Math.random() * devices.length)];
|
|
425
439
|
const deviceId = this.generateConsistentDeviceId(device);
|
|
426
|
-
|
|
427
|
-
return {
|
|
440
|
+
const profile = {
|
|
428
441
|
userAgent: `Dalvik/2.1.0 (Linux; U; Android ${device.release}; ${device.model} Build/${device.build})`,
|
|
429
442
|
device,
|
|
430
443
|
deviceId,
|
|
431
444
|
familyDeviceId: uuidv4(),
|
|
432
445
|
androidId: this.generateAndroidId()
|
|
433
446
|
};
|
|
447
|
+
// Persist first generated device if persistence enabled
|
|
448
|
+
if (this.options.persistentDevice && !this.fixedDeviceProfile) {
|
|
449
|
+
this.fixedDeviceProfile = profile;
|
|
450
|
+
this.savePersistentDevice(profile);
|
|
451
|
+
}
|
|
452
|
+
return profile;
|
|
434
453
|
}
|
|
435
454
|
|
|
436
455
|
generateConsistentDeviceId(device) {
|
|
@@ -640,9 +659,11 @@ class IntegratedNexusLoginSystem {
|
|
|
640
659
|
device_info: {
|
|
641
660
|
model: androidDevice.device.model,
|
|
642
661
|
user_agent: androidDevice.userAgent,
|
|
643
|
-
device_id: androidDevice.deviceId
|
|
662
|
+
device_id: androidDevice.deviceId,
|
|
663
|
+
family_device_id: androidDevice.familyDeviceId
|
|
644
664
|
},
|
|
645
|
-
generated_at: new Date().toISOString()
|
|
665
|
+
generated_at: new Date().toISOString(),
|
|
666
|
+
persistent_device: !!this.options.persistentDevice
|
|
646
667
|
};
|
|
647
668
|
|
|
648
669
|
this.saveAppstate(appstate, result);
|
|
@@ -972,6 +993,17 @@ async function login(loginData, options = {}, callback) {
|
|
|
972
993
|
callback = options;
|
|
973
994
|
options = {};
|
|
974
995
|
}
|
|
996
|
+
// Add promise wrapper when no callback supplied
|
|
997
|
+
let usePromise = false;
|
|
998
|
+
if (typeof callback !== 'function') {
|
|
999
|
+
usePromise = true;
|
|
1000
|
+
}
|
|
1001
|
+
const promise = usePromise ? new Promise((resolve, reject) => {
|
|
1002
|
+
callback = function (err, api) {
|
|
1003
|
+
if (err) return reject(err);
|
|
1004
|
+
resolve(api);
|
|
1005
|
+
};
|
|
1006
|
+
}) : null;
|
|
975
1007
|
|
|
976
1008
|
// Professional logging
|
|
977
1009
|
const mainLogger = {
|
|
@@ -1002,8 +1034,8 @@ async function login(loginData, options = {}, callback) {
|
|
|
1002
1034
|
|
|
1003
1035
|
if (!result.success || !result.appstate) {
|
|
1004
1036
|
mainLogger.error('β Authentication failed', result.message);
|
|
1005
|
-
if (callback)
|
|
1006
|
-
|
|
1037
|
+
if (callback) callback(new Error(result.message || 'Login failed'));
|
|
1038
|
+
return usePromise ? promise : undefined;
|
|
1007
1039
|
}
|
|
1008
1040
|
|
|
1009
1041
|
mainLogger.info('β
Session generated successfully');
|
|
@@ -1027,7 +1059,7 @@ async function login(loginData, options = {}, callback) {
|
|
|
1027
1059
|
...options
|
|
1028
1060
|
};
|
|
1029
1061
|
|
|
1030
|
-
|
|
1062
|
+
loginHelper(
|
|
1031
1063
|
result.appstate, // Use generated appstate
|
|
1032
1064
|
null, // No email for old system
|
|
1033
1065
|
null, // No password for old system
|
|
@@ -1035,23 +1067,24 @@ async function login(loginData, options = {}, callback) {
|
|
|
1035
1067
|
callback,
|
|
1036
1068
|
null
|
|
1037
1069
|
);
|
|
1070
|
+
return usePromise ? promise : undefined;
|
|
1038
1071
|
|
|
1039
1072
|
} catch (error) {
|
|
1040
1073
|
mainLogger.error('π₯ Login error', error.message);
|
|
1041
|
-
if (callback)
|
|
1042
|
-
|
|
1074
|
+
if (callback) callback(error);
|
|
1075
|
+
return usePromise ? promise : undefined;
|
|
1043
1076
|
}
|
|
1044
1077
|
} else {
|
|
1045
1078
|
// Appstate-only authentication (direct session authentication)
|
|
1046
1079
|
if (!loginData.appState && !loginData.appstate) {
|
|
1047
1080
|
const error = new Error('Username and password are required for login, or provide appState for session authentication.');
|
|
1048
1081
|
mainLogger.error('β No credentials provided', 'Either provide ID/password or appstate');
|
|
1049
|
-
if (callback)
|
|
1050
|
-
|
|
1082
|
+
if (callback) callback(error);
|
|
1083
|
+
return usePromise ? promise : undefined;
|
|
1051
1084
|
}
|
|
1052
1085
|
|
|
1053
1086
|
// Direct session authentication using appstate
|
|
1054
|
-
mainLogger.info('
|
|
1087
|
+
mainLogger.info('π Starting session authentication');
|
|
1055
1088
|
|
|
1056
1089
|
const globalOptions = {
|
|
1057
1090
|
selfListen: false,
|
|
@@ -1070,7 +1103,7 @@ async function login(loginData, options = {}, callback) {
|
|
|
1070
1103
|
...options
|
|
1071
1104
|
};
|
|
1072
1105
|
|
|
1073
|
-
|
|
1106
|
+
loginHelper(
|
|
1074
1107
|
loginData.appState || loginData.appstate,
|
|
1075
1108
|
null, // No email for appstate login
|
|
1076
1109
|
null, // No password for appstate login
|
|
@@ -1078,6 +1111,7 @@ async function login(loginData, options = {}, callback) {
|
|
|
1078
1111
|
callback,
|
|
1079
1112
|
null
|
|
1080
1113
|
);
|
|
1114
|
+
return usePromise ? promise : undefined;
|
|
1081
1115
|
}
|
|
1082
1116
|
}
|
|
1083
1117
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-fca",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A modern, safe, and advanced Facebook Chat API for Node.js with fully integrated Nexus Login System. NPM-ready with ID/password/2FA support, ultra-low ban rate protection, and zero external dependencies.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"repository": {
|
package/src/listenMqtt.js
CHANGED
|
@@ -128,6 +128,23 @@ function buildStream(options, WebSocket, Proxy) {
|
|
|
128
128
|
return Stream;
|
|
129
129
|
}
|
|
130
130
|
function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
131
|
+
// Improved preflight with option to disable
|
|
132
|
+
if (!ctx.globalOptions.disablePreflight) {
|
|
133
|
+
(async () => {
|
|
134
|
+
try {
|
|
135
|
+
await utils.validateSession(ctx, defaultFuncs, { retries: 2, delayMs: 1000 });
|
|
136
|
+
} catch (e) {
|
|
137
|
+
// Suppress first failure; only emit if still bad after short grace period
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
utils.validateSession(ctx, defaultFuncs, { retries: 0 }).catch(err2 => {
|
|
140
|
+
log.error("listenMqtt", "Session invalid after retry: Not logged in.");
|
|
141
|
+
ctx.loggedIn = false;
|
|
142
|
+
globalCallback({ type: "not_logged_in", error: "Session invalid (post-retry)." });
|
|
143
|
+
});
|
|
144
|
+
}, 2000);
|
|
145
|
+
}
|
|
146
|
+
})();
|
|
147
|
+
}
|
|
131
148
|
const chatOn = ctx.globalOptions.online;
|
|
132
149
|
const foreground = false;
|
|
133
150
|
const sessionID = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1;
|
|
@@ -218,6 +235,12 @@ function listenMqtt(defaultFuncs, api, ctx, globalCallback) {
|
|
|
218
235
|
mqttClient.on('error', function (err) {
|
|
219
236
|
log.error("listenMqtt", err);
|
|
220
237
|
mqttClient.end();
|
|
238
|
+
// classify redirect/login errors surfaced through upstream logic
|
|
239
|
+
const errMsg = (err && (err.error || err.message || "")).toString();
|
|
240
|
+
if (/not logged in|login_redirect|html_login_page/i.test(errMsg)) {
|
|
241
|
+
ctx.loggedIn = false;
|
|
242
|
+
return globalCallback({ type: "not_logged_in", error: errMsg });
|
|
243
|
+
}
|
|
221
244
|
if (ctx.globalOptions.autoReconnect) {
|
|
222
245
|
listenMqtt(defaultFuncs, api, ctx, globalCallback);
|
|
223
246
|
} else {
|
package/utils.js
CHANGED
|
@@ -989,6 +989,7 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount = 0, sourceCall) {
|
|
|
989
989
|
return function (data) {
|
|
990
990
|
return tryPromise(function () {
|
|
991
991
|
log.verbose("parseAndCheckLogin", data.body);
|
|
992
|
+
// --- Handle HTTP 5xx with bounded retry (existing logic) ---
|
|
992
993
|
if (data.statusCode >= 500 && data.statusCode < 600) {
|
|
993
994
|
if (retryCount >= 5) {
|
|
994
995
|
throw {
|
|
@@ -1016,6 +1017,34 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount = 0, sourceCall) {
|
|
|
1016
1017
|
)
|
|
1017
1018
|
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
|
|
1018
1019
|
}
|
|
1020
|
+
// --- New: Explicit 3xx redirect handling (302 login checkpoint, etc.) ---
|
|
1021
|
+
if (data.statusCode >= 300 && data.statusCode < 400) {
|
|
1022
|
+
const location = data.headers && (data.headers.location || data.headers.Location);
|
|
1023
|
+
if (!location) {
|
|
1024
|
+
throw {
|
|
1025
|
+
message: `Redirect (${data.statusCode}) without location header.`,
|
|
1026
|
+
statusCode: data.statusCode,
|
|
1027
|
+
res: data.body,
|
|
1028
|
+
error: "Redirect without location.",
|
|
1029
|
+
sourceCall
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
// Detect checkpoint/login redirects explicitly
|
|
1033
|
+
if (/checkpoint|login|recover/i.test(location)) {
|
|
1034
|
+
throw {
|
|
1035
|
+
message: `Redirected to login/checkpoint: ${location}`,
|
|
1036
|
+
statusCode: data.statusCode,
|
|
1037
|
+
location,
|
|
1038
|
+
error: "Not logged in.",
|
|
1039
|
+
type: "login_redirect",
|
|
1040
|
+
res: data.body,
|
|
1041
|
+
sourceCall
|
|
1042
|
+
};
|
|
1043
|
+
}
|
|
1044
|
+
log.warn("parseAndCheckLogin", `Following redirect -> ${location}`);
|
|
1045
|
+
return defaultFuncs.get(location, ctx.jar)
|
|
1046
|
+
.then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
|
|
1047
|
+
}
|
|
1019
1048
|
if (data.statusCode !== 200) {
|
|
1020
1049
|
throw {
|
|
1021
1050
|
message: `parseAndCheckLogin got status code: ${data.statusCode}.`,
|
|
@@ -1026,23 +1055,60 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount = 0, sourceCall) {
|
|
|
1026
1055
|
};
|
|
1027
1056
|
}
|
|
1028
1057
|
let res;
|
|
1058
|
+
let bodyText = data.body || "";
|
|
1059
|
+
// --- New: Detect full HTML (often login page) before JSON parse ---
|
|
1060
|
+
const looksLikeHTML = /<html[\s\S]*<\/html>/i.test(bodyText);
|
|
1061
|
+
if (looksLikeHTML && /login|checkpoint|password|m_faceweb|m\.facebook\.com\/login/i.test(bodyText)) {
|
|
1062
|
+
throw {
|
|
1063
|
+
message: "Received HTML login/checkpoint page instead of JSON (session likely invalid).",
|
|
1064
|
+
statusCode: data.statusCode,
|
|
1065
|
+
res: bodyText.slice(0, 5000),
|
|
1066
|
+
error: "Not logged in.",
|
|
1067
|
+
type: "html_login_page",
|
|
1068
|
+
sourceCall
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1029
1071
|
try {
|
|
1030
|
-
res = JSON.parse(makeParsable(
|
|
1072
|
+
res = JSON.parse(makeParsable(bodyText));
|
|
1031
1073
|
} catch (e) {
|
|
1032
|
-
|
|
1074
|
+
// Additional heuristic: if body has FB login form markers
|
|
1075
|
+
if (/login_form|checkpointSubmitButton|memorialized/i.test(bodyText)) {
|
|
1076
|
+
throw {
|
|
1077
|
+
message: "Facebook returned login/checkpoint HTML instead of JSON.",
|
|
1078
|
+
detail: e.message,
|
|
1079
|
+
res: bodyText.slice(0, 5000),
|
|
1080
|
+
error: "Not logged in.",
|
|
1081
|
+
type: "html_login_page_parse_fail",
|
|
1082
|
+
sourceCall
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
log.error("JSON parsing failed:", bodyText);
|
|
1033
1086
|
throw {
|
|
1034
1087
|
message: "Failed to parse JSON response.",
|
|
1035
1088
|
detail: e.message,
|
|
1036
|
-
res:
|
|
1089
|
+
res: bodyText.slice(0, 5000),
|
|
1037
1090
|
error: "JSON.parse error.",
|
|
1038
1091
|
sourceCall
|
|
1039
1092
|
};
|
|
1040
1093
|
}
|
|
1041
1094
|
if (res.redirect && data.request.method === "GET") {
|
|
1095
|
+
// New: classify redirect target
|
|
1096
|
+
if (/checkpoint|login/i.test(res.redirect)) {
|
|
1097
|
+
throw {
|
|
1098
|
+
message: `Redirected to login/checkpoint (JSON redirect): ${res.redirect}`,
|
|
1099
|
+
statusCode: data.statusCode,
|
|
1100
|
+
location: res.redirect,
|
|
1101
|
+
error: "Not logged in.",
|
|
1102
|
+
type: "login_redirect",
|
|
1103
|
+
res,
|
|
1104
|
+
sourceCall
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1042
1107
|
return defaultFuncs
|
|
1043
1108
|
.get(res.redirect, ctx.jar)
|
|
1044
1109
|
.then(parseAndCheckLogin(ctx, defaultFuncs, undefined, sourceCall));
|
|
1045
1110
|
}
|
|
1111
|
+
// --- Existing cookie & token handling logic (unchanged) ---
|
|
1046
1112
|
if (
|
|
1047
1113
|
res.jsmods?.require &&
|
|
1048
1114
|
Array.isArray(res.jsmods.require[0]) &&
|
|
@@ -1062,7 +1128,9 @@ function parseAndCheckLogin(ctx, defaultFuncs, retryCount = 0, sourceCall) {
|
|
|
1062
1128
|
}
|
|
1063
1129
|
}
|
|
1064
1130
|
}
|
|
1065
|
-
|
|
1131
|
+
// --- New: Detect common not-logged-in payload patterns ---
|
|
1132
|
+
if (res.error === 1357001 || res.error === 1357004 || res.errorSummary === "login required") {
|
|
1133
|
+
// 1357001 existing logic below triggers auto_login; keep classification
|
|
1066
1134
|
if (!ctx.auto_login) {
|
|
1067
1135
|
ctx.auto_login = true;
|
|
1068
1136
|
auto_login(success => {
|
|
@@ -1484,12 +1552,80 @@ const rateLimiter = {
|
|
|
1484
1552
|
}
|
|
1485
1553
|
};
|
|
1486
1554
|
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1555
|
+
// Add robust session validation utility used by listenMqtt
|
|
1556
|
+
async function validateSession(ctx, defaultFuncs, opts = {}) {
|
|
1557
|
+
const { retries = 0, delayMs = 750 } = opts || {};
|
|
1558
|
+
if (!ctx || !ctx.jar) {
|
|
1559
|
+
throw new CustomError({ message: 'No context/jar provided', type: 'not_logged_in' });
|
|
1560
|
+
}
|
|
1561
|
+
const cookies = ctx.jar.getCookies('https://www.facebook.com');
|
|
1562
|
+
const hasUser = cookies.some(c => (c.key || c.name) === 'c_user');
|
|
1563
|
+
if (!hasUser) {
|
|
1564
|
+
throw new CustomError({ message: 'Not logged in (missing c_user cookie)', type: 'not_logged_in' });
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
const endpoints = [
|
|
1568
|
+
'https://www.facebook.com/ajax/mercury/threadlist_info.php?client=mercury',
|
|
1569
|
+
'https://m.facebook.com/me'
|
|
1570
|
+
];
|
|
1571
|
+
|
|
1572
|
+
function isHtmlLoginPage(body) {
|
|
1573
|
+
if (!body || typeof body !== 'string') return false;
|
|
1574
|
+
if (body.length < 40) return false;
|
|
1575
|
+
const lowered = body.toLowerCase();
|
|
1576
|
+
return (
|
|
1577
|
+
(lowered.includes('login') && lowered.includes('password')) ||
|
|
1578
|
+
lowered.includes('m_login_email') ||
|
|
1579
|
+
lowered.includes('/login/device-based')
|
|
1580
|
+
);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
1584
|
+
let allPassed = true;
|
|
1585
|
+
for (const url of endpoints) {
|
|
1586
|
+
try {
|
|
1587
|
+
// Prefer provided defaultFuncs.get if available (applies defaults & fb_dtsg)
|
|
1588
|
+
const res = defaultFuncs && defaultFuncs.get
|
|
1589
|
+
? await defaultFuncs.get(url, ctx.jar, {})
|
|
1590
|
+
: await get(url, ctx.jar, null, ctx.globalOptions, ctx);
|
|
1591
|
+
|
|
1592
|
+
const status = res && res.statusCode;
|
|
1593
|
+
const body = res && res.body ? res.body.toString() : '';
|
|
1594
|
+
|
|
1595
|
+
if (status >= 300 && status < 400) {
|
|
1596
|
+
throw new CustomError({ message: 'Login redirect detected', type: 'login_redirect', statusCode: status });
|
|
1597
|
+
}
|
|
1598
|
+
if (status === 0 || status === undefined) {
|
|
1599
|
+
throw new CustomError({ message: 'No status code (network?)', type: 'network_error' });
|
|
1600
|
+
}
|
|
1601
|
+
if (status === 401 || status === 403) {
|
|
1602
|
+
throw new CustomError({ message: 'Unauthorized / forbidden', type: 'not_logged_in', statusCode: status });
|
|
1603
|
+
}
|
|
1604
|
+
if (isHtmlLoginPage(body)) {
|
|
1605
|
+
throw new CustomError({ message: 'HTML login page served', type: 'html_login_page' });
|
|
1606
|
+
}
|
|
1607
|
+
// Basic heuristic: body containing checkpoint indicators
|
|
1608
|
+
if (/checkpoint|review recent login/i.test(body)) {
|
|
1609
|
+
throw new CustomError({ message: 'Checkpoint required', type: 'checkpoint' });
|
|
1610
|
+
}
|
|
1611
|
+
} catch (err) {
|
|
1612
|
+
allPassed = false;
|
|
1613
|
+
if (attempt >= retries) {
|
|
1614
|
+
// Re-throw final classified error (ensure type present)
|
|
1615
|
+
if (err instanceof CustomError) throw err;
|
|
1616
|
+
throw new CustomError({ message: err.message || 'Session invalid', type: err.type || 'not_logged_in', original: err });
|
|
1617
|
+
}
|
|
1618
|
+
break; // break inner loop to retry endpoints
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
if (allPassed) return true;
|
|
1622
|
+
if (attempt < retries) await delay(delayMs);
|
|
1623
|
+
}
|
|
1624
|
+
// Fallback (should not reach)
|
|
1625
|
+
throw new CustomError({ message: 'Unknown session validation failure', type: 'not_logged_in' });
|
|
1626
|
+
}
|
|
1492
1627
|
|
|
1628
|
+
// Preserve earlier named exports while adding validateSession
|
|
1493
1629
|
module.exports = {
|
|
1494
1630
|
CustomError,
|
|
1495
1631
|
cleanHTML,
|
|
@@ -1537,5 +1673,12 @@ module.exports = {
|
|
|
1537
1673
|
setProxy,
|
|
1538
1674
|
checkLiveCookie,
|
|
1539
1675
|
getAccessFromBusiness,
|
|
1540
|
-
getFroms
|
|
1676
|
+
getFroms,
|
|
1677
|
+
validateSession,
|
|
1678
|
+
// Safety & rate limiting exports
|
|
1679
|
+
rateLimiter,
|
|
1680
|
+
smartSafetyLimiter,
|
|
1681
|
+
safeMode,
|
|
1682
|
+
ultraSafeMode,
|
|
1683
|
+
isUserAllowed
|
|
1541
1684
|
};
|