@vangbanlanhat/fca-unofficial 1.4.2
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/.gitattributes +2 -0
- package/.github/workflows/nodejs.yml +26 -0
- package/.github/workflows/npmpublish.yml +30 -0
- package/.travis.yml +6 -0
- package/CHANGELOG.md +2 -0
- package/DOCS.md +1932 -0
- package/LICENSE-MIT +21 -0
- package/README.md +198 -0
- package/jest.config.js +10 -0
- package/package.json +86 -0
- package/pnpm-workspace.yaml +3 -0
- package/src/actions/addExternalModule.js +34 -0
- package/src/actions/addUserToGroup.js +113 -0
- package/src/actions/changeAdminStatus.js +79 -0
- package/src/actions/changeArchivedStatus.js +55 -0
- package/src/actions/changeBio.js +77 -0
- package/src/actions/changeBlockedStatus.js +47 -0
- package/src/actions/changeGroupImage.js +129 -0
- package/src/actions/changeNickname.js +59 -0
- package/src/actions/changeThreadColor.js +71 -0
- package/src/actions/changeThreadEmoji.js +55 -0
- package/src/actions/createNewGroup.js +86 -0
- package/src/actions/createPoll.js +71 -0
- package/src/actions/deleteMessage.js +56 -0
- package/src/actions/deleteThread.js +56 -0
- package/src/actions/editMessage.js +81 -0
- package/src/actions/forwardAttachment.js +60 -0
- package/src/actions/getAvatarUser.js +77 -0
- package/src/actions/getCurrentUserID.js +11 -0
- package/src/actions/getEmojiUrl.js +37 -0
- package/src/actions/getFriendsList.js +84 -0
- package/src/actions/getMessage.js +833 -0
- package/src/actions/getRegion.js +11 -0
- package/src/actions/getThreadHistory.js +702 -0
- package/src/actions/getThreadHistoryDeprecated.js +93 -0
- package/src/actions/getThreadInfo.js +265 -0
- package/src/actions/getThreadInfoDeprecated.js +80 -0
- package/src/actions/getThreadList.js +274 -0
- package/src/actions/getThreadListDeprecated.js +91 -0
- package/src/actions/getThreadPictures.js +79 -0
- package/src/actions/getUserID.js +66 -0
- package/src/actions/getUserInfo.js +92 -0
- package/src/actions/handleFriendRequest.js +61 -0
- package/src/actions/handleMessageRequest.js +65 -0
- package/src/actions/httpGet.js +70 -0
- package/src/actions/httpPost.js +70 -0
- package/src/actions/index.js +69 -0
- package/src/actions/listenMqtt.js +818 -0
- package/src/actions/logout.js +136 -0
- package/src/actions/markAsDelivered.js +58 -0
- package/src/actions/markAsRead.js +92 -0
- package/src/actions/markAsReadAll.js +50 -0
- package/src/actions/markAsSeen.js +59 -0
- package/src/actions/muteThread.js +52 -0
- package/src/actions/pinMessage.js +86 -0
- package/src/actions/refreshFb_dtsg.js +89 -0
- package/src/actions/removeUserFromGroup.js +79 -0
- package/src/actions/resolvePhotoUrl.js +45 -0
- package/src/actions/searchForThread.js +53 -0
- package/src/actions/searchStickers.js +53 -0
- package/src/actions/sendMessage.js +490 -0
- package/src/actions/sendMessageMqtt.js +235 -0
- package/src/actions/sendTypingIndicator.js +59 -0
- package/src/actions/setMessageReaction.js +140 -0
- package/src/actions/setMessageReactionMqtt.js +72 -0
- package/src/actions/setPostReaction.js +76 -0
- package/src/actions/setTitle.js +86 -0
- package/src/actions/stopListenMqtt.js +63 -0
- package/src/actions/threadColors.js +57 -0
- package/src/actions/unfriend.js +52 -0
- package/src/actions/unsendMessage.js +61 -0
- package/src/index.js +659 -0
- package/src/service/uploadAttachment.js +318 -0
- package/src/utils/base-parts/auth.js +286 -0
- package/src/utils/base-parts/formatters.js +751 -0
- package/src/utils/base-parts/identity.js +169 -0
- package/src/utils/base-parts/network.js +159 -0
- package/src/utils/base-parts/parsing.js +53 -0
- package/src/utils/base-parts/type.js +9 -0
- package/src/utils/base.js +18 -0
- package/src/utils/defaults.js +10 -0
- package/src/utils/format-attachments.js +7 -0
- package/src/utils/format-core.js +8 -0
- package/src/utils/format-events.js +11 -0
- package/src/utils/format-messages.js +10 -0
- package/src/utils/format-presence.js +9 -0
- package/src/utils/format-threads.js +8 -0
- package/src/utils/formatters.js +18 -0
- package/src/utils/identity.js +12 -0
- package/src/utils/index.js +15 -0
- package/src/utils/network.js +12 -0
- package/src/utils/parsing.js +11 -0
- package/src/utils.js +3 -0
- package/test/config.env.example +30 -0
- package/test/data/shareAttach.js +146 -0
- package/test/data/something.mov +0 -0
- package/test/data/test.png +0 -0
- package/test/data/test.txt +7 -0
- package/test/example-appstate.txt +11 -0
- package/test/integration/actions.appstate.integration.test.js +233 -0
- package/test/integration/api.integration.test.js +387 -0
- package/test/integration/env-test-config.js +46 -0
- package/test/integration/login.appstate.integration.test.js +47 -0
- package/test/integration/page.integration.test.js +139 -0
- package/test/jest.setup.js +54 -0
- package/test/unit/actions/actions.basic.test.js +116 -0
- package/test/unit/actions/actions.registry.test.js +36 -0
- package/test/unit/index/index.test.js +109 -0
- package/test/unit/utils/base-parts/auth.test.js +92 -0
- package/test/unit/utils/base-parts/formatters.test.js +53 -0
- package/test/unit/utils/base-parts/identity.test.js +43 -0
- package/test/unit/utils/base-parts/parsing.test.js +38 -0
- package/test/unit/utils/base-parts/type.test.js +23 -0
- package/test/unit/utils/base.test.js +35 -0
- package/vangbanlanhat-fca-unofficial-1.4.2.tgz +0 -0
package/LICENSE-MIT
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Avery, Benjamin, David, Maude
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Unofficial Facebook Chat API
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
<a href="https://www.npmjs.com/package/fca-unofficial"><img alt="npm version" src="https://img.shields.io/npm/v/fca-unofficial.svg?style=flat-square"></a>
|
|
5
|
+
<img alt="version" src="https://img.shields.io/github/package-json/v/VangBanLaNhat/fca-unofficial?label=github&style=flat-square">
|
|
6
|
+
<a href="https://www.npmjs.com/package/fca-unofficial"><img src="https://img.shields.io/npm/dm/fca-unofficial.svg?style=flat-square" alt="npm downloads"></a>
|
|
7
|
+
<a href="https://github.com/prettier/prettier"><img alt="code style: prettier" src="https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square"></a>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
This project provides an unofficial API for automating Facebook chat and Messenger functionalities. Facebook has deprecated their XMPP chat interface, leaving emulating a browser as the only viable method for account automation.
|
|
11
|
+
|
|
12
|
+
This API simulates exact GET/POST requests and MQTT connections, tricking Facebook into thinking it's a legitimate browser session.
|
|
13
|
+
|
|
14
|
+
> **Disclaimer:** We are not responsible if your account gets banned for spammy activities (sending messages too quickly, spamming strangers, logging in/out rapidly). Be a responsible Facebook citizen. Use [Facebook Whitehat Accounts](https://www.facebook.com/whitehat/accounts/) for safe testing.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Documentation
|
|
19
|
+
|
|
20
|
+
For a comprehensive list of all available API methods, options, and parameters, please see the **[Full API Documentation (DOCS.md)](DOCS.md)**.
|
|
21
|
+
|
|
22
|
+
## Tech Stack
|
|
23
|
+
|
|
24
|
+
- **Language**: JavaScript (Node.js)
|
|
25
|
+
- **Real-time Protocol**: MQTT (`mqtt` package)
|
|
26
|
+
- **HTML Parsing**: `cheerio`
|
|
27
|
+
- **Networking**: Built-in HTTP/HTTPS + `https-proxy-agent`
|
|
28
|
+
- **Testing Framework**: Jest
|
|
29
|
+
|
|
30
|
+
## Prerequisites
|
|
31
|
+
|
|
32
|
+
- **Node.js**: v14.0.0 or higher
|
|
33
|
+
- **NPM or Yarn**: To install dependencies
|
|
34
|
+
- A valid Facebook account or a Facebook Whitehat Account for testing.
|
|
35
|
+
|
|
36
|
+
## Getting Started
|
|
37
|
+
|
|
38
|
+
### 1. Installation
|
|
39
|
+
|
|
40
|
+
Install the package via NPM:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install @VangBanLaNhat/fca-unofficial
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 2. Basic Echo Bot Example
|
|
47
|
+
|
|
48
|
+
Create an `index.js` file and add the following code to create a bot that echoes messages back to the sender:
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
const login = require("@VangBanLaNhat/fca-unofficial");
|
|
52
|
+
|
|
53
|
+
// Login using your Facebook credentials
|
|
54
|
+
login({email: "FB_EMAIL", password: "FB_PASSWORD"}, (err, api) => {
|
|
55
|
+
if(err) return console.error("Login failed:", err);
|
|
56
|
+
|
|
57
|
+
console.log("Bot successfully logged in!");
|
|
58
|
+
|
|
59
|
+
// Start listening for incoming messages
|
|
60
|
+
api.listen((err, message) => {
|
|
61
|
+
if(err) return console.error(err);
|
|
62
|
+
|
|
63
|
+
// Echo the message back to the same chat thread
|
|
64
|
+
api.sendMessage("Echo: " + message.body, message.threadID);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Run your bot:
|
|
70
|
+
```bash
|
|
71
|
+
node index.js
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Saving the Session (Avoiding Bans & Re-logins)
|
|
75
|
+
|
|
76
|
+
Logging in repeatedly with an email and password is a massive red flag for Facebook's anti-spam systems. **You must save and reuse your session (AppState).**
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
const fs = require("fs");
|
|
80
|
+
const login = require("@VangBanLaNhat/fca-unofficial");
|
|
81
|
+
|
|
82
|
+
// 1. Try to load an existing session
|
|
83
|
+
let appState = null;
|
|
84
|
+
try {
|
|
85
|
+
appState = JSON.parse(fs.readFileSync('appstate.json', 'utf8'));
|
|
86
|
+
} catch (e) {
|
|
87
|
+
console.log("No saved session found. Logging in with credentials...");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const credentials = appState
|
|
91
|
+
? { appState: appState }
|
|
92
|
+
: { email: "FB_EMAIL", password: "FB_PASSWORD" };
|
|
93
|
+
|
|
94
|
+
login(credentials, (err, api) => {
|
|
95
|
+
if(err) return console.error(err);
|
|
96
|
+
|
|
97
|
+
// 2. Save the session for the next run
|
|
98
|
+
fs.writeFileSync('appstate.json', JSON.stringify(api.getAppState()));
|
|
99
|
+
console.log("Logged in and session saved!");
|
|
100
|
+
|
|
101
|
+
// ... continue with your bot logic ...
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
*Alternative:* You can use browser extensions like [c3c-fbstate](https://github.com/lequanglam/c3c-fbstate) to manually extract your `fbstate.json` (appstate) directly from your browser.
|
|
106
|
+
|
|
107
|
+
## Architecture Overview
|
|
108
|
+
|
|
109
|
+
This library essentially functions as a headless Facebook web client.
|
|
110
|
+
|
|
111
|
+
### Request Lifecycle
|
|
112
|
+
1. **Login:** The library performs a sequence of GET/POST requests to Facebook's login endpoints, mimicking a real browser login to acquire authentication cookies (`c_user`, `xs`, etc.).
|
|
113
|
+
2. **Context Creation:** It builds an internal `ctx` (context) object containing your User ID, Client ID, and cookies.
|
|
114
|
+
3. **MQTT Connection:** It establishes an MQTT over WebSockets connection to Facebook's servers to receive real-time events (new messages, typing indicators, read receipts).
|
|
115
|
+
4. **Action Execution:** When you call an API method (like `sendMessage`), the library constructs the exact GraphQL or form-data HTTP request that the Messenger web app would send, and dispatches it.
|
|
116
|
+
|
|
117
|
+
### Core Directory Structure
|
|
118
|
+
|
|
119
|
+
```text
|
|
120
|
+
src/
|
|
121
|
+
├── index.js # Main entrypoint and API builder
|
|
122
|
+
├── actions/ # Contains all the individual API methods
|
|
123
|
+
│ ├── listenMqtt.js # Manages the real-time MQTT socket
|
|
124
|
+
│ ├── sendMessage.js# Handles message formatting and sending
|
|
125
|
+
│ └── ... # Other actions (reactions, unsending, etc.)
|
|
126
|
+
└── utils/ # Shared utilities
|
|
127
|
+
├── auth.js # Cookie formatting and session extraction
|
|
128
|
+
├── base.js # Core network request wrappers (get, post)
|
|
129
|
+
├── formatters.js # Parsers that turn raw FB payloads into clean JSON
|
|
130
|
+
└── identity.js # Generators for IDs, GUIDs, and timestamps
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Available Scripts
|
|
134
|
+
|
|
135
|
+
| Command | Description |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `npm run test` | Runs the full Jest test suite |
|
|
138
|
+
| `npm run test:unit` | Runs only unit tests |
|
|
139
|
+
| `npm run test:integration`| Runs integration tests (requires active config) |
|
|
140
|
+
| `npm run lint` | Runs ESLint to check for syntax/style issues |
|
|
141
|
+
| `npm run prettier` | Formats all code using Prettier |
|
|
142
|
+
|
|
143
|
+
## Testing
|
|
144
|
+
|
|
145
|
+
The project uses **Jest** for unit and integration testing.
|
|
146
|
+
|
|
147
|
+
To run the unit tests:
|
|
148
|
+
```bash
|
|
149
|
+
npm run test:unit
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
To run integration tests (which actually hit Facebook endpoints), you must first create a valid config:
|
|
153
|
+
1. Copy `example-config.json` to `test-config.json` inside the `test` directory.
|
|
154
|
+
2. Fill in your test account credentials or appState.
|
|
155
|
+
3. Run: `npm run test:integration`
|
|
156
|
+
|
|
157
|
+
## Deployment
|
|
158
|
+
|
|
159
|
+
Since this is a standard Node.js application, you can deploy your bot anywhere Node.js runs (VPS, Heroku, Render, AWS, Docker).
|
|
160
|
+
|
|
161
|
+
**Important Deployment Tips:**
|
|
162
|
+
1. **Do not commit `appstate.json` or passwords to Git.** Use environment variables for sensitive data.
|
|
163
|
+
2. **IP Changes:** If you deploy your bot to a cloud server in a different country, Facebook might temporarily lock the account due to a "Suspicious Login". You may need to log into the account manually and approve the new location.
|
|
164
|
+
|
|
165
|
+
## Troubleshooting
|
|
166
|
+
|
|
167
|
+
### 1. "Login failed" or getting prompted for a code
|
|
168
|
+
If you have Two-Factor Authentication (2FA) or Login Approvals enabled, you must handle the approval step. Read the specific guide on [handling login approvals](DOCS.md#login).
|
|
169
|
+
|
|
170
|
+
### 2. My account got locked/banned!
|
|
171
|
+
This happens if you send messages too fast or to people who are not your friends.
|
|
172
|
+
- Use `setTimeout` to add human-like delays.
|
|
173
|
+
- Always use cached sessions (`appState`) instead of logging in repeatedly.
|
|
174
|
+
- Use a throwaway account for development.
|
|
175
|
+
|
|
176
|
+
### 3. `sendMessage` isn't working when logged in as a Page
|
|
177
|
+
Facebook Pages cannot initiate conversations with users to prevent spam. Your bot can only reply to users who have messaged the Page first within the last 24 hours.
|
|
178
|
+
|
|
179
|
+
### 4. How do I stop the spammy console logs?
|
|
180
|
+
Pass a `logLevel` option when configuring the API:
|
|
181
|
+
```javascript
|
|
182
|
+
api.setOptions({
|
|
183
|
+
logLevel: "silent" // Options: "silly", "verbose", "info", "warn", "error", "silent"
|
|
184
|
+
});
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Projects using this API
|
|
190
|
+
|
|
191
|
+
- [c3c](https://github.com/lequanglam/c3c) - A bot that can be customizable using plugins. Support Facebook & Discord.
|
|
192
|
+
|
|
193
|
+
**Historical Projects (from the original `facebook-chat-api`):**
|
|
194
|
+
- [Messer](https://github.com/mjkaufer/Messer) - Command-line messaging for Facebook Messenger
|
|
195
|
+
- [messen](https://github.com/tomquirk/messen) - Rapidly build Facebook Messenger apps in Node.js
|
|
196
|
+
- [Concierge](https://github.com/concierge/Concierge) - Modular chat bot with a package manager
|
|
197
|
+
- [Botium](https://github.com/codeforequity-at/botium-core) - The Selenium for Chatbots
|
|
198
|
+
- [Miscord](https://github.com/Bjornskjald/miscord) - Facebook bridge for Discord.
|
package/jest.config.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vangbanlanhat/fca-unofficial",
|
|
3
|
+
"version": "1.4.2",
|
|
4
|
+
"main": "src/index.js",
|
|
5
|
+
"description": "A Facebook chat API that doesn't rely on XMPP. Will NOT be deprecated after April 30th 2015.",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "jest --runInBand --testPathIgnorePatterns=\"/test/integration/\"",
|
|
8
|
+
"test:unit": "jest --runInBand",
|
|
9
|
+
"test:integration": "jest --runInBand --testPathPattern=\"test/integration\"",
|
|
10
|
+
"lint": "eslint \"src/**/*.js\" && eslint --env jest \"test/**/*.js\"",
|
|
11
|
+
"prettier": "prettier \"src/**/*.js\" \"test/**/*.js\" --write"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/VangBanLaNhat/fca-unofficial"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"facebook",
|
|
19
|
+
"chat",
|
|
20
|
+
"api",
|
|
21
|
+
"fca"
|
|
22
|
+
],
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/VangBanLaNhat/fca-unofficial/issues"
|
|
25
|
+
},
|
|
26
|
+
"author": "Avery, David, Maude, Benjamin, UIRI, HerokeyVN",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"bluebird": "^2.11.0",
|
|
30
|
+
"cheerio": "^0.22.0",
|
|
31
|
+
"https-proxy-agent": "^4.0.0",
|
|
32
|
+
|
|
33
|
+
"mqtt": "^3.0.0",
|
|
34
|
+
"npmlog": "^1.2.1",
|
|
35
|
+
"request": "^2.88.2",
|
|
36
|
+
"websocket-stream": "^5.5.2"
|
|
37
|
+
},
|
|
38
|
+
"pnpm": {
|
|
39
|
+
"overrides": {
|
|
40
|
+
"request@2.88.2>form-data": "2.5.5"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"dotenv": "^16.6.1",
|
|
48
|
+
"eslint": "^7.32.0",
|
|
49
|
+
"jest": "^27.5.1",
|
|
50
|
+
"prettier": "^1.19.1"
|
|
51
|
+
},
|
|
52
|
+
"eslintConfig": {
|
|
53
|
+
"env": {
|
|
54
|
+
"es6": true,
|
|
55
|
+
"es2017": true,
|
|
56
|
+
"node": true
|
|
57
|
+
},
|
|
58
|
+
"extends": "eslint:recommended",
|
|
59
|
+
"parserOptions": {
|
|
60
|
+
"sourceType": "module"
|
|
61
|
+
},
|
|
62
|
+
"rules": {
|
|
63
|
+
"linebreak-style": [
|
|
64
|
+
"error",
|
|
65
|
+
"unix"
|
|
66
|
+
],
|
|
67
|
+
"semi": [
|
|
68
|
+
"error",
|
|
69
|
+
"always"
|
|
70
|
+
],
|
|
71
|
+
"no-unused-vars": [
|
|
72
|
+
1,
|
|
73
|
+
{
|
|
74
|
+
"argsIgnorePattern": "^_",
|
|
75
|
+
"varsIgnorePattern": "^_"
|
|
76
|
+
}
|
|
77
|
+
],
|
|
78
|
+
"no-empty": [
|
|
79
|
+
"error",
|
|
80
|
+
{
|
|
81
|
+
"allowEmptyCatch": true
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
|
|
5
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
6
|
+
return function addExternalModule(moduleObj, callback) {
|
|
7
|
+
var done = typeof callback === "function" ? callback : null;
|
|
8
|
+
|
|
9
|
+
if (utils.getType(moduleObj) == "Object") {
|
|
10
|
+
for (let apiName in moduleObj) {
|
|
11
|
+
if (
|
|
12
|
+
utils.getType(moduleObj[apiName]) == "Function" ||
|
|
13
|
+
utils.getType(moduleObj[apiName]) == "AsyncFunction"
|
|
14
|
+
) {
|
|
15
|
+
api[apiName] = moduleObj[apiName](defaultFuncs, api, ctx);
|
|
16
|
+
} else {
|
|
17
|
+
var err = new Error(`Item "${apiName}" in moduleObj must be a function, not ${utils.getType(moduleObj[apiName])}!`);
|
|
18
|
+
if (done) done(err);
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
var typeErr = new Error(`moduleObj must be an object, not ${utils.getType(moduleObj)}!`);
|
|
24
|
+
if (done) done(typeErr);
|
|
25
|
+
throw typeErr;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (done) {
|
|
29
|
+
done(null, true);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return true;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = require("../utils");
|
|
4
|
+
var log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
7
|
+
return function addUserToGroup(userID, threadID, callback) {
|
|
8
|
+
var resolveFunc = function(){};
|
|
9
|
+
var rejectFunc = function(){};
|
|
10
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (
|
|
16
|
+
!callback &&
|
|
17
|
+
(utils.getType(threadID) === "Function" ||
|
|
18
|
+
utils.getType(threadID) === "AsyncFunction")
|
|
19
|
+
) {
|
|
20
|
+
throw { error: "please pass a threadID as a second argument." };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!callback) {
|
|
24
|
+
callback = function(err) {
|
|
25
|
+
if (err) {
|
|
26
|
+
return rejectFunc(err);
|
|
27
|
+
}
|
|
28
|
+
resolveFunc();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (
|
|
33
|
+
utils.getType(threadID) !== "Number" &&
|
|
34
|
+
utils.getType(threadID) !== "String"
|
|
35
|
+
) {
|
|
36
|
+
throw {
|
|
37
|
+
error:
|
|
38
|
+
"ThreadID should be of type Number or String and not " +
|
|
39
|
+
utils.getType(threadID) +
|
|
40
|
+
"."
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (utils.getType(userID) !== "Array") {
|
|
45
|
+
userID = [userID];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var messageAndOTID = utils.generateOfflineThreadingID();
|
|
49
|
+
var form = {
|
|
50
|
+
client: "mercury",
|
|
51
|
+
action_type: "ma-type:log-message",
|
|
52
|
+
author: "fbid:" + ctx.userID,
|
|
53
|
+
thread_id: "",
|
|
54
|
+
timestamp: Date.now(),
|
|
55
|
+
timestamp_absolute: "Today",
|
|
56
|
+
timestamp_relative: utils.generateTimestampRelative(),
|
|
57
|
+
timestamp_time_passed: "0",
|
|
58
|
+
is_unread: false,
|
|
59
|
+
is_cleared: false,
|
|
60
|
+
is_forward: false,
|
|
61
|
+
is_filtered_content: false,
|
|
62
|
+
is_filtered_content_bh: false,
|
|
63
|
+
is_filtered_content_account: false,
|
|
64
|
+
is_spoof_warning: false,
|
|
65
|
+
source: "source:chat:web",
|
|
66
|
+
"source_tags[0]": "source:chat",
|
|
67
|
+
log_message_type: "log:subscribe",
|
|
68
|
+
status: "0",
|
|
69
|
+
offline_threading_id: messageAndOTID,
|
|
70
|
+
message_id: messageAndOTID,
|
|
71
|
+
threading_id: utils.generateThreadingID(ctx.clientID),
|
|
72
|
+
manual_retry_cnt: "0",
|
|
73
|
+
thread_fbid: threadID
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
for (var i = 0; i < userID.length; i++) {
|
|
77
|
+
if (
|
|
78
|
+
utils.getType(userID[i]) !== "Number" &&
|
|
79
|
+
utils.getType(userID[i]) !== "String"
|
|
80
|
+
) {
|
|
81
|
+
throw {
|
|
82
|
+
error:
|
|
83
|
+
"Elements of userID should be of type Number or String and not " +
|
|
84
|
+
utils.getType(userID[i]) +
|
|
85
|
+
"."
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
form["log_message_data[added_participants][" + i + "]"] =
|
|
90
|
+
"fbid:" + userID[i];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
defaultFuncs
|
|
94
|
+
.post("https://www.facebook.com/messaging/send/", ctx.jar, form)
|
|
95
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
96
|
+
.then(function(resData) {
|
|
97
|
+
if (!resData) {
|
|
98
|
+
throw { error: "Add to group failed." };
|
|
99
|
+
}
|
|
100
|
+
if (resData.error) {
|
|
101
|
+
throw resData;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return callback();
|
|
105
|
+
})
|
|
106
|
+
.catch(function(err) {
|
|
107
|
+
log.error("addUserToGroup", err);
|
|
108
|
+
return callback(err);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return returnPromise;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const utils = require("../utils");
|
|
4
|
+
const log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeAdminStatus(threadID, adminIDs, adminStatus, callback) {
|
|
8
|
+
if (utils.getType(threadID) !== "String") {
|
|
9
|
+
throw {error: "changeAdminStatus: threadID must be a string"};
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (utils.getType(adminIDs) === "String") {
|
|
13
|
+
adminIDs = [adminIDs];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (utils.getType(adminIDs) !== "Array") {
|
|
17
|
+
throw {error: "changeAdminStatus: adminIDs must be an array or string"};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (utils.getType(adminStatus) !== "Boolean") {
|
|
21
|
+
throw {error: "changeAdminStatus: adminStatus must be a string"};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var resolveFunc = function(){};
|
|
25
|
+
var rejectFunc = function(){};
|
|
26
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
27
|
+
resolveFunc = resolve;
|
|
28
|
+
rejectFunc = reject;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (!callback) {
|
|
32
|
+
callback = function (err) {
|
|
33
|
+
if (err) {
|
|
34
|
+
return rejectFunc(err);
|
|
35
|
+
}
|
|
36
|
+
resolveFunc();
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (utils.getType(callback) !== "Function" && utils.getType(callback) !== "AsyncFunction") {
|
|
41
|
+
throw {error: "changeAdminStatus: callback is not a function"};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let form = {
|
|
45
|
+
"thread_fbid": threadID,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
let i = 0;
|
|
49
|
+
for (let u of adminIDs) {
|
|
50
|
+
form[`admin_ids[${i++}]`] = u;
|
|
51
|
+
}
|
|
52
|
+
form["add"] = adminStatus;
|
|
53
|
+
|
|
54
|
+
defaultFuncs
|
|
55
|
+
.post("https://www.facebook.com/messaging/save_admins/?dpr=1", ctx.jar, form)
|
|
56
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
57
|
+
.then(function(resData) {
|
|
58
|
+
if (resData.error) {
|
|
59
|
+
switch (resData.error) {
|
|
60
|
+
case 1976004:
|
|
61
|
+
throw { error: "Cannot alter admin status: you are not an admin.", rawResponse: resData };
|
|
62
|
+
case 1357031:
|
|
63
|
+
throw { error: "Cannot alter admin status: this thread is not a group chat.", rawResponse: resData };
|
|
64
|
+
default:
|
|
65
|
+
throw { error: "Cannot alter admin status: unknown error.", rawResponse: resData };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
callback();
|
|
70
|
+
})
|
|
71
|
+
.catch(function(err) {
|
|
72
|
+
log.error("changeAdminStatus", err);
|
|
73
|
+
return callback(err);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
return returnPromise;
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = require("../utils");
|
|
4
|
+
var log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function(defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeArchivedStatus(threadOrThreads, archive, callback) {
|
|
8
|
+
var resolveFunc = function(){};
|
|
9
|
+
var rejectFunc = function(){};
|
|
10
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (!callback) {
|
|
16
|
+
callback = function(err) {
|
|
17
|
+
if (err) {
|
|
18
|
+
return rejectFunc(err);
|
|
19
|
+
}
|
|
20
|
+
resolveFunc();
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
var form = {};
|
|
25
|
+
|
|
26
|
+
if (utils.getType(threadOrThreads) === "Array") {
|
|
27
|
+
for (var i = 0; i < threadOrThreads.length; i++) {
|
|
28
|
+
form["ids[" + threadOrThreads[i] + "]"] = archive;
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
form["ids[" + threadOrThreads + "]"] = archive;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
defaultFuncs
|
|
35
|
+
.post(
|
|
36
|
+
"https://www.facebook.com/ajax/mercury/change_archived_status.php",
|
|
37
|
+
ctx.jar,
|
|
38
|
+
form
|
|
39
|
+
)
|
|
40
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
41
|
+
.then(function(resData) {
|
|
42
|
+
if (resData.error) {
|
|
43
|
+
throw resData;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return callback();
|
|
47
|
+
})
|
|
48
|
+
.catch(function(err) {
|
|
49
|
+
log.error("changeArchivedStatus", err);
|
|
50
|
+
return callback(err);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
return returnPromise;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var utils = require("../utils");
|
|
4
|
+
var log = require("npmlog");
|
|
5
|
+
|
|
6
|
+
module.exports = function (defaultFuncs, api, ctx) {
|
|
7
|
+
return function changeBio(bio, publish, callback) {
|
|
8
|
+
var resolveFunc = function () { };
|
|
9
|
+
var rejectFunc = function () { };
|
|
10
|
+
var returnPromise = new Promise(function (resolve, reject) {
|
|
11
|
+
resolveFunc = resolve;
|
|
12
|
+
rejectFunc = reject;
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
if (!callback) {
|
|
16
|
+
if (utils.getType(publish) == "Function" || utils.getType(publish) == "AsyncFunction") {
|
|
17
|
+
callback = publish;
|
|
18
|
+
} else {
|
|
19
|
+
callback = function (err) {
|
|
20
|
+
if (err) {
|
|
21
|
+
return rejectFunc(err);
|
|
22
|
+
}
|
|
23
|
+
resolveFunc();
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (utils.getType(publish) != "Boolean") {
|
|
29
|
+
publish = false;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (utils.getType(bio) != "String") {
|
|
33
|
+
bio = "";
|
|
34
|
+
publish = false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var form = {
|
|
38
|
+
fb_api_caller_class: "RelayModern",
|
|
39
|
+
fb_api_req_friendly_name: "ProfileCometSetBioMutation",
|
|
40
|
+
// This doc_is is valid as of May 23, 2020
|
|
41
|
+
doc_id: "2725043627607610",
|
|
42
|
+
variables: JSON.stringify({
|
|
43
|
+
input: {
|
|
44
|
+
bio: bio,
|
|
45
|
+
publish_bio_feed_story: publish,
|
|
46
|
+
actor_id: ctx.userID,
|
|
47
|
+
client_mutation_id: Math.round(Math.random() * 1024).toString()
|
|
48
|
+
},
|
|
49
|
+
hasProfileTileViewID: false,
|
|
50
|
+
profileTileViewID: null,
|
|
51
|
+
scale: 1
|
|
52
|
+
}),
|
|
53
|
+
av: ctx.userID
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
defaultFuncs
|
|
57
|
+
.post(
|
|
58
|
+
"https://www.facebook.com/api/graphql/",
|
|
59
|
+
ctx.jar,
|
|
60
|
+
form
|
|
61
|
+
)
|
|
62
|
+
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
|
|
63
|
+
.then(function (resData) {
|
|
64
|
+
if (resData.errors) {
|
|
65
|
+
throw resData;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return callback();
|
|
69
|
+
})
|
|
70
|
+
.catch(function (err) {
|
|
71
|
+
log.error("changeBio", err);
|
|
72
|
+
return callback(err);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
return returnPromise;
|
|
76
|
+
};
|
|
77
|
+
};
|