@another-trial/whatsapp-web.js 1.34.1 → 1.35.0-alpha.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/.env.example +2 -2
- package/CODE_OF_CONDUCT.md +133 -133
- package/LICENSE +201 -201
- package/README.md +155 -185
- package/example.js +699 -690
- package/index.d.ts +2248 -2202
- package/index.js +35 -35
- package/package.json +59 -59
- package/shell.js +36 -36
- package/src/Client.js +2447 -2361
- package/src/authStrategies/BaseAuthStrategy.js +26 -26
- package/src/authStrategies/LocalAuth.js +58 -58
- package/src/authStrategies/NoAuth.js +11 -11
- package/src/authStrategies/RemoteAuth.js +210 -210
- package/src/factories/ChatFactory.js +21 -21
- package/src/factories/ContactFactory.js +15 -15
- package/src/structures/Base.js +21 -21
- package/src/structures/Broadcast.js +69 -69
- package/src/structures/BusinessContact.js +20 -20
- package/src/structures/Buttons.js +81 -81
- package/src/structures/Call.js +75 -75
- package/src/structures/Channel.js +382 -382
- package/src/structures/Chat.js +329 -299
- package/src/structures/ClientInfo.js +70 -70
- package/src/structures/Contact.js +208 -208
- package/src/structures/GroupChat.js +485 -485
- package/src/structures/GroupNotification.js +104 -104
- package/src/structures/Label.js +49 -49
- package/src/structures/List.js +79 -79
- package/src/structures/Location.js +61 -61
- package/src/structures/Message.js +780 -747
- package/src/structures/MessageMedia.js +111 -111
- package/src/structures/Order.js +51 -51
- package/src/structures/Payment.js +79 -79
- package/src/structures/Poll.js +44 -44
- package/src/structures/PollVote.js +75 -75
- package/src/structures/PrivateChat.js +12 -12
- package/src/structures/PrivateContact.js +12 -12
- package/src/structures/Product.js +67 -67
- package/src/structures/ProductMetadata.js +24 -24
- package/src/structures/Reaction.js +68 -68
- package/src/structures/ScheduledEvent.js +71 -71
- package/src/structures/index.js +27 -27
- package/src/util/Constants.js +186 -183
- package/src/util/Injected/AuthStore/AuthStore.js +16 -16
- package/src/util/Injected/AuthStore/LegacyAuthStore.js +21 -21
- package/src/util/Injected/LegacyStore.js +145 -145
- package/src/util/Injected/Store.js +257 -233
- package/src/util/Injected/Utils.js +1168 -1169
- package/src/util/InterfaceController.js +126 -126
- package/src/util/Puppeteer.js +23 -23
- package/src/util/Util.js +186 -186
- package/src/webCache/LocalWebCache.js +40 -40
- package/src/webCache/RemoteWebCache.js +39 -39
- package/src/webCache/WebCache.js +13 -13
- package/src/webCache/WebCacheFactory.js +19 -19
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Base class which all authentication strategies extend
|
|
5
|
-
*/
|
|
6
|
-
class BaseAuthStrategy {
|
|
7
|
-
constructor() {}
|
|
8
|
-
setup(client) {
|
|
9
|
-
this.client = client;
|
|
10
|
-
}
|
|
11
|
-
async beforeBrowserInitialized() {}
|
|
12
|
-
async afterBrowserInitialized() {}
|
|
13
|
-
async onAuthenticationNeeded() {
|
|
14
|
-
return {
|
|
15
|
-
failed: false,
|
|
16
|
-
restart: false,
|
|
17
|
-
failureEventPayload: undefined
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
async getAuthEventPayload() {}
|
|
21
|
-
async afterAuthReady() {}
|
|
22
|
-
async disconnect() {}
|
|
23
|
-
async destroy() {}
|
|
24
|
-
async logout() {}
|
|
25
|
-
}
|
|
26
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Base class which all authentication strategies extend
|
|
5
|
+
*/
|
|
6
|
+
class BaseAuthStrategy {
|
|
7
|
+
constructor() {}
|
|
8
|
+
setup(client) {
|
|
9
|
+
this.client = client;
|
|
10
|
+
}
|
|
11
|
+
async beforeBrowserInitialized() {}
|
|
12
|
+
async afterBrowserInitialized() {}
|
|
13
|
+
async onAuthenticationNeeded() {
|
|
14
|
+
return {
|
|
15
|
+
failed: false,
|
|
16
|
+
restart: false,
|
|
17
|
+
failureEventPayload: undefined
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
async getAuthEventPayload() {}
|
|
21
|
+
async afterAuthReady() {}
|
|
22
|
+
async disconnect() {}
|
|
23
|
+
async destroy() {}
|
|
24
|
+
async logout() {}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
27
|
module.exports = BaseAuthStrategy;
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const path = require('path');
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Local directory-based authentication
|
|
9
|
-
* @param {object} options - options
|
|
10
|
-
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
|
11
|
-
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
|
12
|
-
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
|
13
|
-
*/
|
|
14
|
-
class LocalAuth extends BaseAuthStrategy {
|
|
15
|
-
constructor({ clientId, dataPath, rmMaxRetries }={}) {
|
|
16
|
-
super();
|
|
17
|
-
|
|
18
|
-
const idRegex = /^[-_\w]+$/i;
|
|
19
|
-
if(clientId && !idRegex.test(clientId)) {
|
|
20
|
-
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
|
24
|
-
this.clientId = clientId;
|
|
25
|
-
this.rmMaxRetries = rmMaxRetries ?? 4;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
async beforeBrowserInitialized() {
|
|
29
|
-
const puppeteerOpts = this.client.options.puppeteer;
|
|
30
|
-
const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
|
|
31
|
-
const dirPath = path.join(this.dataPath, sessionDirName);
|
|
32
|
-
|
|
33
|
-
if(puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
|
34
|
-
throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
fs.mkdirSync(dirPath, { recursive: true });
|
|
38
|
-
|
|
39
|
-
this.client.options.puppeteer = {
|
|
40
|
-
...puppeteerOpts,
|
|
41
|
-
userDataDir: dirPath
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
this.userDataDir = dirPath;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async logout() {
|
|
48
|
-
if (this.userDataDir) {
|
|
49
|
-
await fs.promises.rm(this.userDataDir, { recursive: true, force: true, maxRetries: this.rmMaxRetries })
|
|
50
|
-
.catch((e) => {
|
|
51
|
-
throw new Error(e);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = LocalAuth;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Local directory-based authentication
|
|
9
|
+
* @param {object} options - options
|
|
10
|
+
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
|
11
|
+
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
|
12
|
+
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
|
13
|
+
*/
|
|
14
|
+
class LocalAuth extends BaseAuthStrategy {
|
|
15
|
+
constructor({ clientId, dataPath, rmMaxRetries }={}) {
|
|
16
|
+
super();
|
|
17
|
+
|
|
18
|
+
const idRegex = /^[-_\w]+$/i;
|
|
19
|
+
if(clientId && !idRegex.test(clientId)) {
|
|
20
|
+
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
|
24
|
+
this.clientId = clientId;
|
|
25
|
+
this.rmMaxRetries = rmMaxRetries ?? 4;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async beforeBrowserInitialized() {
|
|
29
|
+
const puppeteerOpts = this.client.options.puppeteer;
|
|
30
|
+
const sessionDirName = this.clientId ? `session-${this.clientId}` : 'session';
|
|
31
|
+
const dirPath = path.join(this.dataPath, sessionDirName);
|
|
32
|
+
|
|
33
|
+
if(puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
|
34
|
+
throw new Error('LocalAuth is not compatible with a user-supplied userDataDir.');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
38
|
+
|
|
39
|
+
this.client.options.puppeteer = {
|
|
40
|
+
...puppeteerOpts,
|
|
41
|
+
userDataDir: dirPath
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
this.userDataDir = dirPath;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async logout() {
|
|
48
|
+
if (this.userDataDir) {
|
|
49
|
+
await fs.promises.rm(this.userDataDir, { recursive: true, force: true, maxRetries: this.rmMaxRetries })
|
|
50
|
+
.catch((e) => {
|
|
51
|
+
throw new Error(e);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = LocalAuth;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* No session restoring functionality
|
|
7
|
-
* Will need to authenticate via QR code every time
|
|
8
|
-
*/
|
|
9
|
-
class NoAuth extends BaseAuthStrategy { }
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* No session restoring functionality
|
|
7
|
+
* Will need to authenticate via QR code every time
|
|
8
|
+
*/
|
|
9
|
+
class NoAuth extends BaseAuthStrategy { }
|
|
10
|
+
|
|
11
|
+
|
|
12
12
|
module.exports = NoAuth;
|
|
@@ -1,210 +1,210 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/* Require Optional Dependencies */
|
|
4
|
-
try {
|
|
5
|
-
var fs = require('fs-extra');
|
|
6
|
-
var unzipper = require('unzipper');
|
|
7
|
-
var archiver = require('archiver');
|
|
8
|
-
} catch {
|
|
9
|
-
fs = undefined;
|
|
10
|
-
unzipper = undefined;
|
|
11
|
-
archiver = undefined;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const path = require('path');
|
|
15
|
-
const { Events } = require('./../util/Constants');
|
|
16
|
-
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Remote-based authentication
|
|
20
|
-
* @param {object} options - options
|
|
21
|
-
* @param {object} options.store - Remote database store instance
|
|
22
|
-
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
|
23
|
-
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
|
24
|
-
* @param {number} options.backupSyncIntervalMs - Sets the time interval for periodic session backups. Accepts values starting from 60000ms {1 minute}
|
|
25
|
-
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
|
26
|
-
*/
|
|
27
|
-
class RemoteAuth extends BaseAuthStrategy {
|
|
28
|
-
constructor({ clientId, dataPath, store, backupSyncIntervalMs, rmMaxRetries } = {}) {
|
|
29
|
-
if (!fs && !unzipper && !archiver) throw new Error('Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag');
|
|
30
|
-
super();
|
|
31
|
-
|
|
32
|
-
const idRegex = /^[-_\w]+$/i;
|
|
33
|
-
if (clientId && !idRegex.test(clientId)) {
|
|
34
|
-
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
|
35
|
-
}
|
|
36
|
-
if (!backupSyncIntervalMs || backupSyncIntervalMs < 60000) {
|
|
37
|
-
throw new Error('Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.');
|
|
38
|
-
}
|
|
39
|
-
if(!store) throw new Error('Remote database store is required.');
|
|
40
|
-
|
|
41
|
-
this.store = store;
|
|
42
|
-
this.clientId = clientId;
|
|
43
|
-
this.backupSyncIntervalMs = backupSyncIntervalMs;
|
|
44
|
-
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
|
45
|
-
this.tempDir = `${this.dataPath}/wwebjs_temp_session_${this.clientId}`;
|
|
46
|
-
this.requiredDirs = ['Default', 'IndexedDB', 'Local Storage']; /* => Required Files & Dirs in WWebJS to restore session */
|
|
47
|
-
this.rmMaxRetries = rmMaxRetries ?? 4;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async beforeBrowserInitialized() {
|
|
51
|
-
const puppeteerOpts = this.client.options.puppeteer;
|
|
52
|
-
const sessionDirName = this.clientId ? `RemoteAuth-${this.clientId}` : 'RemoteAuth';
|
|
53
|
-
const dirPath = path.join(this.dataPath, sessionDirName);
|
|
54
|
-
|
|
55
|
-
if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
|
56
|
-
throw new Error('RemoteAuth is not compatible with a user-supplied userDataDir.');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
this.userDataDir = dirPath;
|
|
60
|
-
this.sessionName = sessionDirName;
|
|
61
|
-
|
|
62
|
-
await this.extractRemoteSession();
|
|
63
|
-
|
|
64
|
-
this.client.options.puppeteer = {
|
|
65
|
-
...puppeteerOpts,
|
|
66
|
-
userDataDir: dirPath
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async logout() {
|
|
71
|
-
await this.disconnect();
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
async destroy() {
|
|
75
|
-
clearInterval(this.backupSync);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
async disconnect() {
|
|
79
|
-
await this.deleteRemoteSession();
|
|
80
|
-
|
|
81
|
-
let pathExists = await this.isValidPath(this.userDataDir);
|
|
82
|
-
if (pathExists) {
|
|
83
|
-
await fs.promises.rm(this.userDataDir, {
|
|
84
|
-
recursive: true,
|
|
85
|
-
force: true,
|
|
86
|
-
maxRetries: this.rmMaxRetries,
|
|
87
|
-
}).catch(() => {});
|
|
88
|
-
}
|
|
89
|
-
clearInterval(this.backupSync);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
async afterAuthReady() {
|
|
93
|
-
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
|
94
|
-
if(!sessionExists) {
|
|
95
|
-
await this.delay(60000); /* Initial delay sync required for session to be stable enough to recover */
|
|
96
|
-
await this.storeRemoteSession({emit: true});
|
|
97
|
-
}
|
|
98
|
-
var self = this;
|
|
99
|
-
this.backupSync = setInterval(async function () {
|
|
100
|
-
await self.storeRemoteSession();
|
|
101
|
-
}, this.backupSyncIntervalMs);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async storeRemoteSession(options) {
|
|
105
|
-
/* Compress & Store Session */
|
|
106
|
-
const pathExists = await this.isValidPath(this.userDataDir);
|
|
107
|
-
if (pathExists) {
|
|
108
|
-
await this.compressSession();
|
|
109
|
-
await this.store.save({session: this.sessionName});
|
|
110
|
-
await fs.promises.unlink(`${this.sessionName}.zip`);
|
|
111
|
-
await fs.promises.rm(`${this.tempDir}`, {
|
|
112
|
-
recursive: true,
|
|
113
|
-
force: true,
|
|
114
|
-
maxRetries: this.rmMaxRetries,
|
|
115
|
-
}).catch(() => {});
|
|
116
|
-
if(options && options.emit) this.client.emit(Events.REMOTE_SESSION_SAVED);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async extractRemoteSession() {
|
|
121
|
-
const pathExists = await this.isValidPath(this.userDataDir);
|
|
122
|
-
const compressedSessionPath = `${this.sessionName}.zip`;
|
|
123
|
-
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
|
124
|
-
if (pathExists) {
|
|
125
|
-
await fs.promises.rm(this.userDataDir, {
|
|
126
|
-
recursive: true,
|
|
127
|
-
force: true,
|
|
128
|
-
maxRetries: this.rmMaxRetries,
|
|
129
|
-
}).catch(() => {});
|
|
130
|
-
}
|
|
131
|
-
if (sessionExists) {
|
|
132
|
-
await this.store.extract({session: this.sessionName, path: compressedSessionPath});
|
|
133
|
-
await this.unCompressSession(compressedSessionPath);
|
|
134
|
-
} else {
|
|
135
|
-
fs.mkdirSync(this.userDataDir, { recursive: true });
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
async deleteRemoteSession() {
|
|
140
|
-
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
|
141
|
-
if (sessionExists) await this.store.delete({session: this.sessionName});
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async compressSession() {
|
|
145
|
-
const archive = archiver('zip');
|
|
146
|
-
const stream = fs.createWriteStream(`${this.sessionName}.zip`);
|
|
147
|
-
|
|
148
|
-
await fs.copy(this.userDataDir, this.tempDir).catch(() => {});
|
|
149
|
-
await this.deleteMetadata();
|
|
150
|
-
return new Promise((resolve, reject) => {
|
|
151
|
-
archive
|
|
152
|
-
.directory(this.tempDir, false)
|
|
153
|
-
.on('error', err => reject(err))
|
|
154
|
-
.pipe(stream);
|
|
155
|
-
|
|
156
|
-
stream.on('close', () => resolve());
|
|
157
|
-
archive.finalize();
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
async unCompressSession(compressedSessionPath) {
|
|
162
|
-
var stream = fs.createReadStream(compressedSessionPath);
|
|
163
|
-
await new Promise((resolve, reject) => {
|
|
164
|
-
stream.pipe(unzipper.Extract({
|
|
165
|
-
path: this.userDataDir
|
|
166
|
-
}))
|
|
167
|
-
.on('error', err => reject(err))
|
|
168
|
-
.on('finish', () => resolve());
|
|
169
|
-
});
|
|
170
|
-
await fs.promises.unlink(compressedSessionPath);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async deleteMetadata() {
|
|
174
|
-
const sessionDirs = [this.tempDir, path.join(this.tempDir, 'Default')];
|
|
175
|
-
for (const dir of sessionDirs) {
|
|
176
|
-
const sessionFiles = await fs.promises.readdir(dir);
|
|
177
|
-
for (const element of sessionFiles) {
|
|
178
|
-
if (!this.requiredDirs.includes(element)) {
|
|
179
|
-
const dirElement = path.join(dir, element);
|
|
180
|
-
const stats = await fs.promises.lstat(dirElement);
|
|
181
|
-
|
|
182
|
-
if (stats.isDirectory()) {
|
|
183
|
-
await fs.promises.rm(dirElement, {
|
|
184
|
-
recursive: true,
|
|
185
|
-
force: true,
|
|
186
|
-
maxRetries: this.rmMaxRetries,
|
|
187
|
-
}).catch(() => {});
|
|
188
|
-
} else {
|
|
189
|
-
await fs.promises.unlink(dirElement).catch(() => {});
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
async isValidPath(path) {
|
|
197
|
-
try {
|
|
198
|
-
await fs.promises.access(path);
|
|
199
|
-
return true;
|
|
200
|
-
} catch {
|
|
201
|
-
return false;
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
async delay(ms) {
|
|
206
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
module.exports = RemoteAuth;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* Require Optional Dependencies */
|
|
4
|
+
try {
|
|
5
|
+
var fs = require('fs-extra');
|
|
6
|
+
var unzipper = require('unzipper');
|
|
7
|
+
var archiver = require('archiver');
|
|
8
|
+
} catch {
|
|
9
|
+
fs = undefined;
|
|
10
|
+
unzipper = undefined;
|
|
11
|
+
archiver = undefined;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const { Events } = require('./../util/Constants');
|
|
16
|
+
const BaseAuthStrategy = require('./BaseAuthStrategy');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Remote-based authentication
|
|
20
|
+
* @param {object} options - options
|
|
21
|
+
* @param {object} options.store - Remote database store instance
|
|
22
|
+
* @param {string} options.clientId - Client id to distinguish instances if you are using multiple, otherwise keep null if you are using only one instance
|
|
23
|
+
* @param {string} options.dataPath - Change the default path for saving session files, default is: "./.wwebjs_auth/"
|
|
24
|
+
* @param {number} options.backupSyncIntervalMs - Sets the time interval for periodic session backups. Accepts values starting from 60000ms {1 minute}
|
|
25
|
+
* @param {number} options.rmMaxRetries - Sets the maximum number of retries for removing the session directory
|
|
26
|
+
*/
|
|
27
|
+
class RemoteAuth extends BaseAuthStrategy {
|
|
28
|
+
constructor({ clientId, dataPath, store, backupSyncIntervalMs, rmMaxRetries } = {}) {
|
|
29
|
+
if (!fs && !unzipper && !archiver) throw new Error('Optional Dependencies [fs-extra, unzipper, archiver] are required to use RemoteAuth. Make sure to run npm install correctly and remove the --no-optional flag');
|
|
30
|
+
super();
|
|
31
|
+
|
|
32
|
+
const idRegex = /^[-_\w]+$/i;
|
|
33
|
+
if (clientId && !idRegex.test(clientId)) {
|
|
34
|
+
throw new Error('Invalid clientId. Only alphanumeric characters, underscores and hyphens are allowed.');
|
|
35
|
+
}
|
|
36
|
+
if (!backupSyncIntervalMs || backupSyncIntervalMs < 60000) {
|
|
37
|
+
throw new Error('Invalid backupSyncIntervalMs. Accepts values starting from 60000ms {1 minute}.');
|
|
38
|
+
}
|
|
39
|
+
if(!store) throw new Error('Remote database store is required.');
|
|
40
|
+
|
|
41
|
+
this.store = store;
|
|
42
|
+
this.clientId = clientId;
|
|
43
|
+
this.backupSyncIntervalMs = backupSyncIntervalMs;
|
|
44
|
+
this.dataPath = path.resolve(dataPath || './.wwebjs_auth/');
|
|
45
|
+
this.tempDir = `${this.dataPath}/wwebjs_temp_session_${this.clientId}`;
|
|
46
|
+
this.requiredDirs = ['Default', 'IndexedDB', 'Local Storage']; /* => Required Files & Dirs in WWebJS to restore session */
|
|
47
|
+
this.rmMaxRetries = rmMaxRetries ?? 4;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async beforeBrowserInitialized() {
|
|
51
|
+
const puppeteerOpts = this.client.options.puppeteer;
|
|
52
|
+
const sessionDirName = this.clientId ? `RemoteAuth-${this.clientId}` : 'RemoteAuth';
|
|
53
|
+
const dirPath = path.join(this.dataPath, sessionDirName);
|
|
54
|
+
|
|
55
|
+
if (puppeteerOpts.userDataDir && puppeteerOpts.userDataDir !== dirPath) {
|
|
56
|
+
throw new Error('RemoteAuth is not compatible with a user-supplied userDataDir.');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
this.userDataDir = dirPath;
|
|
60
|
+
this.sessionName = sessionDirName;
|
|
61
|
+
|
|
62
|
+
await this.extractRemoteSession();
|
|
63
|
+
|
|
64
|
+
this.client.options.puppeteer = {
|
|
65
|
+
...puppeteerOpts,
|
|
66
|
+
userDataDir: dirPath
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async logout() {
|
|
71
|
+
await this.disconnect();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async destroy() {
|
|
75
|
+
clearInterval(this.backupSync);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async disconnect() {
|
|
79
|
+
await this.deleteRemoteSession();
|
|
80
|
+
|
|
81
|
+
let pathExists = await this.isValidPath(this.userDataDir);
|
|
82
|
+
if (pathExists) {
|
|
83
|
+
await fs.promises.rm(this.userDataDir, {
|
|
84
|
+
recursive: true,
|
|
85
|
+
force: true,
|
|
86
|
+
maxRetries: this.rmMaxRetries,
|
|
87
|
+
}).catch(() => {});
|
|
88
|
+
}
|
|
89
|
+
clearInterval(this.backupSync);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async afterAuthReady() {
|
|
93
|
+
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
|
94
|
+
if(!sessionExists) {
|
|
95
|
+
await this.delay(60000); /* Initial delay sync required for session to be stable enough to recover */
|
|
96
|
+
await this.storeRemoteSession({emit: true});
|
|
97
|
+
}
|
|
98
|
+
var self = this;
|
|
99
|
+
this.backupSync = setInterval(async function () {
|
|
100
|
+
await self.storeRemoteSession();
|
|
101
|
+
}, this.backupSyncIntervalMs);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async storeRemoteSession(options) {
|
|
105
|
+
/* Compress & Store Session */
|
|
106
|
+
const pathExists = await this.isValidPath(this.userDataDir);
|
|
107
|
+
if (pathExists) {
|
|
108
|
+
await this.compressSession();
|
|
109
|
+
await this.store.save({session: this.sessionName});
|
|
110
|
+
await fs.promises.unlink(`${this.sessionName}.zip`);
|
|
111
|
+
await fs.promises.rm(`${this.tempDir}`, {
|
|
112
|
+
recursive: true,
|
|
113
|
+
force: true,
|
|
114
|
+
maxRetries: this.rmMaxRetries,
|
|
115
|
+
}).catch(() => {});
|
|
116
|
+
if(options && options.emit) this.client.emit(Events.REMOTE_SESSION_SAVED);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async extractRemoteSession() {
|
|
121
|
+
const pathExists = await this.isValidPath(this.userDataDir);
|
|
122
|
+
const compressedSessionPath = `${this.sessionName}.zip`;
|
|
123
|
+
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
|
124
|
+
if (pathExists) {
|
|
125
|
+
await fs.promises.rm(this.userDataDir, {
|
|
126
|
+
recursive: true,
|
|
127
|
+
force: true,
|
|
128
|
+
maxRetries: this.rmMaxRetries,
|
|
129
|
+
}).catch(() => {});
|
|
130
|
+
}
|
|
131
|
+
if (sessionExists) {
|
|
132
|
+
await this.store.extract({session: this.sessionName, path: compressedSessionPath});
|
|
133
|
+
await this.unCompressSession(compressedSessionPath);
|
|
134
|
+
} else {
|
|
135
|
+
fs.mkdirSync(this.userDataDir, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async deleteRemoteSession() {
|
|
140
|
+
const sessionExists = await this.store.sessionExists({session: this.sessionName});
|
|
141
|
+
if (sessionExists) await this.store.delete({session: this.sessionName});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async compressSession() {
|
|
145
|
+
const archive = archiver('zip');
|
|
146
|
+
const stream = fs.createWriteStream(`${this.sessionName}.zip`);
|
|
147
|
+
|
|
148
|
+
await fs.copy(this.userDataDir, this.tempDir).catch(() => {});
|
|
149
|
+
await this.deleteMetadata();
|
|
150
|
+
return new Promise((resolve, reject) => {
|
|
151
|
+
archive
|
|
152
|
+
.directory(this.tempDir, false)
|
|
153
|
+
.on('error', err => reject(err))
|
|
154
|
+
.pipe(stream);
|
|
155
|
+
|
|
156
|
+
stream.on('close', () => resolve());
|
|
157
|
+
archive.finalize();
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async unCompressSession(compressedSessionPath) {
|
|
162
|
+
var stream = fs.createReadStream(compressedSessionPath);
|
|
163
|
+
await new Promise((resolve, reject) => {
|
|
164
|
+
stream.pipe(unzipper.Extract({
|
|
165
|
+
path: this.userDataDir
|
|
166
|
+
}))
|
|
167
|
+
.on('error', err => reject(err))
|
|
168
|
+
.on('finish', () => resolve());
|
|
169
|
+
});
|
|
170
|
+
await fs.promises.unlink(compressedSessionPath);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async deleteMetadata() {
|
|
174
|
+
const sessionDirs = [this.tempDir, path.join(this.tempDir, 'Default')];
|
|
175
|
+
for (const dir of sessionDirs) {
|
|
176
|
+
const sessionFiles = await fs.promises.readdir(dir);
|
|
177
|
+
for (const element of sessionFiles) {
|
|
178
|
+
if (!this.requiredDirs.includes(element)) {
|
|
179
|
+
const dirElement = path.join(dir, element);
|
|
180
|
+
const stats = await fs.promises.lstat(dirElement);
|
|
181
|
+
|
|
182
|
+
if (stats.isDirectory()) {
|
|
183
|
+
await fs.promises.rm(dirElement, {
|
|
184
|
+
recursive: true,
|
|
185
|
+
force: true,
|
|
186
|
+
maxRetries: this.rmMaxRetries,
|
|
187
|
+
}).catch(() => {});
|
|
188
|
+
} else {
|
|
189
|
+
await fs.promises.unlink(dirElement).catch(() => {});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async isValidPath(path) {
|
|
197
|
+
try {
|
|
198
|
+
await fs.promises.access(path);
|
|
199
|
+
return true;
|
|
200
|
+
} catch {
|
|
201
|
+
return false;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
async delay(ms) {
|
|
206
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
module.exports = RemoteAuth;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const PrivateChat = require('../structures/PrivateChat');
|
|
4
|
-
const GroupChat = require('../structures/GroupChat');
|
|
5
|
-
const Channel = require('../structures/Channel');
|
|
6
|
-
|
|
7
|
-
class ChatFactory {
|
|
8
|
-
static create(client, data) {
|
|
9
|
-
if (data.isGroup) {
|
|
10
|
-
return new GroupChat(client, data);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (data.isChannel) {
|
|
14
|
-
return new Channel(client, data);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return new PrivateChat(client, data);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = ChatFactory;
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const PrivateChat = require('../structures/PrivateChat');
|
|
4
|
+
const GroupChat = require('../structures/GroupChat');
|
|
5
|
+
const Channel = require('../structures/Channel');
|
|
6
|
+
|
|
7
|
+
class ChatFactory {
|
|
8
|
+
static create(client, data) {
|
|
9
|
+
if (data.isGroup) {
|
|
10
|
+
return new GroupChat(client, data);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (data.isChannel) {
|
|
14
|
+
return new Channel(client, data);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return new PrivateChat(client, data);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = ChatFactory;
|